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