23 from builtins
import zip
24 from builtins
import object
31 """This module defines the Mapping base class."""
36 """Mapping is a base class for all mappings. Mappings are used by
37 the Mapper to map (determine a path to some data given some
38 identifiers) and standardize (convert data into some standard
39 format or type) data, and to query the associated registry to see
40 what data is available.
42 Subclasses must specify self.storage or else override self.map().
44 Public methods: lookup, have, need, getKeys, map
46 Mappings are specified mainly by policy. A Mapping policy should
49 template (string): a Python string providing the filename for that
50 particular dataset type based on some data identifiers. In the
51 case of redundancy in the path (e.g., file uniquely specified by
52 the exposure number, but filter in the path), the
53 redundant/dependent identifiers can be looked up in the registry.
55 python (string): the Python type for the retrieved data (e.g.
56 lsst.afw.image.ExposureF)
58 persistable (string): the Persistable registration for the on-disk data
61 storage (string, optional): Storage type for this dataset type (e.g.
64 level (string, optional): the level in the camera hierarchy at which the
65 data is stored (Amp, Ccd or skyTile), if relevant
67 tables (string, optional): a whitespace-delimited list of tables in the
68 registry that can be NATURAL JOIN-ed to look up additional
71 def __init__(self, datasetType, policy, registry, root, provided=None):
72 """Constructor for Mapping class.
73 @param datasetType (string)
74 @param policy (daf_persistence.Policy, or pexPolicy.Policy (only for backward compatibility))
76 @param registry (lsst.daf.butlerUtils.Registry) Registry for metadata lookups
77 @param root (string) Path of root directory
78 @param provided (list of strings) Keys provided by the mapper
82 raise RuntimeError(
"No policy provided for mapping")
95 re.findall(
r'\%\((\w+)\).*?([diouxXeEfFgGcrs])', self.
template)
97 if provided
is not None:
104 if 'level' in policy:
106 if 'tables' in policy:
112 self.
obsTimeName = policy[
'obsTimeName']
if 'obsTimeName' in policy
else None
115 """Return the dict of keys and value types required for this mapping."""
118 def map(self, mapper, dataId, write=False):
119 """Standard implementation of map function.
120 @param mapper (lsst.daf.persistence.Mapper)
121 @param dataId (dict) Dataset identifier
122 @return (lsst.daf.persistence.ButlerLocation)"""
124 actualId = self.
need(
iter(self.keyDict.keys()), dataId)
125 path = mapper._mapActualToPath(self.
template, actualId)
126 if not os.path.isabs(path):
127 path = os.path.join(self.
root, path)
129 newPath = mapper._parentSearch(path)
132 assert path,
"Fully-qualified filename is empty."
135 if hasattr(mapper, addFunc):
136 addFunc = getattr(mapper, addFunc)
137 additionalData = addFunc(actualId)
138 assert isinstance(additionalData, dict),
"Bad type for returned data"
140 additionalData = actualId.copy()
145 """Look up properties for in a metadata registry given a partial
147 @param properties (list of strings)
148 @param dataId (dict) Dataset identifier
149 @return (list of tuples) values of properties"""
152 raise RuntimeError(
"No registry for lookup")
158 if p
not in (
'filter',
'expTime',
'taiObs'):
161 if fastPath
and 'visit' in dataId
and "raw" in self.
tables:
162 lookupDataId = {
'visit': dataId[
'visit']}
163 self.registry.lookup(properties,
'raw_visit', lookupDataId)
164 if dataId
is not None:
165 for k, v
in dataId.items():
170 where.append((k,
'?'))
173 lookupDataId = {k[0]: v
for k, v
in zip(where, values)}
178 return self.registry.lookup(properties, self.
tables, lookupDataId)
180 def have(self, properties, dataId):
181 """Returns whether the provided data identifier has all
182 the properties in the provided list.
183 @param properties (list of strings) Properties required
184 @parm dataId (dict) Dataset identifier
185 @return (bool) True if all properties are present"""
186 for prop
in properties:
187 if prop
not in dataId:
191 def need(self, properties, dataId):
192 """Ensures all properties in the provided list are present in
193 the data identifier, looking them up as needed. This is only
194 possible for the case where the data identifies a single
196 @param properties (list of strings) Properties required
197 @param dataId (dict) Partial dataset identifier
198 @return (dict) copy of dataset identifier with enhanced values
200 newId = dataId.copy()
202 for prop
in properties:
203 if prop
not in newId:
204 newProps.append(prop)
205 if len(newProps) == 0:
208 lookups = self.
lookup(newProps, newId)
209 if len(lookups) != 1:
210 raise RuntimeError(
"No unique lookup for %s from %s: %d matches" %
211 (newProps, newId, len(lookups)))
212 for i, prop
in enumerate(newProps):
213 newId[prop] = lookups[0][i]
218 """Convert a format character into a Python type."""
226 raise RuntimeError(
"Unexpected format specifier %s"
227 " for field %s in template for dataset %s" %
228 (ch, k, datasetType))
232 """ImageMapping is a Mapping subclass for non-camera images."""
234 def __init__(self, datasetType, policy, registry, root, **kwargs):
235 """Constructor for Mapping class.
236 @param datasetType (string)
237 @param policy (daf_persistence.Policy, or pexPolicy.Policy (only for backward compatibility))
239 @param registry (lsst.daf.butlerUtils.Registry) Registry for metadata lookups
240 @param root (string) Path of root directory"""
243 Mapping.__init__(self, datasetType, policy, registry, root, **kwargs)
244 self.
columns = policy.asArray(
'columns')
if 'columns' in policy
else None
248 """ExposureMapping is a Mapping subclass for normal exposures."""
250 def __init__(self, datasetType, policy, registry, root, **kwargs):
251 """Constructor for Mapping class.
252 @param datasetType (string)
253 @param policy (daf_persistence.Policy, or pexPolicy.Policy (only for backward compatibility))
255 @param registry (lsst.daf.butlerUtils.Registry) Registry for metadata lookups
256 @param root (string) Path of root directory"""
259 Mapping.__init__(self, datasetType, policy, registry, root, **kwargs)
260 self.
columns = policy.asArray(
'columns')
if 'columns' in policy
else None
263 return mapper._standardizeExposure(self, item, dataId)
267 """CalibrationMapping is a Mapping subclass for calibration-type products.
269 The difference is that data properties in the query or template
270 can be looked up using a reference Mapping in addition to this one.
272 CalibrationMapping Policies can contain the following:
274 reference (string, optional): a list of tables for finding missing dataset
275 identifier components (including the observation time, if a validity range
276 is required) in the exposure registry; note that the "tables" entry refers
277 to the calibration registry
279 refCols (string, optional): a list of dataset properties required from the
280 reference tables for lookups in the calibration registry
282 validRange (bool): true if the calibration dataset has a validity range
283 specified by a column in the tables of the reference dataset in the
284 exposure registry) and two columns in the tables of this calibration
285 dataset in the calibration registry)
287 obsTimeName (string, optional): the name of the column in the reference
288 dataset tables containing the observation time (default "taiObs")
290 validStartName (string, optional): the name of the column in the
291 calibration dataset tables containing the start of the validity range
292 (default "validStart")
294 validEndName (string, optional): the name of the column in the
295 calibration dataset tables containing the end of the validity range
296 (default "validEnd") """
298 def __init__(self, datasetType, policy, registry, calibRegistry, calibRoot, **kwargs):
299 """Constructor for Mapping class.
300 @param datasetType (string)
301 @param policy (daf_persistence.Policy, or pexPolicy.Policy (only for backward compatibility))
303 @param registry (lsst.daf.butlerUtils.Registry) Registry for metadata lookups
304 @param calibRegistry (lsst.daf.butlerUtils.Registry) Registry for calibration metadata lookups
305 @param calibRoot (string) Path of calibration root directory"""
308 Mapping.__init__(self, datasetType, policy, calibRegistry, calibRoot, **kwargs)
309 self.
reference = policy.asArray(
"reference")
if "reference" in policy
else None
310 self.
refCols = policy.asArray(
"refCols")
if "refCols" in policy
else None
312 if "validRange" in policy
and policy[
"validRange"]:
313 self.
range = (
"?", policy[
"validStartName"], policy[
"validEndName"])
314 if "columns" in policy:
316 if "filter" in policy:
319 if "metadataKey" in policy:
323 """Look up properties for in a metadata registry given a partial
325 @param properties (list of strings)
326 @param dataId (dict) Dataset identifier
327 @return (list of tuples) values of properties"""
332 newId = dataId.copy()
336 for k, v
in dataId.items():
345 for k
in dataId.keys():
348 columns = set(properties)
352 return Mapping.lookup(self, properties, newId)
354 lookupDataId = dict(zip(where, values))
355 lookups = self.refRegistry.lookup(columns, self.
reference, lookupDataId)
356 if len(lookups) != 1:
357 raise RuntimeError(
"No unique lookup for %s from %s: %d matches" %
358 (columns, dataId, len(lookups)))
359 if columns == set(properties):
362 for i, prop
in enumerate(columns):
363 newId[prop] = lookups[0][i]
364 return Mapping.lookup(self, properties, newId)
367 return mapper._standardizeExposure(self, item, dataId, filter=self.
setFilter)
371 """DatasetMapping is a Mapping subclass for non-Exposure datasets that can
372 be retrieved by the standard daf_persistence mechanism.
374 The differences are that the Storage type must be specified and no
375 Exposure standardization is performed.
377 The "storage" entry in the Policy is mandatory; the "tables" entry is
378 optional; no "level" entry is allowed. """
380 def __init__(self, datasetType, policy, registry, root, **kwargs):
381 """Constructor for DatasetMapping class.
382 @param[in,out] mapper (lsst.daf.persistence.Mapper) Mapper object
383 @param policy (daf_persistence.Policy, or pexPolicy.Policy (only for backward compatibility))
385 @param datasetType (string)
386 @param registry (lsst.daf.butlerUtils.Registry) Registry for metadata lookups
387 @param root (string) Path of root directory"""
390 Mapping.__init__(self, datasetType, policy, registry, root, **kwargs)
a container for holding hierarchical configuration data in memory.