LSSTApplications  17.0+11,17.0+34,17.0+56,17.0+57,17.0+59,17.0+7,17.0-1-g377950a+33,17.0.1-1-g114240f+2,17.0.1-1-g4d4fbc4+28,17.0.1-1-g55520dc+49,17.0.1-1-g5f4ed7e+52,17.0.1-1-g6dd7d69+17,17.0.1-1-g8de6c91+11,17.0.1-1-gb9095d2+7,17.0.1-1-ge9fec5e+5,17.0.1-1-gf4e0155+55,17.0.1-1-gfc65f5f+50,17.0.1-1-gfc6fb1f+20,17.0.1-10-g87f9f3f+1,17.0.1-11-ge9de802+16,17.0.1-16-ga14f7d5c+4,17.0.1-17-gc79d625+1,17.0.1-17-gdae4c4a+8,17.0.1-2-g26618f5+29,17.0.1-2-g54f2ebc+9,17.0.1-2-gf403422+1,17.0.1-20-g2ca2f74+6,17.0.1-23-gf3eadeb7+1,17.0.1-3-g7e86b59+39,17.0.1-3-gb5ca14a,17.0.1-3-gd08d533+40,17.0.1-30-g596af8797,17.0.1-4-g59d126d+4,17.0.1-4-gc69c472+5,17.0.1-6-g5afd9b9+4,17.0.1-7-g35889ee+1,17.0.1-7-gc7c8782+18,17.0.1-9-gc4bbfb2+3,w.2019.22
LSSTDataManagementBasePackage
propertyContainerContinued.py
Go to the documentation of this file.
1 #
2 # LSST Data Management System
3 #
4 # Copyright 2008-2017 AURA/LSST.
5 #
6 # This product includes software developed by the
7 # LSST Project (http://www.lsst.org/).
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 LSST License Statement and
20 # the GNU General Public License along with this program. If not,
21 # see <http://www.lsstcorp.org/LegalNotices/>.
22 #
23 
24 
25 __all__ = ["getPropertySetState", "getPropertyListState", "setPropertySetState", "setPropertyListState"]
26 
27 import enum
28 import numbers
29 from collections.abc import Mapping, KeysView
30 
31 # Ensure that C++ exceptions are properly translated to Python
32 import lsst.pex.exceptions # noqa: F401
33 from lsst.utils import continueClass
34 
35 from .propertySet import PropertySet
36 from .propertyList import PropertyList
37 from ..dateTime import DateTime
38 
39 
40 def getPropertySetState(container, asLists=False):
41  """Get the state of a PropertySet in a form that can be pickled.
42 
43  Parameters
44  ----------
45  container : `PropertySet`
46  The property container.
47  asLists : `bool`, optional
48  If False, the default, `tuple` will be used for the contents. If true
49  a `list` will be used.
50 
51  Returns
52  -------
53  state : `list` of `tuple` or `list` of `list`
54  The state, as a list of tuples (or lists), each of which contains
55  the following 3 items:
56  - name (a `str`): the name of the item
57  - elementTypeName (a `str`): the suffix of a ``setX`` method name
58  which is appropriate for the data type. For example integer
59  data has ``elementTypeName="Int"` which corresponds to
60  the ``setInt`` method.
61  - value: the data for the item, in a form compatible
62  with the set method named by ``elementTypeName``
63  """
64  names = container.names(topLevelOnly=True)
65  sequence = list if asLists else tuple
66  return [sequence((name, _propertyContainerElementTypeName(container, name),
67  _propertyContainerGet(container, name, returnStyle=ReturnStyle.AUTO)))
68  for name in names]
69 
70 
71 def getPropertyListState(container, asLists=False):
72  """Get the state of a PropertyList in a form that can be pickled.
73 
74  Parameters
75  ----------
76  container : `PropertyList`
77  The property container.
78  asLists : `bool`, optional
79  If False, the default, `tuple` will be used for the contents. If true
80  a `list` will be used.
81 
82  Returns
83  -------
84  state : `list` of `tuple` or `list` of `list`
85  The state, as a list of tuples (or lists), each of which contains
86  the following 4 items:
87  - name (a `str`): the name of the item
88  - elementTypeName (a `str`): the suffix of a ``setX`` method name
89  which is appropriate for the data type. For example integer
90  data has ``elementTypeName="Int"` which corresponds to
91  the ``setInt`` method.
92  - value: the data for the item, in a form compatible
93  with the set method named by ``elementTypeName``
94  - comment (a `str`): the comment. This item is only present
95  if ``container`` is a PropertyList.
96  """
97  sequence = list if asLists else tuple
98  return [sequence((name, _propertyContainerElementTypeName(container, name),
99  _propertyContainerGet(container, name, returnStyle=ReturnStyle.AUTO),
100  container.getComment(name)))
101  for name in container.getOrderedNames()]
102 
103 
104 def setPropertySetState(container, state):
105  """Restore the state of a PropertySet, in place.
106 
107  Parameters
108  ----------
109  container : `PropertySet`
110  The property container whose state is to be restored.
111  It should be empty to start with and is updated in place.
112  state : `list`
113  The state, as returned by `getPropertySetState`
114  """
115  for name, elemType, value in state:
116  if elemType is not None:
117  getattr(container, "set" + elemType)(name, value)
118  else:
119  raise ValueError(f"Unrecognized values for state restoration: ({name}, {elemType}, {value})")
120 
121 
122 def setPropertyListState(container, state):
123  """Restore the state of a PropertyList, in place.
124 
125  Parameters
126  ----------
127  container : `PropertyList`
128  The property container whose state is to be restored.
129  It should be empty to start with and is updated in place.
130  state : `list`
131  The state, as returned by ``getPropertyListState``
132  """
133  for name, elemType, value, comment in state:
134  getattr(container, "set" + elemType)(name, value, comment)
135 
136 
137 class ReturnStyle(enum.Enum):
138  ARRAY = enum.auto()
139  SCALAR = enum.auto()
140  AUTO = enum.auto()
141 
142 
143 def _propertyContainerElementTypeName(container, name):
144  """Return name of the type of a particular element"""
145  try:
146  t = container.typeOf(name)
147  except LookupError as e:
148  # KeyError is more commonly expected when asking for an element
149  # from a mapping.
150  raise KeyError(str(e))
151  for checkType in ("Bool", "Short", "Int", "Long", "LongLong", "Float", "Double", "String", "DateTime",
152  "PropertySet", "Undef"):
153  if t == getattr(container, "TYPE_" + checkType):
154  return checkType
155  return None
156 
157 
158 def _propertyContainerGet(container, name, returnStyle):
159  """Get a value of unknown type as a scalar or array
160 
161  Parameters
162  ----------
163  container : `lsst.daf.base.PropertySet` or `lsst.daf.base.PropertyList`
164  Container from which to get the value
165  name : `str`
166  Name of item
167  returnStyle : `ReturnStyle`
168  Control whether numeric or string data is returned as an array
169  or scalar (the other types, ``PropertyList``, ``PropertySet``
170  and ``PersistablePtr``, are always returned as a scalar):
171  - ReturnStyle.ARRAY: return numeric or string data types
172  as an array of values.
173  - ReturnStyle.SCALAR: return numeric or string data types
174  as a single value; if the item has multiple values then
175  return the last value.
176  - ReturnStyle.AUTO: (deprecated) return numeric or string data
177  as a scalar if there is just one item, or as an array
178  otherwise.
179 
180  Raises
181  ------
182  KeyError
183  Raised if the specified key does not exist in the container.
184  TypeError
185  Raised if the value retrieved is of an unexpected type.
186  ValueError
187  Raised if the value for ``returnStyle`` is not correct.
188  """
189  if not container.exists(name):
190  raise KeyError(name + " not found")
191  if returnStyle not in ReturnStyle:
192  raise ValueError("returnStyle {} must be a ReturnStyle".format(returnStyle))
193 
194  elemType = _propertyContainerElementTypeName(container, name)
195  if elemType and elemType != "PropertySet":
196  value = getattr(container, "getArray" + elemType)(name)
197  if returnStyle == ReturnStyle.ARRAY or (returnStyle == ReturnStyle.AUTO and len(value) > 1):
198  return value
199  return value[-1]
200 
201  if container.isPropertySetPtr(name):
202  try:
203  return container.getAsPropertyListPtr(name)
204  except Exception:
205  return container.getAsPropertySetPtr(name)
206  try:
207  return container.getAsPersistablePtr(name)
208  except Exception:
209  pass
210  raise TypeError('Unknown PropertySet value type for ' + name)
211 
212 
213 def _guessIntegerType(container, name, value):
214  """Given an existing container and name, determine the type
215  that should be used for the supplied value. The supplied value
216  is assumed to be a scalar.
217 
218  On Python 3 all ints are LongLong but we need to be able to store them
219  in Int containers if that is what is being used (testing for truncation).
220  Int is assumed to mean 32bit integer (2147483647 to -2147483648).
221 
222  If there is no pre-existing value we have to decide what to do. For now
223  we pick Int if the value is less than maxsize.
224 
225  Returns None if the value supplied is a bool or not an integral value.
226  """
227  useType = None
228  maxInt = 2147483647
229  minInt = -2147483648
230 
231  # We do not want to convert bool to int so let the system work that
232  # out itself
233  if isinstance(value, bool):
234  return useType
235 
236  if isinstance(value, numbers.Integral):
237  try:
238  containerType = _propertyContainerElementTypeName(container, name)
239  except LookupError:
240  # nothing in the container so choose based on size. Safe option is
241  # to always use LongLong
242  if value <= maxInt and value >= minInt:
243  useType = "Int"
244  else:
245  useType = "LongLong"
246  else:
247  if containerType == "Int":
248  # Always use an Int even if we know it won't fit. The later
249  # code will trigger OverflowError if appropriate. Setting the
250  # type to LongLong here will trigger a TypeError instead so
251  # it's best to trigger a predictable OverflowError.
252  useType = "Int"
253  elif containerType == "LongLong":
254  useType = "LongLong"
255  return useType
256 
257 
258 def _propertyContainerSet(container, name, value, typeMenu, *args):
259  """Set a single Python value of unknown type"""
260  if hasattr(value, "__iter__") and not isinstance(value, (str, PropertySet, PropertyList)):
261  exemplar = value[0]
262  else:
263  exemplar = value
264 
265  t = type(exemplar)
266  setType = _guessIntegerType(container, name, exemplar)
267 
268  if setType is not None or t in typeMenu:
269  if setType is None:
270  setType = typeMenu[t]
271  return getattr(container, "set" + setType)(name, value, *args)
272  # Allow for subclasses
273  for checkType in typeMenu:
274  if (checkType is None and exemplar is None) or \
275  (checkType is not None and isinstance(exemplar, checkType)):
276  return getattr(container, "set" + typeMenu[checkType])(name, value, *args)
277  raise TypeError("Unknown value type for key '%s': %s" % (name, t))
278 
279 
280 def _propertyContainerAdd(container, name, value, typeMenu, *args):
281  """Add a single Python value of unknown type"""
282  if hasattr(value, "__iter__"):
283  exemplar = value[0]
284  else:
285  exemplar = value
286 
287  t = type(exemplar)
288  addType = _guessIntegerType(container, name, exemplar)
289 
290  if addType is not None or t in typeMenu:
291  if addType is None:
292  addType = typeMenu[t]
293  return getattr(container, "add" + addType)(name, value, *args)
294  # Allow for subclasses
295  for checkType in typeMenu:
296  if (checkType is None and exemplar is None) or \
297  (checkType is not None and isinstance(exemplar, checkType)):
298  return getattr(container, "add" + typeMenu[checkType])(name, value, *args)
299  raise TypeError("Unknown value type for key '%s': %s" % (name, t))
300 
301 
302 def _makePropertySet(state):
303  """Make a `PropertySet` from the state returned by `getPropertySetState`
304 
305  Parameters
306  ----------
307  state : `list`
308  The data returned by `getPropertySetState`.
309  """
310  ps = PropertySet()
311  setPropertySetState(ps, state)
312  return ps
313 
314 
315 def _makePropertyList(state):
316  """Make a `PropertyList` from the state returned by
317  `getPropertyListState`
318 
319  Parameters
320  ----------
321  state : `list`
322  The data returned by `getPropertySetState`.
323  """
324  pl = PropertyList()
325  setPropertyListState(pl, state)
326  return pl
327 
328 
329 @continueClass
331  # Mapping of type to method names;
332  # int types are omitted due to use of _guessIntegerType
333  _typeMenu = {bool: "Bool",
334  float: "Double",
335  str: "String",
336  DateTime: "DateTime",
337  PropertySet: "PropertySet",
338  PropertyList: "PropertySet",
339  None: "Undef",
340  }
341 
342  def get(self, name, default=None):
343  """Return an item as a scalar, else default.
344 
345  Identical to `getScalar` except that a default value is returned
346  if the requested key is not present. If an array item is requested
347  the final value in the array will be returned.
348 
349  Parameters
350  ----------
351  name : ``str``
352  Name of item
353  default : `object`, optional
354  Default value to use if the named item is not present.
355 
356  Returns
357  -------
358  value : any type supported by container
359  Single value of any type supported by the container, else the
360  default value if the requested item is not present in the
361  container. For array items the most recently added value is
362  returned.
363  """
364  try:
365  return _propertyContainerGet(self, name, returnStyle=ReturnStyle.SCALAR)
366  except KeyError:
367  return default
368 
369  def getArray(self, name):
370  """Return an item as an array if the item is numeric or string
371 
372  If the item is a `PropertySet`, `PropertyList` or
373  `lsst.daf.base.PersistablePtr` then return the item as a scalar.
374 
375  Parameters
376  ----------
377  name : `str`
378  Name of item
379 
380  Returns
381  -------
382  values : `list` of any type supported by container
383  The contents of the item, guaranteed to be returned as a `list.`
384 
385  Raises
386  ------
387  KeyError
388  Raised if the item does not exist.
389  """
390  return _propertyContainerGet(self, name, returnStyle=ReturnStyle.ARRAY)
391 
392  def getScalar(self, name):
393  """Return an item as a scalar
394 
395  If the item has more than one value then the last value is returned.
396 
397  Parameters
398  ----------
399  name : `str`
400  Name of item
401 
402  Returns
403  -------
404  value : scalar item
405  Value stored in the item. If the item refers to an array the
406  most recently added value is returned.
407 
408  Raises
409  ------
410  KeyError
411  Raised if the item does not exist.
412  """
413  return _propertyContainerGet(self, name, returnStyle=ReturnStyle.SCALAR)
414 
415  def set(self, name, value):
416  """Set the value of an item
417 
418  If the item already exists it is silently replaced; the types
419  need not match.
420 
421  Parameters
422  ----------
423  name : `str`
424  Name of item
425  value : any supported type
426  Value of item; may be a scalar or array
427  """
428  return _propertyContainerSet(self, name, value, self._typeMenu)
429 
430  def add(self, name, value):
431  """Append one or more values to a given item, which need not exist
432 
433  If the item exists then the new value(s) are appended;
434  otherwise it is like calling `set`
435 
436  Parameters
437  ----------
438  name : `str`
439  Name of item
440  value : any supported type
441  Value of item; may be a scalar or array
442 
443  Notes
444  -----
445  If ``value`` is an `lsst.daf.base.PropertySet` or
446  `lsst.daf.base.PropertyList` then ``value`` replaces
447  the existing value. Also the item is added as a live
448  reference, so updating ``value`` will update this container
449  and vice-versa.
450 
451  Raises
452  ------
453  lsst::pex::exceptions::TypeError
454  Raised if the type of `value` is incompatible with the existing
455  value of the item.
456  """
457  return _propertyContainerAdd(self, name, value, self._typeMenu)
458 
459  def update(self, addition):
460  """Update the current container with the supplied additions.
461 
462  Parameters
463  ----------
464  addition : `collections.abc.Mapping` or `PropertySet`
465  The content to merge into the current container.
466 
467  Notes
468  -----
469  If the supplied parameter is a `PropertySet` then the
470  `PropertySet.combine` method will be used. If the supplied parameter
471  is a `collections.abc.Mapping` each item will be copied out of the
472  mapping and value assigned using `PropertySet.set`, overwriting
473  any previous values.
474  """
475  if isinstance(addition, PropertySet):
476  self.combine(addition)
477  else:
478  for k, v in addition.items():
479  self[k] = v
480 
481  def toDict(self):
482  """Returns a (possibly nested) dictionary with all properties.
483 
484  Returns
485  -------
486  d : `dict`
487  Dictionary with all names and values (no comments).
488  """
489 
490  d = {}
491  for name in self.names():
492  v = _propertyContainerGet(self, name, returnStyle=ReturnStyle.AUTO)
493 
494  if isinstance(v, PropertySet):
495  d[name] = PropertySet.toDict(v)
496  else:
497  d[name] = v
498  return d
499 
500  def __eq__(self, other):
501  if type(self) != type(other):
502  return False
503 
504  if len(self) != len(other):
505  return False
506 
507  for name in self:
508  if _propertyContainerGet(self, name, returnStyle=ReturnStyle.AUTO) != \
509  _propertyContainerGet(other, name, returnStyle=ReturnStyle.AUTO):
510  return False
511  if self.typeOf(name) != other.typeOf(name):
512  return False
513 
514  return True
515 
516  def __copy__(self):
517  # Copy without having to go through pickle state
518  ps = PropertySet()
519  for itemName in self:
520  ps.copy(itemName, self, itemName)
521  return ps
522 
523  def __deepcopy__(self, memo):
524  result = self.deepCopy()
525  memo[id(self)] = result
526  return result
527 
528  def __contains__(self, name):
529  """Determines if the name is found at the top level hierarchy
530  of the container.
531 
532  Notes
533  ------
534  Does not use `PropertySet.exists()`` because that includes support
535  for "."-delimited names. This method is consistent with the
536  items returned from ``__iter__``.
537  """
538  return name in self.names(topLevelOnly=True)
539 
540  def __setitem__(self, name, value):
541  """Assigns the supplied value to the container.
542 
543  Parameters
544  ----------
545  name : `str`
546  Name of item to update.
547  value : Value to assign
548  Can be any value supported by the container's ``set()``
549  method. `~collections.abc.Mapping` are converted to
550  `PropertySet` before assignment.
551 
552  Notes
553  -----
554  Uses `PropertySet.set`, overwriting any previous value.
555  """
556  if isinstance(value, Mapping):
557  # Create a property set instead
558  ps = PropertySet()
559  for k, v in value.items():
560  ps[k] = v
561  value = ps
562  self.set(name, value)
563 
564  def __getitem__(self, name):
565  """Returns a scalar item from the container.
566 
567  Notes
568  -----
569  Uses `PropertySet.getScalar` to guarantee that a single value
570  will be returned.
571  """
572  return self.getScalar(name)
573 
574  def __delitem__(self, name):
575  if name in self:
576  self.remove(name)
577  else:
578  raise KeyError(f"{name} not present in dict")
579 
580  def __str__(self):
581  return self.toString()
582 
583  def __len__(self):
584  return self.nameCount(topLevelOnly=True)
585 
586  def __iter__(self):
587  for n in self.names(topLevelOnly=True):
588  yield n
589 
590  def keys(self):
591  return KeysView(self)
592 
593  def __reduce__(self):
594  # It would be a bit simpler to use __setstate__ and __getstate__.
595  # However, implementing __setstate__ in Python causes segfaults
596  # because pickle creates a new instance by calling
597  # object.__new__(PropertyList, *args) which bypasses
598  # the pybind11 memory allocation step.
599  return (_makePropertySet, (getPropertySetState(self),))
600 
601 
602 @continueClass
604  # Mapping of type to method names
605  _typeMenu = {bool: "Bool",
606  int: "Int",
607  float: "Double",
608  str: "String",
609  DateTime: "DateTime",
610  PropertySet: "PropertySet",
611  PropertyList: "PropertySet",
612  None: "Undef",
613  }
614 
615  COMMENTSUFFIX = "#COMMENT"
616  """Special suffix used to indicate that a named item being assigned
617  using dict syntax is referring to a comment, not value."""
618 
619  def get(self, name, default=None):
620  """Return an item as a scalar, else default.
621 
622  Identical to `getScalar` except that a default value is returned
623  if the requested key is not present. If an array item is requested
624  the final value in the array will be returned.
625 
626  Parameters
627  ----------
628  name : ``str``
629  Name of item
630  default : `object`, optional
631  Default value to use if the named item is not present.
632 
633  Returns
634  -------
635  value : any type supported by container
636  Single value of any type supported by the container, else the
637  default value if the requested item is not present in the
638  container. For array items the most recently added value is
639  returned.
640  """
641  try:
642  return _propertyContainerGet(self, name, returnStyle=ReturnStyle.SCALAR)
643  except KeyError:
644  return default
645 
646  def getArray(self, name):
647  """Return an item as a list.
648 
649  Parameters
650  ----------
651  name : `str`
652  Name of item
653 
654  Returns
655  -------
656  values : `list` of values
657  The contents of the item, guaranteed to be returned as a `list.`
658 
659  Raises
660  ------
661  KeyError
662  Raised if the item does not exist.
663  """
664  return _propertyContainerGet(self, name, returnStyle=ReturnStyle.ARRAY)
665 
666  def getScalar(self, name):
667  """Return an item as a scalar
668 
669  If the item has more than one value then the last value is returned.
670 
671  Parameters
672  ----------
673  name : `str`
674  Name of item.
675 
676  Returns
677  -------
678  value : scalar item
679  Value stored in the item. If the item refers to an array the
680  most recently added value is returned.
681 
682  Raises
683  ------
684  KeyError
685  Raised if the item does not exist.
686  """
687  return _propertyContainerGet(self, name, returnStyle=ReturnStyle.SCALAR)
688 
689  def set(self, name, value, comment=None):
690  """Set the value of an item
691 
692  If the item already exists it is silently replaced; the types
693  need not match.
694 
695  Parameters
696  ----------
697  name : `str`
698  Name of item
699  value : any supported type
700  Value of item; may be a scalar or array
701  """
702  args = []
703  if comment is not None:
704  args.append(comment)
705  return _propertyContainerSet(self, name, value, self._typeMenu, *args)
706 
707  def add(self, name, value, comment=None):
708  """Append one or more values to a given item, which need not exist
709 
710  If the item exists then the new value(s) are appended;
711  otherwise it is like calling `set`
712 
713  Parameters
714  ----------
715  name : `str`
716  Name of item
717  value : any supported type
718  Value of item; may be a scalar or array
719 
720  Notes
721  -----
722  If `value` is an `lsst.daf.base.PropertySet` items are added
723  using dotted names (e.g. if name="a" and value contains
724  an item "b" which is another PropertySet and contains an
725  item "c" which is numeric or string, then the value of "c"
726  is added as "a.b.c", appended to the existing values of
727  "a.b.c" if any (in which case the types must be compatible).
728 
729  Raises
730  ------
731  lsst::pex::exceptions::TypeError
732  Raise if the type of ``value`` is incompatible with the existing
733  value of the item.
734  """
735  args = []
736  if comment is not None:
737  args.append(comment)
738  return _propertyContainerAdd(self, name, value, self._typeMenu, *args)
739 
740  def setComment(self, name, comment):
741  """Set the comment for an existing entry.
742 
743  Parameters
744  ----------
745  name : `str`
746  Name of the key to receive updated comment.
747  comment : `comment`
748  New comment string.
749  """
750  # The only way to do this is to replace the existing entry with
751  # one that has the new comment
752  containerType = _propertyContainerElementTypeName(self, name)
753  if self.isArray(name):
754  value = self.getArray(name)
755  else:
756  value = self.getScalar(name)
757  getattr(self, f"set{containerType}")(name, value, comment)
758 
759  def toList(self):
760  """Return a list of tuples of name, value, comment for each property
761  in the order that they were inserted.
762 
763  Returns
764  -------
765  ret : `list` of `tuple`
766  Tuples of name, value, comment for each property in the order
767  in which they were inserted.
768  """
769  orderedNames = self.getOrderedNames()
770  ret = []
771  for name in orderedNames:
772  if self.isArray(name):
773  values = _propertyContainerGet(self, name, returnStyle=ReturnStyle.AUTO)
774  for v in values:
775  ret.append((name, v, self.getComment(name)))
776  else:
777  ret.append((name, _propertyContainerGet(self, name, returnStyle=ReturnStyle.AUTO),
778  self.getComment(name)))
779  return ret
780 
781  def toOrderedDict(self):
782  """Return an ordered dictionary with all properties in the order that
783  they were inserted.
784 
785  Returns
786  -------
787  d : `dict`
788  Ordered dictionary with all properties in the order that they
789  were inserted. Comments are not included.
790 
791  Notes
792  -----
793  As of Python 3.6 dicts retain their insertion order.
794  """
795  d = {}
796  for name in self:
797  d[name] = _propertyContainerGet(self, name, returnStyle=ReturnStyle.AUTO)
798  return d
799 
800  # For PropertyList the two are equivalent
801  toDict = toOrderedDict
802 
803  def __eq__(self, other):
804  # super() doesn't seem to work properly in @continueClass;
805  # note that super with arguments seems to work at first, but actually
806  # doesn't either.
807  if not PropertySet.__eq__(self, other):
808  return False
809 
810  for name in self:
811  if self.getComment(name) != other.getComment(name):
812  return False
813 
814  return True
815 
816  def __copy__(self):
817  # Copy without having to go through pickle state
818  pl = PropertyList()
819  for itemName in self:
820  pl.copy(itemName, self, itemName)
821  return pl
822 
823  def __deepcopy__(self, memo):
824  result = self.deepCopy()
825  memo[id(self)] = result
826  return result
827 
828  def __iter__(self):
829  for n in self.getOrderedNames():
830  yield n
831 
832  def __setitem__(self, name, value):
833  """Assigns the supplied value to the container.
834 
835  Parameters
836  ----------
837  name : `str`
838  Name of item to update. If the name ends with
839  `PropertyList.COMMENTSUFFIX`, the comment is updated rather
840  than the value.
841  value : Value to assign
842  Can be any value supported by the container's ``set()``
843  method. `~collections.abc.Mapping` are converted to
844  `PropertySet` before assignment.
845 
846  Notes
847  -----
848  Uses `PropertySet.set`, overwriting any previous value.
849  """
850  if name.endswith(self.COMMENTSUFFIX):
851  name = name[:-len(self.COMMENTSUFFIX)]
852  self.setComment(name, value)
853  return
854  if isinstance(value, Mapping):
855  # Create a property set instead
856  ps = PropertySet()
857  for k, v in value.items():
858  ps[k] = v
859  value = ps
860  self.set(name, value)
861 
862  def __reduce__(self):
863  # It would be a bit simpler to use __setstate__ and __getstate__.
864  # However, implementing __setstate__ in Python causes segfaults
865  # because pickle creates a new instance by calling
866  # object.__new__(PropertyList, *args) which bypasses
867  # the pybind11 memory allocation step.
868  return (_makePropertyList, (getPropertyListState(self),))
table::Key< int > id
Definition: Detector.cc:166
table::Key< int > type
Definition: Detector.cc:167
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:168