25 __all__ = [
"getPropertySetState", 
"getPropertyListState", 
"setPropertySetState", 
"setPropertyListState"]
 
   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: 
   59         elementTypeName (a `str`) 
   60             the suffix of a ``setX`` method name 
   61             which is appropriate for the data type. For example integer 
   62             data has ``elementTypeName="Int"` which corresponds to 
   63             the ``setInt`` method. 
   65             the data for the item, in a form compatible 
   66             with the set method named by ``elementTypeName`` 
   68     names = container.names(topLevelOnly=
True)
 
   69     sequence = list 
if asLists 
else tuple
 
   70     return [sequence((name, _propertyContainerElementTypeName(container, name),
 
   71             _propertyContainerGet(container, name, returnStyle=ReturnStyle.AUTO)))
 
   76     """Get the state of a PropertyList in a form that can be pickled. 
   80     container : `PropertyList` 
   81         The property container. 
   82     asLists : `bool`, optional 
   83         If False, the default, `tuple` will be used for the contents. If true 
   84         a `list` will be used. 
   88     state : `list` of `tuple` or `list` of `list` 
   89         The state, as a list of tuples (or lists), each of which contains 
   90         the following 4 items: 
   94         elementTypeName (a `str`): 
   95             the suffix of a ``setX`` method name 
   96             which is appropriate for the data type. For example integer 
   97             data has ``elementTypeName="Int"` which corresponds to 
   98             the ``setInt`` method. 
  100             the data for the item, in a form compatible 
  101             with the set method named by ``elementTypeName`` 
  102         comment (a `str`): the comment. This item is only present 
  103             if ``container`` is a PropertyList. 
  105     sequence = list 
if asLists 
else tuple
 
  106     return [sequence((name, _propertyContainerElementTypeName(container, name),
 
  107             _propertyContainerGet(container, name, returnStyle=ReturnStyle.AUTO),
 
  108             container.getComment(name)))
 
  109             for name 
in container.getOrderedNames()]
 
  113     """Restore the state of a PropertySet, in place. 
  117     container : `PropertySet` 
  118         The property container whose state is to be restored. 
  119         It should be empty to start with and is updated in place. 
  121         The state, as returned by `getPropertySetState` 
  123     for name, elemType, value 
in state:
 
  124         if elemType 
is not None:
 
  125             getattr(container, 
"set" + elemType)(name, value)
 
  127             raise ValueError(f
"Unrecognized values for state restoration: ({name}, {elemType}, {value})")
 
  131     """Restore the state of a PropertyList, in place. 
  135     container : `PropertyList` 
  136         The property container whose state is to be restored. 
  137         It should be empty to start with and is updated in place. 
  139         The state, as returned by ``getPropertyListState`` 
  141     for name, elemType, value, comment 
in state:
 
  142         getattr(container, 
"set" + elemType)(name, value, comment)
 
  151 def _propertyContainerElementTypeName(container, name):
 
  152     """Return name of the type of a particular element 
  156     container : `lsst.daf.base.PropertySet` or `lsst.daf.base.PropertyList` 
  157         Container including the element 
  162         t = container.typeOf(name)
 
  163     except LookupError 
as e:
 
  166         raise KeyError(str(e))
 
  167     for checkType 
in (
"Bool", 
"Short", 
"Int", 
"Long", 
"LongLong", 
"UnsignedLongLong",
 
  168                       "Float", 
"Double", 
"String", 
"DateTime",
 
  169                       "PropertySet", 
"Undef"):
 
  170         if t == getattr(container, 
"TYPE_" + checkType):
 
  175 def _propertyContainerGet(container, name, returnStyle):
 
  176     """Get a value of unknown type as a scalar or array 
  180     container : `lsst.daf.base.PropertySet` or `lsst.daf.base.PropertyList` 
  181         Container from which to get the value 
  184     returnStyle : `ReturnStyle` 
  185         Control whether numeric or string data is returned as an array 
  186         or scalar (the other types, ``PropertyList``, ``PropertySet`` 
  187             and ``PersistablePtr``, are always returned as a scalar): 
  188         - ReturnStyle.ARRAY: return numeric or string data types 
  189             as an array of values. 
  190         - ReturnStyle.SCALAR: return numeric or string data types 
  191             as a single value; if the item has multiple values then 
  192             return the last value. 
  193         - ReturnStyle.AUTO: (deprecated) return numeric or string data 
  194             as a scalar if there is just one item, or as an array 
  200         Raised if the specified key does not exist in the container. 
  202         Raised if the value retrieved is of an unexpected type. 
  204         Raised if the value for ``returnStyle`` is not correct. 
  206     if not container.exists(name):
 
  207         raise KeyError(name + 
" not found")
 
  208     if returnStyle 
not in ReturnStyle:
 
  209         raise ValueError(
"returnStyle {} must be a ReturnStyle".
format(returnStyle))
 
  211     elemType = _propertyContainerElementTypeName(container, name)
 
  212     if elemType 
and elemType != 
"PropertySet":
 
  213         value = getattr(container, 
"getArray" + elemType)(name)
 
  214         if returnStyle == ReturnStyle.ARRAY 
or (returnStyle == ReturnStyle.AUTO 
and len(value) > 1):
 
  218     if container.isPropertySetPtr(name):
 
  220             return container.getAsPropertyListPtr(name)
 
  222             return container.getAsPropertySetPtr(name)
 
  224         return container.getAsPersistablePtr(name)
 
  227     raise TypeError(
'Unknown PropertySet value type for ' + name)
 
  231     """Make input iterable. 
  233     Takes whatever is given to it and yields it back one element at a time. 
  234     If it is not an iterable or it is a string or PropertySet/List, 
  237     if isinstance(a, (str, PropertyList, PropertySet)):
 
  246 def _guessIntegerType(container, name, value):
 
  247     """Given an existing container and name, determine the type 
  248     that should be used for the supplied value. The supplied value 
  249     is assumed to be a scalar. 
  251     On Python 3 all ints are LongLong but we need to be able to store them 
  252     in Int containers if that is what is being used (testing for truncation). 
  253     Int is assumed to mean 32bit integer (2147483647 to -2147483648). 
  255     If there is no pre-existing value we have to decide what to do. For now 
  256     we pick Int if the value is less than maxsize. 
  260     container : `lsst.daf.base.PropertySet` or `lsst.daf.base.PropertyList` 
  261         Container from which to get the value 
  267         Value to be assigned a type. Can be an iterable. 
  271     useType : `str` or none 
  272         Type to use for the supplied value. `None` if the input is 
  273         `bool` or a non-integral value. 
  277     maxLongLong = 2**63 - 1
 
  286     for v 
in _iterable(value):
 
  288         if not isinstance(v, numbers.Integral) 
or isinstance(v, bool):
 
  300     if min 
is None or max 
is None:
 
  301         raise RuntimeError(f
"Internal logic failure calculating integer range of {value}")
 
  303     def _choose_int_from_range(int_value, current_type):
 
  306         if current_type 
not in {
"Int", 
"LongLong", 
"UnsignedLongLong"}:
 
  309         if int_value <= maxInt 
and int_value >= minInt 
and current_type 
in (
None, 
"Int"):
 
  313         elif int_value >= minLongLong 
and int_value < 0:
 
  316             use_type = 
"LongLong" 
  317         elif int_value >= 0 
and int_value <= maxLongLong 
and current_type 
in (
None, 
"Int", 
"LongLong"):
 
  319             use_type = 
"LongLong" 
  320         elif int_value <= maxU64 
and int_value >= minU64:
 
  321             use_type = 
"UnsignedLongLong" 
  323             raise RuntimeError(
"Unable to guess integer type for storing out of " 
  324                                f
"range value: {int_value}")
 
  328         containerType = _propertyContainerElementTypeName(container, name)
 
  332     useTypeMin = _choose_int_from_range(min, containerType)
 
  333     useTypeMax = _choose_int_from_range(max, containerType)
 
  335     if useTypeMin == useTypeMax:
 
  343     choices = {useTypeMin, useTypeMax}
 
  344     if choices == {
"Int", 
"LongLong"}:
 
  350     if "UnsignedLongLong" in choices:
 
  351         return "UnsignedLongLong" 
  353     raise RuntimeError(f
"Logic error in guessing integer type from {min} and {max}")
 
  356 def _propertyContainerSet(container, name, value, typeMenu, *args):
 
  357     """Set a single Python value of unknown type 
  360         exemplar = 
next(_iterable(value))
 
  361     except StopIteration:
 
  366     setType = _guessIntegerType(container, name, value)
 
  368     if setType 
is not None or t 
in typeMenu:
 
  370             setType = typeMenu[t]
 
  371         return getattr(container, 
"set" + setType)(name, value, *args)
 
  373     for checkType 
in typeMenu:
 
  374         if (checkType 
is None and exemplar 
is None) 
or \
 
  375                 (checkType 
is not None and isinstance(exemplar, checkType)):
 
  376             return getattr(container, 
"set" + typeMenu[checkType])(name, value, *args)
 
  377     raise TypeError(
"Unknown value type for key '%s': %s" % (name, t))
 
  380 def _propertyContainerAdd(container, name, value, typeMenu, *args):
 
  381     """Add a single Python value of unknown type 
  384         exemplar = 
next(_iterable(value))
 
  385     except StopIteration:
 
  390     addType = _guessIntegerType(container, name, exemplar)
 
  392     if addType 
is not None or t 
in typeMenu:
 
  394             addType = typeMenu[t]
 
  395         return getattr(container, 
"add" + addType)(name, value, *args)
 
  397     for checkType 
in typeMenu:
 
  398         if (checkType 
is None and exemplar 
is None) 
or \
 
  399                 (checkType 
is not None and isinstance(exemplar, checkType)):
 
  400             return getattr(container, 
"add" + typeMenu[checkType])(name, value, *args)
 
  401     raise TypeError(
"Unknown value type for key '%s': %s" % (name, t))
 
  404 def _makePropertySet(state):
 
  405     """Make a `PropertySet` from the state returned by `getPropertySetState` 
  410         The data returned by `getPropertySetState`. 
  417 def _makePropertyList(state):
 
  418     """Make a `PropertyList` from the state returned by 
  419     `getPropertyListState` 
  424         The data returned by `getPropertySetState`. 
  435     _typeMenu = {bool: 
"Bool",
 
  438                  DateTime: 
"DateTime",
 
  439                  PropertySet: 
"PropertySet",
 
  440                  PropertyList: 
"PropertySet",
 
  444     def get(self, name, default=None):
 
  445         """Return an item as a scalar, else default. 
  447         Identical to `getScalar` except that a default value is returned 
  448         if the requested key is not present.  If an array item is requested 
  449         the final value in the array will be returned. 
  455         default : `object`, optional 
  456             Default value to use if the named item is not present. 
  460         value : any type supported by container 
  461             Single value of any type supported by the container, else the 
  462             default value if the requested item is not present in the 
  463             container.  For array items the most recently added value is 
  467             return _propertyContainerGet(self, name, returnStyle=ReturnStyle.SCALAR)
 
  472         """Return an item as an array if the item is numeric or string 
  474         If the item is a `PropertySet`, `PropertyList` or 
  475         `lsst.daf.base.PersistablePtr` then return the item as a scalar. 
  484         values : `list` of any type supported by container 
  485             The contents of the item, guaranteed to be returned as a `list.` 
  490             Raised if the item does not exist. 
  492         return _propertyContainerGet(self, name, returnStyle=ReturnStyle.ARRAY)
 
  495         """Return an item as a scalar 
  497         If the item has more than one value then the last value is returned. 
  507             Value stored in the item.  If the item refers to an array the 
  508             most recently added value is returned. 
  513             Raised if the item does not exist. 
  515         return _propertyContainerGet(self, name, returnStyle=ReturnStyle.SCALAR)
 
  517     def set(self, name, value):
 
  518         """Set the value of an item 
  520         If the item already exists it is silently replaced; the types 
  527         value : any supported type 
  528             Value of item; may be a scalar or array 
  530         return _propertyContainerSet(self, name, value, self.
_typeMenu_typeMenu)
 
  532     def add(self, name, value):
 
  533         """Append one or more values to a given item, which need not exist 
  535         If the item exists then the new value(s) are appended; 
  536         otherwise it is like calling `set` 
  542         value : any supported type 
  543             Value of item; may be a scalar or array 
  547         If ``value`` is an `lsst.daf.base.PropertySet` or 
  548         `lsst.daf.base.PropertyList` then ``value`` replaces 
  549         the existing value. Also the item is added as a live 
  550         reference, so updating ``value`` will update this container 
  555         lsst::pex::exceptions::TypeError 
  556             Raised if the type of `value` is incompatible with the existing 
  559         return _propertyContainerAdd(self, name, value, self.
_typeMenu_typeMenu)
 
  562         """Update the current container with the supplied additions. 
  566         addition : `collections.abc.Mapping` or `PropertySet` 
  567             The content to merge into the current container. 
  571         This is not the same as calling `PropertySet.combine` since the 
  572         behavior differs when both mappings contain the same key.  This 
  573         method updates by overwriting existing values completely with 
  576         if isinstance(addition, PropertySet):
 
  580                 self.copy(k, addition, k)
 
  582             for k, v 
in addition.items():
 
  586         """Returns a (possibly nested) dictionary with all properties. 
  591             Dictionary with all names and values (no comments). 
  595         for name 
in self.names():
 
  596             v = _propertyContainerGet(self, name, returnStyle=ReturnStyle.AUTO)
 
  598             if isinstance(v, PropertySet):
 
  599                 d[name] = PropertySet.toDict(v)
 
  606             return NotImplemented
 
  608         if len(self) != len(other):
 
  612             if _propertyContainerGet(self, name, returnStyle=ReturnStyle.AUTO) != \
 
  613                     _propertyContainerGet(other, name, returnStyle=ReturnStyle.AUTO):
 
  615             if self.typeOf(name) != other.typeOf(name):
 
  623         for itemName 
in self:
 
  624             ps.copy(itemName, self, itemName)
 
  628         result = self.deepCopy()
 
  629         memo[
id(self)] = result
 
  633         """Determines if the name is found at the top level hierarchy 
  638         Does not use `PropertySet.exists()`` because that includes support 
  639         for "."-delimited names.  This method is consistent with the 
  640         items returned from ``__iter__``. 
  642         return name 
in self.names(topLevelOnly=
True)
 
  645         """Assigns the supplied value to the container. 
  650             Name of item to update. 
  651         value : Value to assign 
  652             Can be any value supported by the container's ``set()`` 
  653             method. `~collections.abc.Mapping` are converted to 
  654             `PropertySet` before assignment. 
  658         Uses `PropertySet.set`, overwriting any previous value. 
  660         if isinstance(value, Mapping):
 
  663             for k, v 
in value.items():
 
  666         self.
setset(name, value)
 
  669         """Returns a scalar item from the container. 
  673         Uses `PropertySet.getScalar` to guarantee that a single value 
  682             raise KeyError(f
"{name} not present in dict")
 
  685         return self.toString()
 
  688         return self.nameCount(topLevelOnly=
True)
 
  691         for n 
in self.names(topLevelOnly=
True):
 
  695         return KeysView(self)
 
  698         return ItemsView(self)
 
  701         return ValuesView(self)
 
  703     def pop(self, name, default=None):
 
  704         """Remove the named key and return its value. 
  709             Name of the key to remove. 
  710         default : Any, optional 
  711             Value to return if the key is not present. 
  716             The value of the item as would be returned using `getScalar()`. 
  721             Raised if no default is given and the key is missing. 
  744     _typeMenu = {bool: 
"Bool",
 
  748                  DateTime: 
"DateTime",
 
  749                  PropertySet: 
"PropertySet",
 
  750                  PropertyList: 
"PropertySet",
 
  754     COMMENTSUFFIX = 
"#COMMENT" 
  755     """Special suffix used to indicate that a named item being assigned 
  756     using dict syntax is referring to a comment, not value.""" 
  758     def get(self, name, default=None):
 
  759         """Return an item as a scalar, else default. 
  761         Identical to `getScalar` except that a default value is returned 
  762         if the requested key is not present.  If an array item is requested 
  763         the final value in the array will be returned. 
  769         default : `object`, optional 
  770             Default value to use if the named item is not present. 
  774         value : any type supported by container 
  775             Single value of any type supported by the container, else the 
  776             default value if the requested item is not present in the 
  777             container.  For array items the most recently added value is 
  781             return _propertyContainerGet(self, name, returnStyle=ReturnStyle.SCALAR)
 
  786         """Return an item as a list. 
  795         values : `list` of values 
  796             The contents of the item, guaranteed to be returned as a `list.` 
  801             Raised if the item does not exist. 
  803         return _propertyContainerGet(self, name, returnStyle=ReturnStyle.ARRAY)
 
  806         """Return an item as a scalar 
  808         If the item has more than one value then the last value is returned. 
  818             Value stored in the item.  If the item refers to an array the 
  819             most recently added value is returned. 
  824             Raised if the item does not exist. 
  826         return _propertyContainerGet(self, name, returnStyle=ReturnStyle.SCALAR)
 
  828     def set(self, name, value, comment=None):
 
  829         """Set the value of an item 
  831         If the item already exists it is silently replaced; the types 
  838         value : any supported type 
  839             Value of item; may be a scalar or array 
  842         if comment 
is not None:
 
  844         return _propertyContainerSet(self, name, value, self.
_typeMenu_typeMenu, *args)
 
  846     def add(self, name, value, comment=None):
 
  847         """Append one or more values to a given item, which need not exist 
  849         If the item exists then the new value(s) are appended; 
  850         otherwise it is like calling `set` 
  856         value : any supported type 
  857             Value of item; may be a scalar or array 
  861         If `value` is an `lsst.daf.base.PropertySet` items are added 
  862         using dotted names (e.g. if name="a" and value contains 
  863         an item "b" which is another PropertySet and contains an 
  864         item "c" which is numeric or string, then the value of "c" 
  865         is added as "a.b.c", appended to the existing values of 
  866         "a.b.c" if any (in which case the types must be compatible). 
  870         lsst::pex::exceptions::TypeError 
  871             Raise if the type of ``value`` is incompatible with the existing 
  875         if comment 
is not None:
 
  877         return _propertyContainerAdd(self, name, value, self.
_typeMenu_typeMenu, *args)
 
  880         """Set the comment for an existing entry. 
  885             Name of the key to receive updated comment. 
  891         containerType = _propertyContainerElementTypeName(self, name)
 
  892         if self.isArray(name):
 
  896         getattr(self, f
"set{containerType}")(name, value, comment)
 
  899         """Return a list of tuples of name, value, comment for each property 
  900         in the order that they were inserted. 
  904         ret : `list` of `tuple` 
  905             Tuples of name, value, comment for each property in the order 
  906             in which they were inserted. 
  908         orderedNames = self.getOrderedNames()
 
  910         for name 
in orderedNames:
 
  911             if self.isArray(name):
 
  912                 values = _propertyContainerGet(self, name, returnStyle=ReturnStyle.AUTO)
 
  914                     ret.append((name, v, self.getComment(name)))
 
  916                 ret.append((name, _propertyContainerGet(self, name, returnStyle=ReturnStyle.AUTO),
 
  917                             self.getComment(name)))
 
  921         """Return an ordered dictionary with all properties in the order that 
  927             Ordered dictionary with all properties in the order that they 
  928             were inserted. Comments are not included. 
  932         As of Python 3.6 dicts retain their insertion order. 
  936             d[name] = _propertyContainerGet(self, name, returnStyle=ReturnStyle.AUTO)
 
  940     toDict = toOrderedDict
 
  946         if not PropertySet.__eq__(self, other):
 
  950             if self.getComment(name) != other.getComment(name):
 
  958         for itemName 
in self:
 
  959             pl.copy(itemName, self, itemName)
 
  963         result = self.deepCopy()
 
  964         memo[
id(self)] = result
 
  968         for n 
in self.getOrderedNames():
 
  972         """Assigns the supplied value to the container. 
  977             Name of item to update. If the name ends with 
  978             `PropertyList.COMMENTSUFFIX`, the comment is updated rather 
  980         value : Value to assign 
  981             Can be any value supported by the container's ``set()`` 
  982             method. `~collections.abc.Mapping` are converted to 
  983             `PropertySet` before assignment. 
  987         Uses `PropertySet.set`, overwriting any previous value. 
  993         if isinstance(value, Mapping):
 
  996             for k, v 
in value.items():
 
  999         self.
setset(name, value)
 
def __deepcopy__(self, memo)
 
def set(self, name, value, comment=None)
 
def setComment(self, name, comment)
 
def get(self, name, default=None)
 
def __setitem__(self, name, value)
 
def add(self, name, value, comment=None)
 
def getScalar(self, name)
 
def __deepcopy__(self, memo)
 
def add(self, name, value)
 
def __contains__(self, name)
 
def __setitem__(self, name, value)
 
def get(self, name, default=None)
 
def __getitem__(self, name)
 
def pop(self, name, default=None)
 
def getScalar(self, name)
 
def __delitem__(self, name)
 
def update(self, addition)
 
def set(self, name, value)
 
def setPropertyListState(container, state)
 
def setPropertySetState(container, state)
 
def getPropertyListState(container, asLists=False)
 
def getPropertySetState(container, asLists=False)
 
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)