@@ -802,41 +802,24 @@ def _is_single_item(testee):
802802
803803class CubeAttrsDict (MutableMapping ):
804804 """
805- A dict-like object for Cube :attr:`~ iris.cube.Cube.attributes`, which provides unified user access to
806- the combined cube `` local`` and `` global`` attributes, mimicking the behaviour of a
807- simple dict .
805+ A :class:` dict` \\ -like object for :attr:`iris.cube.Cube.attributes`,
806+ providing unified user access to combined cube " local" and " global" attributes
807+ dictionaries, with the access behaviour of an ordinary (single) dictionary .
808808
809- This supports all the regular methods of a :class:`dict`.
810- However, a few things such as the detailed print (repr) are different.
809+ Properties :attr:`globals` and :attr:`locals` are regular
810+ :class:`~iris.common.mixin.LimitedAttributeDict`\\ s, which can be accessed and
811+ modified separately. The :class:`CubeAttrsDict` itself contains *no* additional
812+ state, but simply provides a 'combined' view of both global + local attributes.
811813
812- In addition, the 'locals' and 'globals' properties provide specific access to local
813- and global attributes, as regular
814- :class:`~iris.common.mixin.LimitedAttributeDict` \\ s .
814+ All the read- and write-type methods, such as ``get()``, ``update()``, ``values()``,
815+ behave according to the logic documented for : :meth:`__getitem__`,
816+ :meth:`__setitem__` and :meth:`__iter__` .
815817
816818 Notes
817819 -----
818820 For type testing, ``issubclass(CubeAttrsDict, Mapping)`` is ``True``, but
819821 ``issubclass(CubeAttrsDict, dict)`` is ``False``.
820822
821- Properties 'locals' and 'globals' are the two sets of cube attributes. These are
822- both :class:`~iris.common.mixin.LimitedAttributeDict` . The CubeAttrsDict object
823- contains *no* additional state of its own, but simply acts as a view on these two.
824-
825- When reading (__getitem__, pop, popitem, keys, values etc), it contains all the
826- keys + values of both 'locals' and 'globals'. When a key occurs in *both* 'locals'
827- and 'globals', the result is the local value.
828- See :meth:`~iris.cube.CubeAttrsDict.__getitem__` .
829-
830- When writing (__setitem__, setdefault, update, etc) to a key already present, the
831- existing entry in either 'locals' or 'globals' is updated. If both are present,
832- 'locals' is updated. See :meth:`~iris.cube.CubeAttrsDict.__setitem__` .
833-
834- When writing to a new key, this generally updates 'locals'. However, certain
835- specific names would never normally be 'data' attributes, and these are created as
836- 'globals' instead. These are listed in Appendix A of the
837- `CF Conventions: <https://cfconventions.org/>`_ .
838- At present, these are : 'conventions', 'featureType', 'history', 'title'.
839-
840823 Examples
841824 --------
842825
@@ -869,12 +852,12 @@ def __init__(
869852 """
870853 Create a cube attributes dictionary.
871854
872- Unlike the attributes of other :class:`~iris.common.mixin.CFVariableMixin`
873- subclasses, this is a "split" dictionary - i.e. it contains separate global +
874- local settings.
875-
876- We support initialisation from a generic dictionary (using default global/local
877- name identification rules), or from specific local and global ones .
855+ We support initialisation from a single generic mapping input, using the default
856+ global/local assignment rules explained at :meth:`__setatrr__`, or from
857+ two separate mappings. Two separate dicts can be passed in the ``locals``
858+ and ``globals`` args, **or** via a ``combined`` arg which has its own
859+ ``.globals`` and ``.locals`` properties -- so this allows passing an existing
860+ :class:`CubeAttrsDict`, which will be copied .
878861
879862 Parameters
880863 ----------
@@ -898,15 +881,17 @@ def __init__(
898881 >>> CubeAttrsDict({'history': 'data-story', 'comment': 'this-cube'})
899882 CubeAttrsDict(globals={'history': 'data-story'}, locals={'comment': 'this-cube'})
900883
901- >>> CubeAttrsDict({'history': 'data-story', 'comment': 'this cube'}).globals
902- {'history': 'data-story'}
903-
904884 >>> CubeAttrsDict(locals={'history': 'local-history'})
905885 CubeAttrsDict(globals={}, locals={'history': 'local-history'})
906886
907887 >>> CubeAttrsDict(globals={'x': 'global'}, locals={'x': 'local'})
908888 CubeAttrsDict(globals={'x': 'global'}, locals={'x': 'local'})
909889
890+ >>> x1 = CubeAttrsDict(globals={'x': 1}, locals={'y': 2})
891+ >>> x2 = CubeAttrsDict(x1)
892+ >>> x2
893+ CubeAttrsDict(globals={'x': 1}, locals={'y': 2})
894+
910895 """
911896 # First initialise locals + globals, defaulting to empty.
912897 self .locals = locals
@@ -1000,7 +985,12 @@ def copy(self):
1000985 #
1001986
1002987 def __iter__ (self ):
1003- # Ordering: all global keys, then all local ones, but omitting duplicates.
988+ """
989+ Define the combined iteration order.
990+
991+ Result is: all global keys, then all local ones, but omitting duplicates.
992+
993+ """
1004994 # NOTE: this means that in the "summary" view, attributes present in both
1005995 # locals+globals are listed first, amongst the globals, even though they appear
1006996 # with the *value* from locals.
@@ -1032,15 +1022,20 @@ def __setitem__(self, key, value):
10321022 """
10331023 Assign an attribute value.
10341024
1035- If there is *no* existing attribute of this name, then one is created, either
1036- local or global, depending on whether the name is in the known set of "normally
1037- global" attribute names defined by CF. See :class:`~iris.cube.CubeAttrsDict`.
1025+ This may be assigned in either ``self.locals`` or ``self.globals``, chosen as
1026+ follows:
1027+
1028+ * If there is an existing setting in either ``.locals`` or ``.globals``, then
1029+ that is updated (i.e. overwritten).
10381030
1039- If there is an *existing* attribute of this name in either ``self.locals`` or
1040- ``self.globals``, then that one is updated (i.e. overwritten) .
1031+ * If it is present in *both*, only
1032+ ``.locals`` is updated.
10411033
1042- If the name is present in *both* locals and globals, then only the local one is
1043- updated.
1034+ * If there is *no* existing attribute, it is usually created in ``.locals``.
1035+ **However** a handful of "known normally global" cases, as defined by CF,
1036+ go into ``.globals`` instead.
1037+ At present these are : ('conventions', 'featureType', 'history', 'title').
1038+ See `CF Conventions, Appendix A: <http://cfconventions.org/Data/cf-conventions/cf-conventions-1.10/cf-conventions.html#attribute-appendix>`_ .
10441039
10451040 """
10461041 # If an attribute of this name is already present, update that
@@ -1278,8 +1273,8 @@ def __init__(
12781273
12791274 self .cell_methods = cell_methods
12801275
1281- #: A dictionary, with a few restricted keys, for arbitrary
1282- #: Cube metadata .
1276+ #: A dictionary for arbitrary Cube metadata.
1277+ #: A few keys are restricted - see :class:`CubeAttrsDict` .
12831278 self .attributes = attributes
12841279
12851280 # Coords
0 commit comments