29 """This module defines the Mapping base class."""
33 """Mapping is a base class for all mappings. Mappings are used by
34 the Mapper to map (determine a path to some data given some
35 identifiers) and standardize (convert data into some standard
36 format or type) data, and to query the associated registry to see
37 what data is available.
39 Subclasses must specify self.storage or else override self.map().
41 Public methods: lookup, have, need, getKeys, map
43 Mappings are specified mainly by policy. A Mapping policy should
46 template (string): a Python string providing the filename for that
47 particular dataset type based on some data identifiers. In the
48 case of redundancy in the path (e.g., file uniquely specified by
49 the exposure number, but filter in the path), the
50 redundant/dependent identifiers can be looked up in the registry.
52 python (string): the Python type for the retrieved data (e.g.
53 lsst.afw.image.ExposureF)
55 persistable (string): the Persistable registration for the on-disk data
58 storage (string, optional): Storage type for this dataset type (e.g.
61 level (string, optional): the level in the camera hierarchy at which the
62 data is stored (Amp, Ccd or skyTile), if relevant
64 tables (string, optional): a whitespace-delimited list of tables in the
65 registry that can be NATURAL JOIN-ed to look up additional
68 def __init__(self, datasetType, policy, registry, root, provided=None):
69 """Constructor for Mapping class.
70 @param datasetType (string)
71 @param policy (lsst.pex.policy.Policy) Mapping policy
72 @param registry (lsst.daf.butlerUtils.Registry) Registry for metadata lookups
73 @param root (string) Path of root directory
74 @param provided (list of strings) Keys provided by the mapper
78 raise RuntimeError,
"No policy provided for mapping"
88 re.findall(
r'\%\((\w+)\).*?([diouxXeEfFgGcrs])', self.
template)
90 if provided
is not None:
94 self.
python = policy.getString(
"python")
96 self.
storage = policy.getString(
"storage")
97 if policy.exists(
"level"):
98 self.
level = policy.getString(
"level")
99 if policy.exists(
"tables"):
100 self.
tables = policy.getStringArray(
"tables")
106 if policy.exists(
"obsTimeName")
else None
109 """Return the dict of keys and value types required for this mapping."""
112 def map(self, mapper, dataId, write=False):
113 """Standard implementation of map function.
114 @param mapper (lsst.daf.persistence.Mapper)
115 @param dataId (dict) Dataset identifier
116 @return (lsst.daf.persistence.ButlerLocation)"""
118 actualId = self.
need(self.keyDict.iterkeys(), dataId)
119 path = mapper._mapActualToPath(self.
template, actualId)
120 if not os.path.isabs(path):
121 path = os.path.join(self.
root, path)
123 newPath = mapper._parentSearch(path)
124 if newPath
is not None:
128 if hasattr(mapper, addFunc):
129 addFunc = getattr(mapper, addFunc)
130 additionalData = addFunc(actualId)
131 assert isinstance(additionalData, dict),
"Bad type for returned data"
133 additionalData = actualId.copy()
138 """Look up properties for in a metadata registry given a partial
140 @param properties (list of strings)
141 @param dataId (dict) Dataset identifier
142 @return (list of tuples) values of properties"""
145 raise RuntimeError,
"No registry for lookup"
151 if p
not in (
'filter',
'expTime',
'taiObs'):
154 if fastPath
and dataId.has_key(
'visit')
and "raw" in self.
tables:
155 return self.registry.executeQuery(properties, (
'raw_visit',),
156 [(
'visit',
'?')],
None, (dataId[
'visit'],))
157 if dataId
is not None:
158 for k, v
in dataId.iteritems():
163 where.append((k,
'?'))
165 if self.
range is not None:
167 return self.registry.executeQuery(properties, self.
tables,
168 where, self.
range, values)
170 def have(self, properties, dataId):
171 """Returns whether the provided data identifier has all
172 the properties in the provided list.
173 @param properties (list of strings) Properties required
174 @parm dataId (dict) Dataset identifier
175 @return (bool) True if all properties are present"""
176 for prop
in properties:
177 if not dataId.has_key(prop):
181 def need(self, properties, dataId):
182 """Ensures all properties in the provided list are present in
183 the data identifier, looking them up as needed. This is only
184 possible for the case where the data identifies a single
186 @param properties (list of strings) Properties required
187 @param dataId (dict) Partial dataset identifier
188 @return (dict) copy of dataset identifier with enhanced values
191 newId = dataId.copy()
193 for prop
in properties:
194 if not newId.has_key(prop):
195 newProps.append(prop)
196 if len(newProps) == 0:
199 lookups = self.
lookup(newProps, newId)
200 if len(lookups) != 1:
201 raise RuntimeError,
"No unique lookup for %s from %s: %d matches" % (newProps, newId, len(lookups))
202 for i, prop
in enumerate(newProps):
203 newId[prop] = lookups[0][i]
207 """Convert a format character into a Python type."""
215 raise RuntimeError(
"Unexpected format specifier %s"
216 " for field %s in template for dataset %s" %
217 (ch, k, datasetType))
221 """ImageMapping is a Mapping subclass for non-camera images."""
223 def __init__(self, datasetType, policy, registry, root, **kwargs):
224 """Constructor for Mapping class.
225 @param datasetType (string)
226 @param policy (lsst.pex.policy.Policy) Mapping policy
227 @param registry (lsst.daf.butlerUtils.Registry) Registry for metadata lookups
228 @param root (string) Path of root directory"""
229 Mapping.__init__(self, datasetType, policy, registry, root, **kwargs)
230 self.
columns = policy.getStringArray(
"columns")
if policy.exists(
"columns")
else None
234 """ExposureMapping is a Mapping subclass for normal exposures."""
236 def __init__(self, datasetType, policy, registry, root, **kwargs):
237 """Constructor for Mapping class.
238 @param datasetType (string)
239 @param policy (lsst.pex.policy.Policy) Mapping policy
240 @param registry (lsst.daf.butlerUtils.Registry) Registry for metadata lookups
241 @param root (string) Path of root directory"""
242 Mapping.__init__(self, datasetType, policy, registry, root, **kwargs)
243 self.
columns = policy.getStringArray(
"columns")
if policy.exists(
"columns")
else None
246 return mapper._standardizeExposure(self, item, dataId)
249 """CalibrationMapping is a Mapping subclass for calibration-type products.
251 The difference is that data properties in the query or template
252 can be looked up using a reference Mapping in addition to this one.
254 CalibrationMapping Policies can contain the following:
256 reference (string, optional): a list of tables for finding missing dataset
257 identifier components (including the observation time, if a validity range
258 is required) in the exposure registry; note that the "tables" entry refers
259 to the calibration registry
261 refCols (string, optional): a list of dataset properties required from the
262 reference tables for lookups in the calibration registry
264 validRange (bool): true if the calibration dataset has a validity range
265 specified by a column in the tables of the reference dataset in the
266 exposure registry) and two columns in the tables of this calibration
267 dataset in the calibration registry)
269 obsTimeName (string, optional): the name of the column in the reference
270 dataset tables containing the observation time (default "taiObs")
272 validStartName (string, optional): the name of the column in the
273 calibration dataset tables containing the start of the validity range
274 (default "validStart")
276 validEndName (string, optional): the name of the column in the
277 calibration dataset tables containing the end of the validity range
278 (default "validEnd") """
280 def __init__(self, datasetType, policy, registry, calibRegistry, calibRoot, **kwargs):
281 """Constructor for Mapping class.
282 @param datasetType (string)
283 @param policy (lsst.pex.policy.Policy) Mapping policy
284 @param registry (lsst.daf.butlerUtils.Registry) Registry for metadata lookups
285 @param calibRegistry (lsst.daf.butlerUtils.Registry) Registry for calibration metadata lookups
286 @param calibRoot (string) Path of calibration root directory"""
288 Mapping.__init__(self, datasetType, policy, calibRegistry, calibRoot, **kwargs)
290 if policy.exists(
"reference")
else None
291 self.
refCols = policy.getStringArray(
"refCols") \
292 if policy.exists(
"refCols")
else None
294 if policy.exists(
"validRange")
and policy.getBool(
"validRange"):
295 self.
range = (
"?", policy.getString(
"validStartName"),
296 policy.getString(
"validEndName"))
297 if policy.exists(
"columns"):
298 self.
columns = policy.getStringArray(
"columns")
299 if policy.exists(
"filter"):
303 """Look up properties for in a metadata registry given a partial
305 @param properties (list of strings)
306 @param dataId (dict) Dataset identifier
307 @return (list of tuples) values of properties"""
312 newId = dataId.copy()
316 for k, v
in dataId.iteritems():
319 where.append((k,
'?'))
325 for k
in dataId.iterkeys():
328 columns = set(properties)
333 return Mapping.lookup(self, properties, newId)
335 lookups = self.refRegistry.executeQuery(columns, self.
reference,
337 if len(lookups) != 1:
338 raise RuntimeError(
"No unique lookup for %s from %s: %d matches" %
339 (columns, dataId, len(lookups)))
340 if columns == set(properties):
343 for i, prop
in enumerate(columns):
344 newId[prop] = lookups[0][i]
345 return Mapping.lookup(self, properties, newId)
348 return mapper._standardizeExposure(self, item, dataId, filter=self.
setFilter)
351 """DatasetMapping is a Mapping subclass for non-Exposure datasets that can
352 be retrieved by the standard daf_persistence mechanism.
354 The differences are that the Storage type must be specified and no
355 Exposure standardization is performed.
357 The "storage" entry in the Policy is mandatory; the "tables" entry is
358 optional; no "level" entry is allowed. """
360 def __init__(self, datasetType, policy, registry, root, **kwargs):
361 """Constructor for DatasetMapping class.
362 @param[in,out] mapper (lsst.daf.persistence.Mapper) Mapper object
363 @param policy (lsst.pex.policy.Policy) Mapping policy
364 @param datasetType (string)
365 @param registry (lsst.daf.butlerUtils.Registry) Registry for metadata lookups
366 @param root (string) Path of root directory"""
367 Mapping.__init__(self, datasetType, policy, registry, root, **kwargs)