LSSTApplications  19.0.0-10-g920eed2,19.0.0-11-g48a0200+2,19.0.0-18-gfc4e62b+13,19.0.0-2-g3b2f90d+2,19.0.0-2-gd671419+5,19.0.0-20-g5a5a17ab+11,19.0.0-21-g2644856+13,19.0.0-23-g84eeccb+1,19.0.0-24-g878c510+1,19.0.0-25-g6c8df7140,19.0.0-25-gb330496+1,19.0.0-3-g2b32d65+5,19.0.0-3-g8227491+12,19.0.0-3-g9c54d0d+12,19.0.0-3-gca68e65+8,19.0.0-3-gcfc5f51+5,19.0.0-3-ge110943+11,19.0.0-3-ge74d124,19.0.0-3-gfe04aa6+13,19.0.0-30-g9c3fd16+1,19.0.0-4-g06f5963+5,19.0.0-4-g3d16501+13,19.0.0-4-g4a9c019+5,19.0.0-4-g5a8b323,19.0.0-4-g66397f0+1,19.0.0-4-g8278b9b+1,19.0.0-4-g8557e14,19.0.0-4-g8964aba+13,19.0.0-4-ge404a01+12,19.0.0-5-g40f3a5a,19.0.0-5-g4db63b3,19.0.0-5-gfb03ce7+13,19.0.0-6-gbaebbfb+12,19.0.0-61-gec4c6e08+1,19.0.0-7-g039c0b5+11,19.0.0-7-gbea9075+4,19.0.0-7-gc567de5+13,19.0.0-71-g41c0270,19.0.0-9-g2f02add+1,19.0.0-9-g463f923+12,w.2020.22
LSSTDataManagementBasePackage
ingest.py
Go to the documentation of this file.
1 # This file is part of pipe_tasks.
2 #
3 # Developed for the LSST Data Management System.
4 # This product includes software developed by the LSST Project
5 # (https://www.lsst.org).
6 # See the COPYRIGHT file at the top-level directory of this distribution
7 # for details of code ownership.
8 #
9 # This program is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <https://www.gnu.org/licenses/>.
21 
22 import os
23 import shutil
24 import sqlite3
25 import sys
26 from fnmatch import fnmatch
27 from glob import glob
28 from contextlib import contextmanager
29 
30 from lsst.pex.config import Config, Field, DictField, ListField, ConfigurableField
32 from lsst.afw.fits import readMetadata
33 from lsst.pipe.base import Task, InputOnlyArgumentParser
34 from lsst.afw.fits import DEFAULT_HDU
35 
36 
38  """Argument parser to support ingesting images into the image repository"""
39 
40  def __init__(self, *args, **kwargs):
41  super(IngestArgumentParser, self).__init__(*args, **kwargs)
42  self.add_argument("-n", "--dry-run", dest="dryrun", action="store_true", default=False,
43  help="Don't perform any action?")
44  self.add_argument("--mode", choices=["move", "copy", "link", "skip"], default="link",
45  help="Mode of delivering the files to their destination")
46  self.add_argument("--create", action="store_true", help="Create new registry (clobber old)?")
47  self.add_argument("--ignore-ingested", dest="ignoreIngested", action="store_true",
48  help="Don't register files that have already been registered")
49  self.add_id_argument("--badId", "raw", "Data identifier for bad data", doMakeDataRefList=False)
50  self.add_argument("--badFile", nargs="*", default=[],
51  help="Names of bad files (no path; wildcards allowed)")
52  self.add_argument("files", nargs="+", help="Names of file")
53 
54 
55 class ParseConfig(Config):
56  """Configuration for ParseTask"""
57  translation = DictField(keytype=str, itemtype=str, default={},
58  doc="Translation table for property --> header")
59  translators = DictField(keytype=str, itemtype=str, default={},
60  doc="Properties and name of translator method")
61  defaults = DictField(keytype=str, itemtype=str, default={},
62  doc="Default values if header is not present")
63  hdu = Field(dtype=int, default=DEFAULT_HDU, doc="HDU to read for metadata")
64  extnames = ListField(dtype=str, default=[], doc="Extension names to search for")
65 
66 
67 class ParseTask(Task):
68  """Task that will parse the filename and/or its contents to get the required information
69  for putting the file in the correct location and populating the registry."""
70  ConfigClass = ParseConfig
71 
72  def getInfo(self, filename):
73  """Get information about the image from the filename and its contents
74 
75  Here, we open the image and parse the header, but one could also look at the filename itself
76  and derive information from that, or set values from the configuration.
77 
78  @param filename Name of file to inspect
79  @return File properties; list of file properties for each extension
80  """
81  md = readMetadata(filename, self.config.hdu)
82  phuInfo = self.getInfoFromMetadata(md)
83  if len(self.config.extnames) == 0:
84  # No extensions to worry about
85  return phuInfo, [phuInfo]
86  # Look in the provided extensions
87  extnames = set(self.config.extnames)
88  extnum = 0
89  infoList = []
90  while len(extnames) > 0:
91  extnum += 1
92  try:
93  md = readMetadata(filename, extnum)
94  except Exception as e:
95  self.log.warn("Error reading %s extensions %s: %s" % (filename, extnames, e))
96  break
97  ext = self.getExtensionName(md)
98  if ext in extnames:
99  hduInfo = self.getInfoFromMetadata(md, info=phuInfo.copy())
100  # We need the HDU number when registering MEF files.
101  hduInfo["hdu"] = extnum
102  infoList.append(hduInfo)
103  extnames.discard(ext)
104  return phuInfo, infoList
105 
106  @staticmethod
108  """ Get the name of an extension.
109  @param md: PropertySet like one obtained from lsst.afw.fits.readMetadata)
110  @return Name of the extension if it exists. None otherwise.
111  """
112  try:
113  # This returns a tuple
114  ext = md.getScalar("EXTNAME")
115  return ext[1]
117  return None
118 
119  def getInfoFromMetadata(self, md, info=None):
120  """Attempt to pull the desired information out of the header
121 
122  This is done through two mechanisms:
123  * translation: a property is set directly from the relevant header keyword
124  * translator: a property is set with the result of calling a method
125 
126  The translator methods receive the header metadata and should return the
127  appropriate value, or None if the value cannot be determined.
128 
129  @param md FITS header
130  @param info File properties, to be supplemented
131  @return info
132  """
133  if info is None:
134  info = {}
135  for p, h in self.config.translation.items():
136  value = md.get(h, None)
137  if value is not None:
138  if isinstance(value, str):
139  value = value.strip()
140  info[p] = value
141  elif p in self.config.defaults:
142  info[p] = self.config.defaults[p]
143  else:
144  self.log.warn("Unable to find value for %s (derived from %s)" % (p, h))
145  for p, t in self.config.translators.items():
146  func = getattr(self, t)
147  try:
148  value = func(md)
149  except Exception as e:
150  self.log.warn("%s failed to translate %s: %s", t, p, e)
151  value = None
152  if value is not None:
153  info[p] = value
154  return info
155 
156  def translate_date(self, md):
157  """Convert a full DATE-OBS to a mere date
158 
159  Besides being an example of a translator, this is also generally useful.
160  It will only be used if listed as a translator in the configuration.
161  """
162  date = md.getScalar("DATE-OBS").strip()
163  c = date.find("T")
164  if c > 0:
165  date = date[:c]
166  return date
167 
168  def translate_filter(self, md):
169  """Translate a full filter description into a mere filter name
170 
171  Besides being an example of a translator, this is also generally useful.
172  It will only be used if listed as a translator in the configuration.
173  """
174  filterName = md.getScalar("FILTER").strip()
175  filterName = filterName.strip()
176  c = filterName.find(" ")
177  if c > 0:
178  filterName = filterName[:c]
179  return filterName
180 
181  def getDestination(self, butler, info, filename):
182  """Get destination for the file
183 
184  @param butler Data butler
185  @param info File properties, used as dataId for the butler
186  @param filename Input filename
187  @return Destination filename
188  """
189  raw = butler.get("raw_filename", info)[0]
190  # Ensure filename is devoid of cfitsio directions about HDUs
191  c = raw.find("[")
192  if c > 0:
193  raw = raw[:c]
194  return raw
195 
196 
197 class RegisterConfig(Config):
198  """Configuration for the RegisterTask"""
199  table = Field(dtype=str, default="raw", doc="Name of table")
200  columns = DictField(keytype=str, itemtype=str, doc="List of columns for raw table, with their types",
201  itemCheck=lambda x: x in ("text", "int", "double"),
202  default={'object': 'text',
203  'visit': 'int',
204  'ccd': 'int',
205  'filter': 'text',
206  'date': 'text',
207  'taiObs': 'text',
208  'expTime': 'double',
209  },
210  )
211  unique = ListField(dtype=str, doc="List of columns to be declared unique for the table",
212  default=["visit", "ccd"])
213  visit = ListField(dtype=str, default=["visit", "object", "date", "filter"],
214  doc="List of columns for raw_visit table")
215  ignore = Field(dtype=bool, default=False, doc="Ignore duplicates in the table?")
216  permissions = Field(dtype=int, default=0o664, doc="Permissions mode for registry; 0o664 = rw-rw-r--")
217 
218 
220  """Context manager to provide a registry
221  """
222 
223  def __init__(self, registryName, createTableFunc, forceCreateTables, permissions):
224  """Construct a context manager
225 
226  @param registryName: Name of registry file
227  @param createTableFunc: Function to create tables
228  @param forceCreateTables: Force the (re-)creation of tables?
229  @param permissions: Permissions to set on database file
230  """
231  self.conn = sqlite3.connect(registryName)
232  os.chmod(registryName, permissions)
233  createTableFunc(self.conn, forceCreateTables=forceCreateTables)
234 
235  def __enter__(self):
236  """Provide the 'as' value"""
237  return self.conn
238 
239  def __exit__(self, excType, excValue, traceback):
240  self.conn.commit()
241  self.conn.close()
242  return False # Don't suppress any exceptions
243 
244 
245 @contextmanager
247  """A context manager that doesn't provide any context
248 
249  Useful for dry runs where we don't want to actually do anything real.
250  """
251  yield
252 
253 
254 class RegisterTask(Task):
255  """Task that will generate the registry for the Mapper"""
256  ConfigClass = RegisterConfig
257  placeHolder = '?' # Placeholder for parameter substitution; this value suitable for sqlite3
258  typemap = {'text': str, 'int': int, 'double': float} # Mapping database type --> python type
259 
260  def openRegistry(self, directory, create=False, dryrun=False, name="registry.sqlite3"):
261  """Open the registry and return the connection handle.
262 
263  @param directory Directory in which the registry file will be placed
264  @param create Clobber any existing registry and create a new one?
265  @param dryrun Don't do anything permanent?
266  @param name Filename of the registry
267  @return Database connection
268  """
269  if dryrun:
270  return fakeContext()
271 
272  registryName = os.path.join(directory, name)
273  context = RegistryContext(registryName, self.createTable, create, self.config.permissions)
274  return context
275 
276  def createTable(self, conn, table=None, forceCreateTables=False):
277  """Create the registry tables
278 
279  One table (typically 'raw') contains information on all files, and the
280  other (typically 'raw_visit') contains information on all visits.
281 
282  @param conn Database connection
283  @param table Name of table to create in database
284  """
285  cursor = conn.cursor()
286  if table is None:
287  table = self.config.table
288  cmd = "SELECT name FROM sqlite_master WHERE type='table' AND name='%s'" % table
289  cursor.execute(cmd)
290  if cursor.fetchone() and not forceCreateTables: # Assume if we get an answer the table exists
291  self.log.info('Table "%s" exists. Skipping creation' % table)
292  return
293  else:
294  cmd = "drop table if exists %s" % table
295  cursor.execute(cmd)
296  cmd = "drop table if exists %s_visit" % table
297  cursor.execute(cmd)
298 
299  cmd = "create table %s (id integer primary key autoincrement, " % table
300  cmd += ",".join([("%s %s" % (col, colType)) for col, colType in self.config.columns.items()])
301  if len(self.config.unique) > 0:
302  cmd += ", unique(" + ",".join(self.config.unique) + ")"
303  cmd += ")"
304  cursor.execute(cmd)
305 
306  cmd = "create table %s_visit (" % table
307  cmd += ",".join([("%s %s" % (col, self.config.columns[col])) for col in self.config.visit])
308  cmd += ", unique(" + ",".join(set(self.config.visit).intersection(set(self.config.unique))) + ")"
309  cmd += ")"
310  cursor.execute(cmd)
311 
312  conn.commit()
313 
314  def check(self, conn, info, table=None):
315  """Check for the presence of a row already
316 
317  Not sure this is required, given the 'ignore' configuration option.
318  """
319  if table is None:
320  table = self.config.table
321  if self.config.ignore or len(self.config.unique) == 0:
322  return False # Our entry could already be there, but we don't care
323  cursor = conn.cursor()
324  sql = "SELECT COUNT(*) FROM %s WHERE " % table
325  sql += " AND ".join(["%s = %s" % (col, self.placeHolder) for col in self.config.unique])
326  values = [self.typemap[self.config.columns[col]](info[col]) for col in self.config.unique]
327 
328  cursor.execute(sql, values)
329  if cursor.fetchone()[0] > 0:
330  return True
331  return False
332 
333  def addRow(self, conn, info, dryrun=False, create=False, table=None):
334  """Add a row to the file table (typically 'raw').
335 
336  @param conn Database connection
337  @param info File properties to add to database
338  @param table Name of table in database
339  """
340  with conn:
341  if table is None:
342  table = self.config.table
343  ignoreClause = ""
344  if self.config.ignore:
345  ignoreClause = " OR IGNORE"
346  sql = "INSERT%s INTO %s (%s) VALUES (" % (ignoreClause, table, ",".join(self.config.columns))
347  sql += ",".join([self.placeHolder] * len(self.config.columns)) + ")"
348  values = [self.typemap[tt](info[col]) for col, tt in self.config.columns.items()]
349 
350  if dryrun:
351  print("Would execute: '%s' with %s" % (sql, ",".join([str(value) for value in values])))
352  else:
353  conn.cursor().execute(sql, values)
354 
355  sql = "INSERT OR IGNORE INTO %s_visit VALUES (" % table
356  sql += ",".join([self.placeHolder] * len(self.config.visit)) + ")"
357  values = [self.typemap[self.config.columns[col]](info[col]) for col in self.config.visit]
358 
359  if dryrun:
360  print("Would execute: '%s' with %s" % (sql, ",".join([str(value) for value in values])))
361  else:
362  conn.cursor().execute(sql, values)
363 
364 
365 class IngestConfig(Config):
366  """Configuration for IngestTask"""
367  parse = ConfigurableField(target=ParseTask, doc="File parsing")
368  register = ConfigurableField(target=RegisterTask, doc="Registry entry")
369  allowError = Field(dtype=bool, default=False, doc="Allow error in ingestion?")
370  clobber = Field(dtype=bool, default=False, doc="Clobber existing file?")
371 
372 
373 class IngestError(RuntimeError):
374  def __init__(self, message, pathname, position):
375  super().__init__(message)
376  self.pathname = pathname
377  self.position = position
378 
379 
381  """Task that will ingest images into the data repository"""
382  ConfigClass = IngestConfig
383  ArgumentParser = IngestArgumentParser
384  _DefaultName = "ingest"
385 
386  def __init__(self, *args, **kwargs):
387  super(IngestTask, self).__init__(*args, **kwargs)
388  self.makeSubtask("parse")
389  self.makeSubtask("register")
390 
391  @classmethod
392  def _parse(cls):
393  """Parse the command-line arguments and return them along with a Task
394  instance."""
395  config = cls.ConfigClass()
396  parser = cls.ArgumentParser(name=cls._DefaultName)
397  args = parser.parse_args(config)
398  task = cls(config=args.config)
399  return task, args
400 
401  @classmethod
402  def parseAndRun(cls):
403  """Parse the command-line arguments and run the Task."""
404  task, args = cls._parse()
405  task.run(args)
406 
407  @classmethod
408  def prepareTask(cls, root=None, dryrun=False, mode="move", create=False,
409  ignoreIngested=False):
410  """Prepare for running the task repeatedly with `ingestFiles`.
411 
412  Saves the parsed arguments, including the Butler and log, as a
413  private instance variable.
414 
415  Parameters
416  ----------
417  root : `str`, optional
418  Repository root pathname. If None, run the Task using the
419  command line arguments, ignoring all other arguments below.
420  dryrun : `bool`, optional
421  If True, don't perform any action; log what would have happened.
422  mode : `str`, optional
423  How files are delivered to their destination. Default is "move",
424  unlike the command-line default of "link".
425  create : `bool`, optional
426  If True, create a new registry, clobbering any old one present.
427  ignoreIngested : `bool`, optional
428  If True, do not complain if the file is already present in the
429  registry (and do nothing else).
430 
431  Returns
432  -------
433  task : `IngestTask`
434  If `root` was provided, the IngestTask instance
435  """
436  sys.argv = ["IngestTask"]
437  sys.argv.append(root)
438  if dryrun:
439  sys.argv.append("--dry-run")
440  sys.argv.append("--mode")
441  sys.argv.append(mode)
442  if create:
443  sys.argv.append("--create")
444  if ignoreIngested:
445  sys.argv.append("--ignore-ingested")
446  sys.argv.append("__fakefile__") # needed for parsing, not used
447 
448  task, args = cls._parse()
449  task._args = args
450  return task
451 
452  def ingest(self, infile, outfile, mode="move", dryrun=False):
453  """Ingest a file into the image repository.
454 
455  @param infile Name of input file
456  @param outfile Name of output file (file in repository)
457  @param mode Mode of ingest (copy/link/move/skip)
458  @param dryrun Only report what would occur?
459  @param Success boolean
460  """
461  if mode == "skip":
462  return True
463  if dryrun:
464  self.log.info("Would %s from %s to %s" % (mode, infile, outfile))
465  return True
466  try:
467  outdir = os.path.dirname(outfile)
468  if not os.path.isdir(outdir):
469  try:
470  os.makedirs(outdir)
471  except OSError as exc:
472  # Silently ignore mkdir failures due to race conditions
473  if not os.path.isdir(outdir):
474  raise RuntimeError(f"Failed to create directory {outdir}") from exc
475  if os.path.lexists(outfile):
476  if self.config.clobber:
477  os.unlink(outfile)
478  else:
479  raise RuntimeError("File %s already exists; consider --config clobber=True" % outfile)
480 
481  if mode == "copy":
482  assertCanCopy(infile, outfile)
483  shutil.copyfile(infile, outfile)
484  elif mode == "link":
485  if os.path.exists(outfile):
486  if os.path.samefile(infile, outfile):
487  self.log.debug("Already linked %s to %s: ignoring" % (infile, outfile))
488  else:
489  self.log.warn("%s already has a file at the target location (%s): ignoring "
490  "(set clobber=True to overwrite)" % (infile, outfile))
491  return False
492  os.symlink(os.path.abspath(infile), outfile)
493  elif mode == "move":
494  assertCanCopy(infile, outfile)
495  shutil.move(infile, outfile)
496  else:
497  raise AssertionError("Unknown mode: %s" % mode)
498  self.log.info("%s --<%s>--> %s" % (infile, mode, outfile))
499  except Exception as e:
500  self.log.warn("Failed to %s %s to %s: %s" % (mode, infile, outfile, e))
501  if not self.config.allowError:
502  raise RuntimeError(f"Failed to {mode} {infile} to {outfile}") from e
503  return False
504  return True
505 
506  def isBadFile(self, filename, badFileList):
507  """Return whether the file qualifies as bad
508 
509  We match against the list of bad file patterns.
510  """
511  filename = os.path.basename(filename)
512  if not badFileList:
513  return False
514  for badFile in badFileList:
515  if fnmatch(filename, badFile):
516  return True
517  return False
518 
519  def isBadId(self, info, badIdList):
520  """Return whether the file information qualifies as bad
521 
522  We match against the list of bad data identifiers.
523  """
524  if not badIdList:
525  return False
526  for badId in badIdList:
527  if all(info[key] == value for key, value in badId.items()):
528  return True
529  return False
530 
531  def expandFiles(self, fileNameList):
532  """!Expand a set of filenames and globs, returning a list of filenames
533 
534  @param fileNameList A list of files and glob patterns
535 
536  N.b. globs obey Posix semantics, so a pattern that matches nothing is returned unchanged
537  """
538  filenameList = []
539  for globPattern in fileNameList:
540  files = glob(globPattern)
541 
542  if not files: # posix behaviour is to return pattern unchanged
543  self.log.warn("%s doesn't match any file" % globPattern)
544  continue
545 
546  filenameList.extend(files)
547 
548  return filenameList
549 
550  def runFile(self, infile, registry, args, pos):
551  """!Examine and ingest a single file
552 
553  @param infile: File to process
554  @param registry: Registry into which to insert Butler metadata, or None
555  @param args: Parsed command-line arguments
556  @param pos: Position number of this file in the input list
557  @return parsed information from FITS HDUs if registry is None; or None
558  """
559  if self.isBadFile(infile, args.badFile):
560  self.log.info("Skipping declared bad file %s" % infile)
561  return None
562  try:
563  fileInfo, hduInfoList = self.parse.getInfo(infile)
564  except Exception as e:
565  if not self.config.allowError:
566  raise RuntimeError(f"Error parsing {infile}") from e
567  self.log.warn("Error parsing %s (%s); skipping" % (infile, e))
568  return None
569  if self.isBadId(fileInfo, args.badId.idList):
570  self.log.info("Skipping declared bad file %s: %s" % (infile, fileInfo))
571  return None
572  if registry is not None and self.register.check(registry, fileInfo):
573  if args.ignoreIngested:
574  return None
575  self.log.warn("%s: already ingested: %s" % (infile, fileInfo))
576  outfile = self.parse.getDestination(args.butler, fileInfo, infile)
577  if not self.ingest(infile, outfile, mode=args.mode, dryrun=args.dryrun):
578  return None
579  if hduInfoList is None:
580  return None
581  if registry is None:
582  return hduInfoList
583  for info in hduInfoList:
584  try:
585  self.register.addRow(registry, info, dryrun=args.dryrun, create=args.create)
586  except Exception as exc:
587  raise IngestError(f"Failed to register file {infile}", infile, pos) from exc
588  return None # No further registration should be performed
589 
590  def run(self, args):
591  """Ingest all specified files and add them to the registry"""
592  filenameList = self.expandFiles(args.files)
593  root = args.input
594  context = self.register.openRegistry(root, create=args.create, dryrun=args.dryrun)
595  with context as registry:
596  for pos in range(len(filenameList)):
597  infile = filenameList[pos]
598  try:
599  self.runFile(infile, registry, args, pos)
600  except Exception as exc:
601  self.log.warn("Failed to ingest file %s: %s", infile, exc)
602  if not self.config.allowError:
603  raise IngestError(f"Failed to ingest file {infile}", infile, pos) from exc
604  continue
605 
606  def ingestFiles(self, fileList):
607  """Ingest specified file or list of files and add them to the registry.
608 
609  This method can only be called if `prepareTask` was used.
610 
611  Parameters
612  ----------
613  fileList : `str` or `list` [`str`]
614  Pathname or list of pathnames of files to ingest.
615  """
616  if not hasattr(self, "_args"):
617  raise RuntimeError("Task not created with prepareTask")
618  if isinstance(fileList, str):
619  fileList = [fileList]
620  self._args.files = fileList
621  self.run(self._args)
622 
623 
624 def assertCanCopy(fromPath, toPath):
625  """Can I copy a file? Raise an exception is space constraints not met.
626 
627  @param fromPath Path from which the file is being copied
628  @param toPath Path to which the file is being copied
629  """
630  req = os.stat(fromPath).st_size
631  st = os.statvfs(os.path.dirname(toPath))
632  avail = st.f_bavail * st.f_frsize
633  if avail < req:
634  raise RuntimeError("Insufficient space: %d vs %d" % (req, avail))
lsst.pipe.tasks.ingest.RegisterTask.typemap
typemap
Definition: ingest.py:258
lsst.pipe.tasks.ingest.IngestConfig
Definition: ingest.py:365
lsst::log.log.logContinued.warn
def warn(fmt, *args)
Definition: logContinued.py:202
lsst.pipe.tasks.ingest.RegistryContext
Definition: ingest.py:219
lsst::log.log.logContinued.info
def info(fmt, *args)
Definition: logContinued.py:198
lsst.pipe.tasks.ingest.IngestTask.__init__
def __init__(self, *args, **kwargs)
Definition: ingest.py:386
lsst.pipe.tasks.ingest.IngestTask.isBadFile
def isBadFile(self, filename, badFileList)
Definition: ingest.py:506
lsst.pipe.tasks.ingest.ParseTask.translate_date
def translate_date(self, md)
Definition: ingest.py:156
lsst.pipe.tasks.ingest.IngestTask.ingestFiles
def ingestFiles(self, fileList)
Definition: ingest.py:606
lsst.pipe.tasks.ingest.IngestTask.parseAndRun
def parseAndRun(cls)
Definition: ingest.py:402
lsst.pipe.tasks.ingest.ParseTask.getExtensionName
def getExtensionName(md)
Definition: ingest.py:107
lsst.pipe.tasks.ingest.IngestTask.expandFiles
def expandFiles(self, fileNameList)
Expand a set of filenames and globs, returning a list of filenames.
Definition: ingest.py:531
lsst.gdb.afw.printers.debug
bool debug
Definition: printers.py:9
lsst.pipe.tasks.ingest.fakeContext
def fakeContext()
Definition: ingest.py:246
lsst.pipe.tasks.ingest.IngestTask._parse
def _parse(cls)
Definition: ingest.py:392
lsst.pipe.tasks.ingest.RegisterTask.placeHolder
placeHolder
Definition: ingest.py:257
lsst.pipe.tasks.ingest.RegisterTask.check
def check(self, conn, info, table=None)
Definition: ingest.py:314
lsst.pipe.base.argumentParser.InputOnlyArgumentParser
Definition: argumentParser.py:914
lsst.pipe.tasks.ingest.IngestTask._DefaultName
_DefaultName
Definition: ingest.py:384
lsst.pipe.tasks.ingest.IngestTask
Definition: ingest.py:380
strip
bool strip
Definition: fits.cc:911
lsst.pipe.base.argumentParser.ArgumentParser.add_id_argument
def add_id_argument(self, name, datasetType, help, level=None, doMakeDataRefList=True, ContainerClass=DataIdContainer)
Definition: argumentParser.py:510
lsst.pipe.tasks.ingest.ParseTask
Definition: ingest.py:67
lsst.pipe.tasks.ingest.RegisterTask.openRegistry
def openRegistry(self, directory, create=False, dryrun=False, name="registry.sqlite3")
Definition: ingest.py:260
lsst.pipe.tasks.ingest.ParseTask.getInfo
def getInfo(self, filename)
Definition: ingest.py:72
lsst::afw::geom.transform.transformContinued.cls
cls
Definition: transformContinued.py:33
lsst::geom::all
bool all(CoordinateExpr< N > const &expr) noexcept
Return true if all elements are true.
Definition: CoordinateExpr.h:81
lsst.pipe.tasks.ingest.ParseTask.getInfoFromMetadata
def getInfoFromMetadata(self, md, info=None)
Definition: ingest.py:119
lsst.pipe.tasks.ingest.RegisterTask.createTable
def createTable(self, conn, table=None, forceCreateTables=False)
Definition: ingest.py:276
lsst.pipe.base.task.Task.makeSubtask
def makeSubtask(self, name, **keyArgs)
Definition: task.py:275
lsst.pipe.tasks.ingest.ParseTask.getDestination
def getDestination(self, butler, info, filename)
Definition: ingest.py:181
lsst.pipe.tasks.ingest.IngestTask.runFile
def runFile(self, infile, registry, args, pos)
Examine and ingest a single file.
Definition: ingest.py:550
lsst.pipe.tasks.ingest.RegistryContext.__exit__
def __exit__(self, excType, excValue, traceback)
Definition: ingest.py:239
lsst.pipe.tasks.ingest.IngestError.pathname
pathname
Definition: ingest.py:376
lsst.pipe.tasks.ingest.RegistryContext.conn
conn
Definition: ingest.py:231
lsst.pipe.base.task.Task.config
config
Definition: task.py:149
lsst.pipe.tasks.ingest.RegistryContext.__enter__
def __enter__(self)
Definition: ingest.py:235
lsstDebug.getInfo
getInfo
Definition: lsstDebug.py:87
lsst.pipe.tasks.ingest.IngestTask.ArgumentParser
ArgumentParser
Definition: ingest.py:383
lsst.pipe.base.task.Task.log
log
Definition: task.py:148
lsst.pipe.tasks.ingest.IngestTask.run
def run(self, args)
Definition: ingest.py:590
lsst.pipe.tasks.ingest.IngestError
Definition: ingest.py:373
lsst.pipe.tasks.ingest.IngestTask.prepareTask
def prepareTask(cls, root=None, dryrun=False, mode="move", create=False, ignoreIngested=False)
Definition: ingest.py:408
lsst::afw::image.readMetadata.readMetadataContinued.readMetadata
readMetadata
Definition: readMetadataContinued.py:28
lsst.pipe.tasks.ingest.IngestTask.ingest
def ingest(self, infile, outfile, mode="move", dryrun=False)
Definition: ingest.py:452
lsst.pipe.tasks.ingest.assertCanCopy
def assertCanCopy(fromPath, toPath)
Definition: ingest.py:624
lsst.pipe.tasks.ingest.IngestArgumentParser
Definition: ingest.py:37
lsst::afw::fits
Definition: fits.h:31
lsst.pipe.base.task.Task
Definition: task.py:46
lsst.pipe.tasks.ingest.IngestArgumentParser.__init__
def __init__(self, *args, **kwargs)
Definition: ingest.py:40
lsst::pex::exceptions
Definition: Exception.h:37
lsst::pex::exceptions::Exception
Provides consistent interface for LSST exceptions.
Definition: Exception.h:107
lsst.pipe.tasks.ingest.ParseTask.translate_filter
def translate_filter(self, md)
Definition: ingest.py:168
lsst.pipe.base
Definition: __init__.py:1
lsst.pipe.tasks.ingest.ParseConfig
Definition: ingest.py:55
lsst.pipe.tasks.ingest.RegistryContext.__init__
def __init__(self, registryName, createTableFunc, forceCreateTables, permissions)
Definition: ingest.py:223
lsst.pipe.tasks.ingest.RegisterConfig
Definition: ingest.py:197
lsst.pipe.tasks.ingest.IngestError.__init__
def __init__(self, message, pathname, position)
Definition: ingest.py:374
set
daf::base::PropertySet * set
Definition: fits.cc:912
lsst.pipe.tasks.ingest.IngestTask.ConfigClass
ConfigClass
Definition: ingest.py:382
lsst.pipe.tasks.ingest.RegisterTask.addRow
def addRow(self, conn, info, dryrun=False, create=False, table=None)
Definition: ingest.py:333
lsst.pipe.tasks.ingest.IngestTask.isBadId
def isBadId(self, info, badIdList)
Definition: ingest.py:519
lsst.pipe.tasks.ingest.IngestError.position
position
Definition: ingest.py:377