25 __all__ = [
"getPropertySetState",
"getPropertyListState",
"setPropertySetState",
"setPropertyListState"]
29 from collections.abc
import Mapping, KeysView, ValuesView, ItemsView
35 from .propertySet
import PropertySet
36 from .propertyList
import PropertyList
37 from ..dateTime
import DateTime
41 """Get the state of a PropertySet in a form that can be pickled. 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. 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`` 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)))
72 """Get the state of a PropertyList in a form that can be pickled. 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. 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. 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()]
105 """Restore the state of a PropertySet, in place. 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. 113 The state, as returned by `getPropertySetState` 115 for name, elemType, value
in state:
116 if elemType
is not None:
117 getattr(container,
"set" + elemType)(name, value)
119 raise ValueError(f
"Unrecognized values for state restoration: ({name}, {elemType}, {value})")
123 """Restore the state of a PropertyList, in place. 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. 131 The state, as returned by ``getPropertyListState`` 133 for name, elemType, value, comment
in state:
134 getattr(container,
"set" + elemType)(name, value, comment)
143 def _propertyContainerElementTypeName(container, name):
144 """Return name of the type of a particular element""" 146 t = container.typeOf(name)
147 except LookupError
as e:
150 raise KeyError(str(e))
151 for checkType
in (
"Bool",
"Short",
"Int",
"Long",
"LongLong",
"UnsignedLongLong",
152 "Float",
"Double",
"String",
"DateTime",
153 "PropertySet",
"Undef"):
154 if t == getattr(container,
"TYPE_" + checkType):
159 def _propertyContainerGet(container, name, returnStyle):
160 """Get a value of unknown type as a scalar or array 164 container : `lsst.daf.base.PropertySet` or `lsst.daf.base.PropertyList` 165 Container from which to get the value 168 returnStyle : `ReturnStyle` 169 Control whether numeric or string data is returned as an array 170 or scalar (the other types, ``PropertyList``, ``PropertySet`` 171 and ``PersistablePtr``, are always returned as a scalar): 172 - ReturnStyle.ARRAY: return numeric or string data types 173 as an array of values. 174 - ReturnStyle.SCALAR: return numeric or string data types 175 as a single value; if the item has multiple values then 176 return the last value. 177 - ReturnStyle.AUTO: (deprecated) return numeric or string data 178 as a scalar if there is just one item, or as an array 184 Raised if the specified key does not exist in the container. 186 Raised if the value retrieved is of an unexpected type. 188 Raised if the value for ``returnStyle`` is not correct. 190 if not container.exists(name):
191 raise KeyError(name +
" not found")
192 if returnStyle
not in ReturnStyle:
193 raise ValueError(
"returnStyle {} must be a ReturnStyle".format(returnStyle))
195 elemType = _propertyContainerElementTypeName(container, name)
196 if elemType
and elemType !=
"PropertySet":
197 value = getattr(container,
"getArray" + elemType)(name)
198 if returnStyle == ReturnStyle.ARRAY
or (returnStyle == ReturnStyle.AUTO
and len(value) > 1):
202 if container.isPropertySetPtr(name):
204 return container.getAsPropertyListPtr(name)
206 return container.getAsPropertySetPtr(name)
208 return container.getAsPersistablePtr(name)
211 raise TypeError(
'Unknown PropertySet value type for ' + name)
214 def _guessIntegerType(container, name, value):
215 """Given an existing container and name, determine the type 216 that should be used for the supplied value. The supplied value 217 is assumed to be a scalar. 219 On Python 3 all ints are LongLong but we need to be able to store them 220 in Int containers if that is what is being used (testing for truncation). 221 Int is assumed to mean 32bit integer (2147483647 to -2147483648). 223 If there is no pre-existing value we have to decide what to do. For now 224 we pick Int if the value is less than maxsize. 226 Returns None if the value supplied is a bool or not an integral value. 231 maxLongLong = 2**63 - 1
238 if isinstance(value, bool):
241 if isinstance(value, numbers.Integral):
243 containerType = _propertyContainerElementTypeName(container, name)
246 if value <= maxInt
and value >= minInt:
248 elif value <= maxLongLong
and value >= minLongLong:
250 elif value <= maxU64
and value >= minU64:
251 useType =
"UnsignedLongLong" 253 raise RuntimeError(
"Unable to guess integer type for storing value: %d" % (value,))
255 if containerType ==
"Int":
261 elif containerType ==
"LongLong":
263 elif containerType ==
"UnsignedLongLong":
264 useType =
"UnsignedLongLong" 268 def _propertyContainerSet(container, name, value, typeMenu, *args):
269 """Set a single Python value of unknown type""" 270 if hasattr(value,
"__iter__")
and not isinstance(value, (str, PropertySet, PropertyList)):
276 setType = _guessIntegerType(container, name, exemplar)
278 if setType
is not None or t
in typeMenu:
280 setType = typeMenu[t]
281 return getattr(container,
"set" + setType)(name, value, *args)
283 for checkType
in typeMenu:
284 if (checkType
is None and exemplar
is None)
or \
285 (checkType
is not None and isinstance(exemplar, checkType)):
286 return getattr(container,
"set" + typeMenu[checkType])(name, value, *args)
287 raise TypeError(
"Unknown value type for key '%s': %s" % (name, t))
290 def _propertyContainerAdd(container, name, value, typeMenu, *args):
291 """Add a single Python value of unknown type""" 292 if hasattr(value,
"__iter__"):
298 addType = _guessIntegerType(container, name, exemplar)
300 if addType
is not None or t
in typeMenu:
302 addType = typeMenu[t]
303 return getattr(container,
"add" + addType)(name, value, *args)
305 for checkType
in typeMenu:
306 if (checkType
is None and exemplar
is None)
or \
307 (checkType
is not None and isinstance(exemplar, checkType)):
308 return getattr(container,
"add" + typeMenu[checkType])(name, value, *args)
309 raise TypeError(
"Unknown value type for key '%s': %s" % (name, t))
312 def _makePropertySet(state):
313 """Make a `PropertySet` from the state returned by `getPropertySetState` 318 The data returned by `getPropertySetState`. 325 def _makePropertyList(state):
326 """Make a `PropertyList` from the state returned by 327 `getPropertyListState` 332 The data returned by `getPropertySetState`. 343 _typeMenu = {bool:
"Bool",
346 DateTime:
"DateTime",
347 PropertySet:
"PropertySet",
348 PropertyList:
"PropertySet",
352 def get(self, name, default=None):
353 """Return an item as a scalar, else default. 355 Identical to `getScalar` except that a default value is returned 356 if the requested key is not present. If an array item is requested 357 the final value in the array will be returned. 363 default : `object`, optional 364 Default value to use if the named item is not present. 368 value : any type supported by container 369 Single value of any type supported by the container, else the 370 default value if the requested item is not present in the 371 container. For array items the most recently added value is 375 return _propertyContainerGet(self, name, returnStyle=ReturnStyle.SCALAR)
380 """Return an item as an array if the item is numeric or string 382 If the item is a `PropertySet`, `PropertyList` or 383 `lsst.daf.base.PersistablePtr` then return the item as a scalar. 392 values : `list` of any type supported by container 393 The contents of the item, guaranteed to be returned as a `list.` 398 Raised if the item does not exist. 400 return _propertyContainerGet(self, name, returnStyle=ReturnStyle.ARRAY)
403 """Return an item as a scalar 405 If the item has more than one value then the last value is returned. 415 Value stored in the item. If the item refers to an array the 416 most recently added value is returned. 421 Raised if the item does not exist. 423 return _propertyContainerGet(self, name, returnStyle=ReturnStyle.SCALAR)
425 def set(self, name, value):
426 """Set the value of an item 428 If the item already exists it is silently replaced; the types 435 value : any supported type 436 Value of item; may be a scalar or array 438 return _propertyContainerSet(self, name, value, self.
_typeMenu)
440 def add(self, name, value):
441 """Append one or more values to a given item, which need not exist 443 If the item exists then the new value(s) are appended; 444 otherwise it is like calling `set` 450 value : any supported type 451 Value of item; may be a scalar or array 455 If ``value`` is an `lsst.daf.base.PropertySet` or 456 `lsst.daf.base.PropertyList` then ``value`` replaces 457 the existing value. Also the item is added as a live 458 reference, so updating ``value`` will update this container 463 lsst::pex::exceptions::TypeError 464 Raised if the type of `value` is incompatible with the existing 467 return _propertyContainerAdd(self, name, value, self.
_typeMenu)
470 """Update the current container with the supplied additions. 474 addition : `collections.abc.Mapping` or `PropertySet` 475 The content to merge into the current container. 479 If the supplied parameter is a `PropertySet` then the 480 `PropertySet.combine` method will be used. If the supplied parameter 481 is a `collections.abc.Mapping` each item will be copied out of the 482 mapping and value assigned using `PropertySet.set`, overwriting 485 if isinstance(addition, PropertySet):
486 self.combine(addition)
488 for k, v
in addition.items():
492 """Returns a (possibly nested) dictionary with all properties. 497 Dictionary with all names and values (no comments). 501 for name
in self.names():
502 v = _propertyContainerGet(self, name, returnStyle=ReturnStyle.AUTO)
504 if isinstance(v, PropertySet):
505 d[name] = PropertySet.toDict(v)
511 if type(self) != type(other):
514 if len(self) != len(other):
518 if _propertyContainerGet(self, name, returnStyle=ReturnStyle.AUTO) != \
519 _propertyContainerGet(other, name, returnStyle=ReturnStyle.AUTO):
521 if self.typeOf(name) != other.typeOf(name):
529 for itemName
in self:
530 ps.copy(itemName, self, itemName)
534 result = self.deepCopy()
535 memo[id(self)] = result
539 """Determines if the name is found at the top level hierarchy 544 Does not use `PropertySet.exists()`` because that includes support 545 for "."-delimited names. This method is consistent with the 546 items returned from ``__iter__``. 548 return name
in self.names(topLevelOnly=
True)
551 """Assigns the supplied value to the container. 556 Name of item to update. 557 value : Value to assign 558 Can be any value supported by the container's ``set()`` 559 method. `~collections.abc.Mapping` are converted to 560 `PropertySet` before assignment. 564 Uses `PropertySet.set`, overwriting any previous value. 566 if isinstance(value, Mapping):
569 for k, v
in value.items():
572 self.
set(name, value)
575 """Returns a scalar item from the container. 579 Uses `PropertySet.getScalar` to guarantee that a single value 588 raise KeyError(f
"{name} not present in dict")
591 return self.toString()
594 return self.nameCount(topLevelOnly=
True)
597 for n
in self.names(topLevelOnly=
True):
601 return KeysView(self)
604 return ItemsView(self)
607 return ValuesView(self)
621 _typeMenu = {bool:
"Bool",
625 DateTime:
"DateTime",
626 PropertySet:
"PropertySet",
627 PropertyList:
"PropertySet",
631 COMMENTSUFFIX =
"#COMMENT" 632 """Special suffix used to indicate that a named item being assigned 633 using dict syntax is referring to a comment, not value.""" 635 def get(self, name, default=None):
636 """Return an item as a scalar, else default. 638 Identical to `getScalar` except that a default value is returned 639 if the requested key is not present. If an array item is requested 640 the final value in the array will be returned. 646 default : `object`, optional 647 Default value to use if the named item is not present. 651 value : any type supported by container 652 Single value of any type supported by the container, else the 653 default value if the requested item is not present in the 654 container. For array items the most recently added value is 658 return _propertyContainerGet(self, name, returnStyle=ReturnStyle.SCALAR)
663 """Return an item as a list. 672 values : `list` of values 673 The contents of the item, guaranteed to be returned as a `list.` 678 Raised if the item does not exist. 680 return _propertyContainerGet(self, name, returnStyle=ReturnStyle.ARRAY)
683 """Return an item as a scalar 685 If the item has more than one value then the last value is returned. 695 Value stored in the item. If the item refers to an array the 696 most recently added value is returned. 701 Raised if the item does not exist. 703 return _propertyContainerGet(self, name, returnStyle=ReturnStyle.SCALAR)
705 def set(self, name, value, comment=None):
706 """Set the value of an item 708 If the item already exists it is silently replaced; the types 715 value : any supported type 716 Value of item; may be a scalar or array 719 if comment
is not None:
721 return _propertyContainerSet(self, name, value, self.
_typeMenu, *args)
723 def add(self, name, value, comment=None):
724 """Append one or more values to a given item, which need not exist 726 If the item exists then the new value(s) are appended; 727 otherwise it is like calling `set` 733 value : any supported type 734 Value of item; may be a scalar or array 738 If `value` is an `lsst.daf.base.PropertySet` items are added 739 using dotted names (e.g. if name="a" and value contains 740 an item "b" which is another PropertySet and contains an 741 item "c" which is numeric or string, then the value of "c" 742 is added as "a.b.c", appended to the existing values of 743 "a.b.c" if any (in which case the types must be compatible). 747 lsst::pex::exceptions::TypeError 748 Raise if the type of ``value`` is incompatible with the existing 752 if comment
is not None:
754 return _propertyContainerAdd(self, name, value, self.
_typeMenu, *args)
757 """Set the comment for an existing entry. 762 Name of the key to receive updated comment. 768 containerType = _propertyContainerElementTypeName(self, name)
769 if self.isArray(name):
773 getattr(self, f
"set{containerType}")(name, value, comment)
776 """Return a list of tuples of name, value, comment for each property 777 in the order that they were inserted. 781 ret : `list` of `tuple` 782 Tuples of name, value, comment for each property in the order 783 in which they were inserted. 785 orderedNames = self.getOrderedNames()
787 for name
in orderedNames:
788 if self.isArray(name):
789 values = _propertyContainerGet(self, name, returnStyle=ReturnStyle.AUTO)
791 ret.append((name, v, self.getComment(name)))
793 ret.append((name, _propertyContainerGet(self, name, returnStyle=ReturnStyle.AUTO),
794 self.getComment(name)))
798 """Return an ordered dictionary with all properties in the order that 804 Ordered dictionary with all properties in the order that they 805 were inserted. Comments are not included. 809 As of Python 3.6 dicts retain their insertion order. 813 d[name] = _propertyContainerGet(self, name, returnStyle=ReturnStyle.AUTO)
817 toDict = toOrderedDict
823 if not PropertySet.__eq__(self, other):
827 if self.getComment(name) != other.getComment(name):
835 for itemName
in self:
836 pl.copy(itemName, self, itemName)
840 result = self.deepCopy()
841 memo[id(self)] = result
845 for n
in self.getOrderedNames():
849 """Assigns the supplied value to the container. 854 Name of item to update. If the name ends with 855 `PropertyList.COMMENTSUFFIX`, the comment is updated rather 857 value : Value to assign 858 Can be any value supported by the container's ``set()`` 859 method. `~collections.abc.Mapping` are converted to 860 `PropertySet` before assignment. 864 Uses `PropertySet.set`, overwriting any previous value. 870 if isinstance(value, Mapping):
873 for k, v
in value.items():
876 self.
set(name, value)
def __contains__(self, name)
def add(self, name, value, comment=None)
def set(self, name, value, comment=None)
def __deepcopy__(self, memo)
def get(self, name, default=None)
def set(self, name, value)
def __setitem__(self, name, value)
def add(self, name, value)
def __getitem__(self, name)
def getPropertySetState(container, asLists=False)
def setComment(self, name, comment)
def __setitem__(self, name, value)
def getScalar(self, name)
def setPropertyListState(container, state)
def __deepcopy__(self, memo)
def getPropertyListState(container, asLists=False)
def setPropertySetState(container, state)
def __delitem__(self, name)
def get(self, name, default=None)
def getScalar(self, name)
def update(self, addition)