LSST Applications  21.0.0-147-g0e635eb1+1acddb5be5,22.0.0+052faf71bd,22.0.0+1ea9a8b2b2,22.0.0+6312710a6c,22.0.0+729191ecac,22.0.0+7589c3a021,22.0.0+9f079a9461,22.0.1-1-g7d6de66+b8044ec9de,22.0.1-1-g87000a6+536b1ee016,22.0.1-1-g8e32f31+6312710a6c,22.0.1-10-gd060f87+016f7cdc03,22.0.1-12-g9c3108e+df145f6f68,22.0.1-16-g314fa6d+c825727ab8,22.0.1-19-g93a5c75+d23f2fb6d8,22.0.1-19-gb93eaa13+aab3ef7709,22.0.1-2-g8ef0a89+b8044ec9de,22.0.1-2-g92698f7+9f079a9461,22.0.1-2-ga9b0f51+052faf71bd,22.0.1-2-gac51dbf+052faf71bd,22.0.1-2-gb66926d+6312710a6c,22.0.1-2-gcb770ba+09e3807989,22.0.1-20-g32debb5+b8044ec9de,22.0.1-23-gc2439a9a+fb0756638e,22.0.1-3-g496fd5d+09117f784f,22.0.1-3-g59f966b+1e6ba2c031,22.0.1-3-g849a1b8+f8b568069f,22.0.1-3-gaaec9c0+c5c846a8b1,22.0.1-32-g5ddfab5d3+60ce4897b0,22.0.1-4-g037fbe1+64e601228d,22.0.1-4-g8623105+b8044ec9de,22.0.1-5-g096abc9+d18c45d440,22.0.1-5-g15c806e+57f5c03693,22.0.1-7-gba73697+57f5c03693,master-g6e05de7fdc+c1283a92b8,master-g72cdda8301+729191ecac,w.2021.39
LSST Data Management Base Package
_GenericMap.py
Go to the documentation of this file.
1 # This file is part of afw.
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 __all__ = ["GenericMap", "MutableGenericMap"]
23 
24 from collections.abc import Mapping, MutableMapping
25 
26 from lsst.utils import TemplateMeta
27 from ._typehandling import GenericMapS, MutableGenericMapS
28 
29 
30 class GenericMap(metaclass=TemplateMeta):
31  """An abstract `~collections.abc.Mapping` for use when sharing a
32  map between C++ and Python.
33 
34  For compatibility with C++, ``GenericMap`` has the following
35  restrictions:
36 
37  - all keys must be of the same type
38  - values must be built-in types or subclasses of
39  `lsst.afw.typehandling.Storable`. Almost any user-defined class in
40  C++ or Python can have `~lsst.afw.typehandling.Storable` as a mixin.
41 
42  As a safety precaution, `~lsst.afw.typehandling.Storable` objects that are
43  added from C++ may be copied when you retrieve them from Python, making it
44  impossible to modify them in-place. This issue does not affect objects that
45  are added from Python, or objects that are always passed by
46  :cpp:class:`shared_ptr` in C++.
47  """
48 
49  def __repr__(self):
50  className = type(self).__name__
51  return className + "({" + ", ".join("%r: %r" % (key, value) for key, value in self.itemsitems()) + "})"
52 
53  # Support equality with any Mapping, including dict
54  # Not clear why Mapping.__eq__ doesn't work
55  def __eq__(self, other):
56  if len(self) != len(other):
57  return False
58 
59  for key, value in self.itemsitems():
60  try:
61  if (value != other[key]):
62  return False
63  except KeyError:
64  return False
65  return True
66 
67  # Easier than making GenericMap actually inherit from Mapping
68  keys = Mapping.keys
69  values = Mapping.values
70  items = Mapping.items
71 
72 
73 GenericMap.register(str, GenericMapS)
74 Mapping.register(GenericMapS)
75 
76 
78  """An abstract `~collections.abc.MutableMapping` for use when sharing a
79  map between C++ and Python.
80 
81  For compatibility with C++, ``MutableGenericMap`` has the following
82  restrictions:
83 
84  - all keys must be of the same type
85  - values must be built-in types or subclasses of
86  `lsst.afw.typehandling.Storable`. Almost any user-defined class in
87  C++ or Python can have `~lsst.afw.typehandling.Storable` as a mixin.
88 
89  As a safety precaution, `~lsst.afw.typehandling.Storable` objects that are
90  added from C++ may be copied when you retrieve them from Python, making it
91  impossible to modify them in-place. This issue does not affect objects that
92  are added from Python, or objects that are always passed by
93  :cpp:class:`shared_ptr` in C++.
94 
95  Notes
96  -----
97  Key-type specializations of ``MutableGenericMap`` are available as, e.g.,
98  ``MutableGenericMap[str]``.
99  """
100 
101  # Easier than making MutableGenericMap actually inherit from MutableMapping
102  setdefault = MutableMapping.setdefault
103  update = MutableMapping.update
104 
105  # MutableMapping.pop relies on implementation details of MutableMapping
106  def pop(self, key, default=None):
107  try:
108  value = self[key]
109  del self[key]
110  return value
111  except KeyError:
112  if default is not None:
113  return default
114  else:
115  raise
116 
117 
118 MutableGenericMap.register(str, MutableGenericMapS)
119 MutableMapping.register(MutableGenericMapS)
120 
121 
122 class AutoKeyMeta(TemplateMeta):
123  """A metaclass for abstract mappings whose key type is implied by their
124  constructor arguments.
125 
126  This metaclass requires that the mapping have a `dict`-like constructor,
127  i.e., it takes a mapping or an iterable of key-value pairs as its first
128  positional parameter.
129 
130  This class differs from `~lsst.utils.TemplateMeta` only in that the dtype
131  (or equivalent) constructor keyword is optional. If it is omitted, the
132  class will attempt to infer it from the first argument.
133  """
134 
135  def __call__(cls, *args, **kwargs): # noqa N805, non-self first param
136  if len(cls.TEMPLATE_PARAMS) != 1:
137  raise ValueError("AutoKeyMeta requires exactly one template parameter")
138  dtypeKey = cls.TEMPLATE_PARAMS[0]
139  dtype = kwargs.get(dtypeKey, None)
140 
141  # Try to infer dtype if not provided
142  if dtype is None and len(args) >= 1:
143  dtype = cls._guessKeyType_guessKeyType(args[0])
144  if dtype is not None:
145  kwargs[dtypeKey] = dtype
146 
147  return super().__call__(*args, **kwargs)
148 
149  def _guessKeyType(cls, inputData): # noqa N805, non-self first param
150  """Try to infer the key type of a map from its input.
151 
152  Parameters
153  ----------
154  inputData : `~collections.abc.Mapping` or iterable of pairs
155  Any object that can be passed to a `dict`-like constructor. Keys
156  are assumed homogeneous (if not, a
157  `~lsst.afw.typehandling.GenericMap` constructor will raise
158  `TypeError` no matter what key type, if any, is provided).
159 
160  Returns
161  -------
162  keyType : `type`
163  The type of the keys in ``inputData``, or `None` if the type could
164  not be inferred.
165  """
166  if inputData:
167  firstKey = None
168  if isinstance(inputData, Mapping):
169  # mapping to copy
170  firstKey = iter(inputData.keys()).__next__()
171  elif not isinstance(inputData, str):
172  # iterable of key-value pairs
173  try:
174  firstKey = iter(inputData).__next__()[0]
175  except TypeError:
176  # Not an iterable of pairs
177  pass
178  if firstKey:
179  return type(firstKey)
180  # Any other input is either empty or an invalid input to dict-like constructors
181  return None
table::Key< int > type
Definition: Detector.cc:163