Module tenlib.struct.proxy

Functions

def wrap_object(obj)

Converts an object into a proxy item. dicts are converted to a TenDict, lists to a TenList.

Classes

class TenDict (*args, **kwargs)

Proxy for dict that allows you to access items as properties recursively and provides other helpers.

Examples

Items can be accessed as attributes:

>>> some = TenDict({'a': 'b', 'c', 'd'})
>>> some.a
'b'
>>> some.c = 'e'
>>> some.c
'e'

This property is recursive:

>>> deep = TenDict({
...     'some_list': [
...         {'some_dict': {
...             'a_value': 3
...         }}
...     ]
... })
>>> deep.some_list[0].some_dict.a_value
3

Helpers are available:

>>> some = TenDict({'key1': 'value1', 'key2': 'value2'})
>>> some.setdefaults({'key2': 'value2_new', 'key3': 'value3'})
TenDict({'key1': 'value1', 'key2': 'value2', 'key3': 'value3'})
>>> some.keep('key1', 'key3')
TenDict({'key1': 'value1', 'key3': 'value3'})

The instance is a proxy, modifying the TenDict instance modifies the original dict as well.

>>> some_dict = {'a': 'b', 'c': 'd'}
>>> proxy = TenDict(some_dict)
>>> proxy['e'] = 'f'
>>> proxy
TenDict({'a': 3, 'c': 'd', 'e': 'f'})
>>> some_dict
{'a': 3, 'c': 'd', 'e': 'f'}
Expand source code
class TenDict(GetItemProxy, UserDict):
    """Proxy for `dict` that allows you to access items as properties
    recursively and provides other helpers.

    Examples:

        Items can be accessed as attributes:

        >>> some = TenDict({'a': 'b', 'c', 'd'})
        >>> some.a
        'b'
        >>> some.c = 'e'
        >>> some.c
        'e'

        This property is recursive:

        >>> deep = TenDict({
        ...     'some_list': [
        ...         {'some_dict': {
        ...             'a_value': 3
        ...         }}
        ...     ]
        ... })
        >>> deep.some_list[0].some_dict.a_value
        3

        Helpers are available:

        >>> some = TenDict({'key1': 'value1', 'key2': 'value2'})
        >>> some.setdefaults({'key2': 'value2_new', 'key3': 'value3'})
        TenDict({'key1': 'value1', 'key2': 'value2', 'key3': 'value3'})
        >>> some.keep('key1', 'key3')
        TenDict({'key1': 'value1', 'key3': 'value3'})

        The instance is a proxy, modifying the `TenDict` instance modifies the
        original `dict` as well.

        >>> some_dict = {'a': 'b', 'c': 'd'}
        >>> proxy = TenDict(some_dict)
        >>> proxy['e'] = 'f'
        >>> proxy
        TenDict({'a': 3, 'c': 'd', 'e': 'f'})
        >>> some_dict
        {'a': 3, 'c': 'd', 'e': 'f'}
    """

    __annotations_cache__ = {}

    def __getattr__(self, name):
        # This means that the expected attribute is annotated but not defined
        if name in self._defined_annotations():
            raise AttributeError(name)
        try:
            return self[name]
        except KeyError:
            raise AttributeError(name) from None

    @classmethod
    def _defined_annotations(cls):
        """Returns a set containing every annotation of the base class and its
        superclasses.
        """
        try:
            return cls.__annotations_cache__[cls]
        except KeyError:
            pass

        cache = cls.__annotations_cache__[cls] = set()

        for scls in cls.__mro__:
            try:
                cache |= set(scls.__annotations__.keys())
            except AttributeError:
                pass

        return cache

    def __setattr__(self, name, value):
        if name in self._defined_annotations() or name in dir(self):
            super().__setattr__(name, value)
        else:
            self[name] = value

    def __delattr__(self, name):
        if name in self._defined_annotations() or name in dir(self):
            return super().__delattr__(name)

        try:
            del self[name]
        except KeyError:
            raise AttributeError(name) from None

    def __repr__(self):
        return f"{type(self).__name__}({self.__wo__!r})"

    def update(self, *args, **kwargs) -> TenDict:
        """Same as `dict.update()`, but returns the instance."""
        self.__wo__.update(*args, **kwargs)
        return self

    def setdefaults(self, other={}, **kwargs) -> TenDict:
        """Generalizes `dict.setdefault()` for several values, and returns the
        instance.

        >>> some = TenDict({'key1': 'value1', 'key2': 'value2'})
        >>> some.setdefaults({'key2': 'value2_new', 'key3': 'value3'})
        TenDict({'key1': 'value1', 'key2': 'value2', 'key3': 'value3'})
        """
        kwargs.update(other)
        for k, v in kwargs.items():
            self.setdefault(k, v)
        return self

    def keep(self, *to_keep) -> TenDict:
        """Returns a `TenDict` that contains only the given keys.

        >>> some = TenDict({'a': 1, 'b': 2, 'c': 3, 'd': 4})
        >>> some.keep('a', 'd')
        TenDict({'a': 1, 'd': 4})
        """
        new = TenDict()

        for k in to_keep:
            try:
                new[k] = self[k]
            except KeyError:
                pass

        return new

Ancestors

  • tenlib.struct.proxy.GetItemProxy
  • tenlib.struct.proxy.UserDict
  • collections.abc.MutableMapping
  • collections.abc.Mapping
  • collections.abc.Collection
  • collections.abc.Sized
  • collections.abc.Iterable
  • collections.abc.Container

Subclasses

Methods

def update(self, *args, **kwargs) ‑> TenDict

Same as dict.update(), but returns the instance.

def setdefaults(self, other={}, **kwargs) ‑> TenDict

Generalizes dict.setdefault() for several values, and returns the instance.

>>> some = TenDict({'key1': 'value1', 'key2': 'value2'})
>>> some.setdefaults({'key2': 'value2_new', 'key3': 'value3'})
TenDict({'key1': 'value1', 'key2': 'value2', 'key3': 'value3'})
def keep(self, *to_keep) ‑> TenDict

Returns a TenDict that contains only the given keys.

>>> some = TenDict({'a': 1, 'b': 2, 'c': 3, 'd': 4})
>>> some.keep('a', 'd')
TenDict({'a': 1, 'd': 4})
class TenList (lst=None)

A proxy class that converts sequences and dicts to their proxified equivalent, to access items as properties recursively.

Expand source code
class TenList(GetItemProxy, UserList):
    def __init__(self, lst=None):
        if lst is None:
            self.data = []
        elif isinstance(lst, list):
            self.data = lst
        else:
            self.data = list(lst)

    def __repr__(self):
        return f"{type(self).__name__}({self.data!r})"

Ancestors

  • tenlib.struct.proxy.GetItemProxy
  • collections.UserList
  • collections.abc.MutableSequence
  • collections.abc.Sequence
  • collections.abc.Reversible
  • collections.abc.Collection
  • collections.abc.Sized
  • collections.abc.Iterable
  • collections.abc.Container

Subclasses

  • tenlib.struct.xmldict.XMLList