27 __all__ = [
'getMapperClass',
35 'lsstsim':
'lsst.obs.lsstSim.LsstSimMapper',
36 'sdss':
'lsst.obs.sdss.SdssMapper',
37 'cfht':
'lsst.obs.cfht.CfhtMapper',
42 """Return the subclass of lsst.daf.persistence.Mapper
43 to use for the camera with the given name (case-insensitive).
45 camera = camera.lower()
46 if camera
not in _mapperClassName:
47 raise RuntimeError(str.format(
"{} is not a valid camera name", camera))
48 name = _mapperClassName[camera]
50 pieces = name.split(
'.')
51 cls = reduce(getattr, pieces[1:], __import__(
'.'.join(pieces[:-1])))
54 raise RuntimeError(str.format(
"Failed to import {}", name))
105 """A rule is a string in the following format:
107 'key=value1[^value2[^value3...]'
109 The values may either be strings, or of the form 'int...int'
110 (e.g. '1..3') which is interpreted as '1^2^3' (inclusive, unlike a python
111 range). So '0^2..4^7..9' is equivalent to '0^2^3^4^7^8^9'.
113 This function parses a list of such strings, and returns a dict mapping
114 keys to sets of legal values.
119 Camera the rule list applies to (e.g. 'lsstSim' or 'sdss')
121 camera = camera.lower()
122 if camera
not in _keyTypes:
123 raise RuntimeError(
'{} is not a recognized camera name'.
format(camera))
125 for rule
in ruleList:
127 key, _, pattern = rule.partition(
'=')
128 if key
not in _keyTypes[camera]:
129 raise RuntimeError(
'{} is not a valid dataId key for camera {}'.
format(key, camera))
130 if len(pattern) == 0:
134 for p
in pattern.split(
'^'):
135 if _keyTypes[camera][key] == int:
137 m = re.search(
r'^(\d+)\.\.(\d+)$', p)
139 values.update(xrange(int(m.group(1)), int(m.group(2)) + 1))
145 kvs[key].update(values)
152 """A key in a path template. Three attributes are provided:
155 Formatting spec for the key, e.g. '%(filter)s'.
158 key value type; int or str
161 A function that takes a key name, key value string and a dictionary.
162 This function should return a fresh dictionary including new entries
163 derived from the given key, value, and existing entries. The
164 _mungeStr and _mungeInt functions are examples.
172 """Munger for keys with string formats."""
178 """Munger for keys with integer formats."""
185 """A single component (directory or file) of a path template. The
186 following attributes are provided:
189 List of key names first occurring in this path component.
192 Compiled regular expression identifying matches to this path
193 component unless simple is True; in that case, regex is just
197 True if regex is a simple string literal rather than a pattern.
198 In this case, keys will always by None or [].
207 """A hierarchical scanner for paths matching a template, optionally
208 also restricting visited paths to those matching a list of dataId rules.
211 """Build an FsScanner for given a path template. The path template
212 should be a Python string with named format substitution
213 specifications, as used in mapper policy files. For example:
215 deepCoadd-results/%(filter)s/%(tract)d/%(patch)s/calexp-%(filter)s-%(tract)d-%(patch)s.fits
217 Note that a key may appear multiple times. If it does,
218 the value for each occurrence should be identical (the formatting
219 specs must be identical). Octal, binary, hexadecimal, and floating
220 point formats are not supported.
222 template = os.path.normpath(template)
223 if (len(template) == 0
or
224 template == os.curdir
or
225 template[0] == os.sep
or
226 template[-1] == os.sep):
228 'Path template is empty, absolute, or identifies a directory')
231 fmt = re.compile(
r'%\((\w+)\).*?([diucrs])')
234 for component
in template.split(os.sep):
240 for m
in fmt.finditer(component):
244 seenBefore = self._formatKeys.has_key(k)
246 regex += re.escape(component[last:m.start(0)])
251 if m.group(2)
in 'crs':
258 regex +=
r'[+-]?\d+)'
263 'Path template contains inconsistent format type-codes '
268 regex += re.escape(component[last:])
272 regex = re.compile(
'^' + regex +
'$')
273 self._pathComponents.append(
_PathComponent(newKeys, regex, simple))
275 def walk(self, root, rules=None):
276 """Generator that descends the given root directory in top-down
277 fashion, matching paths corresponding to the template and satisfying
278 the given rule list. The generator yields tuples of the form
279 (path, dataId), where path is a dataset file name relative to root,
280 and dataId is a key value dictionary identifying the file.
283 while os.path.exists(root)
and not oneFound:
284 stack = [(0, root, rules, {})]
286 depth, path, rules, dataId = stack.pop()
287 if os.path.isfile(path):
293 if not os.path.exists(os.path.join(path, pc.regex)):
296 entries = os.listdir(path)
303 m = pc.regex.match(e)
308 for i, k
in enumerate(pc.keys):
309 subDataId = self.
_formatKeys[k].munge(k, m.group(i + 1), subDataId)
314 if subRules
and pc.keys:
319 if k
not in r
or subDataId[k]
in r[k]:
325 p = os.path.join(path, e)
328 stack.append((depth, p, subRules, subDataId))
330 if os.path.isfile(p):
332 yield os.path.relpath(p, root), subDataId
335 root = os.path.join(root,
"_parent")
341 dataId = dataId.copy()
344 dataId[
'raft'] = r1 +
',' + r2
345 dataId[
'raftId'] = int(r1) * 5 + int(r2)
346 elif k
in (
'sensor',
'ccd'):
348 dataId[
'sensor'] = s1 +
',' + s2
349 dataId[
'sensorNum'] = int(s1) * 3 + int(s2)
350 elif k
in (
'channel',
'amp'):
352 dataId[
'channel'] = c1 +
',' + c2
353 dataId[
'channelNum'] = int(c1) * 8 + int(c2)
354 elif k
in (
'snap',
'exposure'):
355 dataId[
'snap'] = int(v)
356 elif _keyTypes[
'lsstsim'][k] == int:
363 dataId = dataId.copy()
364 if _keyTypes[
'sdss'][k] == int:
371 dataId = dataId.copy()
373 dataId[
'ccd'] = int(v)
374 dataId[
'ccdName'] = v
376 dataId[
'amp'] = int(v)
377 dataId[
'ampName'] = v
378 elif _keyTypes[
'sdss'][k] == int:
385 'lsstsim': _mungeLsstSim,
392 """File system scanner for a dataset known to a camera mapper.
396 raise TypeError(
'Expecting a lsst.daf.butlerUtils.CameraMapper!')
397 if dataset
not in cameraMapper.mappings:
398 raise NotFoundError(
'Unknown dataset ' + str(dataset))
399 HfsScanner.__init__(self, cameraMapper.mappings[dataset].template)
400 camera = camera.lower()
401 if camera
not in _keyTypes:
402 raise RuntimeError(
'{} camera not supported yet'.
format(camera))
404 if k
not in _keyTypes[camera]:
405 raise RuntimeError(
'{} is not a valid dataId key for camera {}'.
format(k, camera))
406 self.
_formatKeys[k].munge = _mungeFunctions[camera]