LSSTApplications  11.0-13-gbb96280,12.1.rc1,12.1.rc1+1,12.1.rc1+2,12.1.rc1+5,12.1.rc1+8,12.1.rc1-1-g06d7636+1,12.1.rc1-1-g253890b+5,12.1.rc1-1-g3d31b68+7,12.1.rc1-1-g3db6b75+1,12.1.rc1-1-g5c1385a+3,12.1.rc1-1-g83b2247,12.1.rc1-1-g90cb4cf+6,12.1.rc1-1-g91da24b+3,12.1.rc1-2-g3521f8a,12.1.rc1-2-g39433dd+4,12.1.rc1-2-g486411b+2,12.1.rc1-2-g4c2be76,12.1.rc1-2-gc9c0491,12.1.rc1-2-gda2cd4f+6,12.1.rc1-3-g3391c73+2,12.1.rc1-3-g8c1bd6c+1,12.1.rc1-3-gcf4b6cb+2,12.1.rc1-4-g057223e+1,12.1.rc1-4-g19ed13b+2,12.1.rc1-4-g30492a7
LSSTDataManagementBasePackage
mapper.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
3 #
4 # LSST Data Management System
5 # Copyright 2008, 2009, 2010 LSST Corporation.
6 #
7 # This product includes software developed by the
8 # LSST Project (http://www.lsst.org/).
9 #
10 # This program is free software: you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation, either version 3 of the License, or
13 # (at your option) any later version.
14 #
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
19 #
20 # You should have received a copy of the LSST License Statement and
21 # the GNU General Public License along with this program. If not,
22 # see <http://www.lsstcorp.org/LegalNotices/>.
23 #
24 from builtins import object
25 
26 import yaml
27 
28 from . import Policy
29 
30 """This module defines the Mapper base class."""
31 
32 
33 class MapperCfg(Policy):
34  """Represents a mapper configuration.
35 
36  .. warning::
37 
38  cfg is 'wet paint' and very likely to change. Use of it in production
39  code other than via the 'old butler' API is strongly discouraged.
40  """
41 
42  yaml_tag = u"!MapperCfg"
43  yaml_loader = yaml.Loader
44  yaml_dumper = yaml.Dumper
45 
46  def __init__(self, cls, policy, storage):
47  super(MapperCfg, self).__init__()
48  self.update({'cls': cls, 'policy': policy, 'storage': storage})
49 
50  @staticmethod
51  def to_yaml(dumper, obj):
52  return dumper.represent_mapping(RepositoryMapperCfg.yaml_tag,
53  {'cls': obj['cls'], 'policy': obj['policy'],
54  'storage': obj['storage']})
55 
56  @staticmethod
57  def from_yaml(loader, node):
58  obj = loader.construct_mapping(node)
59  return RepositoryMapperCfg(**obj)
60 
61 
62 class Mapper(object):
63  """Mapper is a base class for all mappers.
64 
65  Subclasses may define the following methods:
66 
67  map_{datasetType}(self, dataId, write)
68  Map a dataset id for the given dataset type into a ButlerLocation.
69  If write=True, this mapping is for an output dataset.
70 
71  query_{datasetType}(self, key, format, dataId)
72  Return the possible values for the format fields that would produce
73  datasets at the granularity of key in combination with the provided
74  partial dataId.
75 
76  std_{datasetType}(self, item)
77  Standardize an object of the given data set type.
78 
79  Methods that must be overridden:
80 
81  keys(self)
82  Return a list of the keys that can be used in data ids.
83 
84  Other public methods:
85 
86  __init__(self)
87 
88  getDatasetTypes(self)
89 
90  map(self, datasetType, dataId, write=False)
91 
92  queryMetadata(self, datasetType, key, format, dataId)
93 
94  canStandardize(self, datasetType)
95 
96  standardize(self, datasetType, item, dataId)
97 
98  validate(self, dataId)
99  """
100 
101  @staticmethod
102  def Mapper(cfg):
103  '''Instantiate a Mapper from a configuration.
104  In come cases the cfg may have already been instantiated into a Mapper, this is allowed and
105  the input var is simply returned.
106 
107  :param cfg: the cfg for this mapper. It is recommended this be created by calling
108  Mapper.cfg()
109  :return: a Mapper instance
110  '''
111  if isinstance(cfg, Policy):
112  return cfg['cls'](cfg)
113  return cfg
114 
115  def __new__(cls, *args, **kwargs):
116  """Create a new Mapper, saving arguments for pickling.
117 
118  This is in __new__ instead of __init__ to save the user
119  from having to save the arguments themselves (either explicitly,
120  or by calling the super's __init__ with all their
121  *args,**kwargs. The resulting pickling system (of __new__,
122  __getstate__ and __setstate__ is similar to how __reduce__
123  is usually used, except that we save the user from any
124  responsibility (except when overriding __new__, but that
125  is not common).
126  """
127  self = super(Mapper, cls).__new__(cls)
128  self._arguments = (args, kwargs)
129  return self
130 
131  def __init__(self):
132  pass
133 
134  def __getstate__(self):
135  return self._arguments
136 
137  def __setstate__(self, state):
138  self._arguments = state
139  args, kwargs = state
140  self.__init__(*args, **kwargs)
141 
142  def keys(self):
143  raise NotImplementedError("keys() unimplemented")
144 
145  def queryMetadata(self, datasetType, format, dataId):
146  """Get possible values for keys given a partial data id.
147 
148  :param datasetType: see documentation about the use of datasetType
149  :param key: this is used as the 'level' parameter
150  :param format:
151  :param dataId: see documentation about the use of dataId
152  :return:
153  """
154 
155  func = getattr(self, 'query_' + datasetType)
156 
157  val = func(format, self.validate(dataId))
158  return val
159 
160  def getDatasetTypes(self):
161  """Return a list of the mappable dataset types."""
162 
163  list = []
164  for attr in dir(self):
165  if attr.startswith("map_"):
166  list.append(attr[4:])
167  return list
168 
169  def map(self, datasetType, dataId, write=False):
170  """Map a data id using the mapping method for its dataset type."""
171 
172  func = getattr(self, 'map_' + datasetType)
173  return func(self.validate(dataId), write)
174 
175  def canStandardize(self, datasetType):
176  """Return true if this mapper can standardize an object of the given
177  dataset type."""
178 
179  return hasattr(self, 'std_' + datasetType)
180 
181  def standardize(self, datasetType, item, dataId):
182  """Standardize an object using the standardization method for its data
183  set type, if it exists."""
184 
185  if hasattr(self, 'std_' + datasetType):
186  func = getattr(self, 'std_' + datasetType)
187  return func(item, self.validate(dataId))
188  return item
189 
190  def validate(self, dataId):
191  """Validate a dataId's contents.
192 
193  If the dataId is valid, return it. If an invalid component can be
194  transformed into a valid one, copy the dataId, fix the component, and
195  return the copy. Otherwise, raise an exception."""
196 
197  return dataId
198 
199  def backup(self, datasetType, dataId):
200  """Rename any existing object with the given type and dataId.
201 
202  Not implemented in the base mapper.
203  """
204  raise NotImplementedError("Base-class Mapper does not implement backups")