Source code for toolbox.collections.mapping

from typing import Any, Optional

from .item import Item, ItemType


[docs] class BaseDict(dict): """Dictionary with pretty :py:func:`__repr__` output. Base class that all other dictionaries in this file inherit from. :py:func:`__repr__` is replaced with ``<{class_name} {dictionary data}>`` output style for implicit inferences. Example: .. code-block:: python from toolbox.collections.mapping import BaseDict class NewDict(BaseDict): '''New dictionary example.''' d = NewDict({"hello": "world"}) print(d) # >>> <NewDict {'hello': 'world'}> """ def __repr__(self): return "<{} {}>".format( self.__class__.__name__, super(BaseDict, self).__repr__(), )
[docs] class BidirectionalDict(BaseDict): """Dictionary with two-way capabilities. Example: .. code-block:: python from toolbox.collections.mapping import BidirectionalDict d = BidirectionalDict({"hello": "world"}) print(d) # >>> <BidirectionalDict {'hello': 'world', 'world': 'hello'}> """ def __init__(self, dictionary: Optional[dict] = None, **kwargs) -> dict: dictionary = dictionary or {} super(BidirectionalDict, self).__init__( { **dictionary, **{v: k for k, v in dictionary.items()}, **kwargs, **{v: k for k, v in kwargs.items()}, } ) def __setitem__(self, key: Any, value: Any): super(BidirectionalDict, self).__setitem__(key, value) super(BidirectionalDict, self).__setitem__(value, key) def update(self, dictionary: dict = Optional[dict], **kwargs): dictionary = dictionary or {} super(BidirectionalDict, self).update( { **dictionary, **{v: k for k, v in dictionary.items()}, **kwargs, **{v: k for k, v in kwargs.items()}, } )
[docs] class ObjectDict(BaseDict): """Dictionary that can be accessed and set as though it was an object. Example: .. code-block:: python from toolbox.collections.mapping import ObjectDict d = ObjectDict({"hello": "world"}) print(d) # >>> <ObjectDict {'hello': 'world'}> print(d.hello) # >>> 'world' d.hello = "mundo" print(d.hello) # >>> 'mundo' """ def __getattr__(self, key: Any) -> Any: return self.__getitem__(key) def __setattr__(self, key: str, value: Any): return self.__setitem__(key, value)
[docs] class OverloadedDict(BaseDict): """Dictionary that can be added or subtracted. Example: .. code-block:: python from toolbox.collections.mapping import OverloadedDict d1 = OverloadedDict({"hello": "world"}) d2 = {"ola": "mundo"} d1 += d2 print(d1) # >>> <OverloadedDict {'hello': 'world', 'ola': 'mundo'}> d1 -= d2 print(d1) # >>> <OverloadedDict {'hello': 'world'}> """ def __add__(self, other: dict) -> dict: dct = {**self, **other} return OverloadedDict(dct) def __iadd__(self, other: dict) -> dict: self = self.__add__(other) return self def __sub__(self, other: dict) -> dict: dct = {k: v for k, v in self.items() if (k, v) not in other.items()} return OverloadedDict(dct) def __isub__(self, other: dict) -> dict: self = self.__sub__(other) return self
[docs] class UnderscoreAccessDict(BaseDict): """Dictionary that doesn't distinct keys with empty spaces and underscores. Example: .. code-block:: python from toolbox.collections.mapping import UnderscoreAccessDict d = UnderscoreAccessDict({"hello world": "ola mundo"}) print(d) # >>> <UnderscoreAccessDict {'hello world': 'ola mundo'}> print(d['hello_world']) # >>> 'ola mundo' """ def __getitem__(self, key: Any) -> Any: if isinstance(key, bytes): utw = key.replace(b"_", b" ") wtu = key.replace(b"_", b"") else: utw = key.replace("_", " ") wtu = key.replace("_", "") if utw in self: return super(UnderscoreAccessDict, self).__getitem__(utw) elif wtu in self: return super(UnderscoreAccessDict, self).__getitem__(wtu) return super(UnderscoreAccessDict, self).__getitem__(key)
[docs] class FrozenDict(BaseDict): """Dictionary that is frozen. .. code-block:: python from toolbox.collections.mapping import FrozenDict d = FrozenDict({"hello": "world"}) print(d) # >>> <FrozenDict {'hello': 'world'}> d['ola'] = 'mundo' # >>> KeyError: 'Cannot set key and value because this is a frozen dictionary.' """ def __setitem__(self, key, value): err = "Cannot set key and value because this is a frozen dictionary." raise KeyError(err) def update(self, dictionary: Optional[dict] = None, **kwargs): err = "Cannot set key and value because this is a frozen dictionary." raise KeyError(err)
[docs] class MultiEntryDict(BaseDict): """Dictionary that can have multiple entries for the same key. .. code-block:: python from toolbox.collections.mapping import MultiEntryDict d = MultiEntryDict({"hello": "world", "hello": "mundo"}) print(d) # >>> <MultiEntryDict {'hello': ['world', 'mundo']}> d['hello'] = 'globo' print(d) # >>> <MultiEntryDict {'hello': ['world', 'mundo', 'globo']}> """ def __setitem__(self, key, value): if key in self: if isinstance(self[key], list): self[key].append(value) else: super().__setitem__(key, [self[key], value]) else: super(MultiEntryDict, self).__setitem__(key, value)
[docs] class ItemDict(BaseDict): """Dictionary composed of :py:class:`toolbox.collections.item.Item` key and values. Example: .. code-block:: python from toolbox.collections.mapping import ItemDict d = ItemDict({"100": "one hundred"}) print(d) # >>> <ItemDict {100: one hundred}> print(d["100"] == d[100] == d[b"100"]) # >>> True """ def __init__(self, dictionary: Optional[dict] = None, **kwargs): dictionary = dictionary or {} kwargs = kwargs or {} dictionary = {**dictionary, **kwargs} new = {} for k, v in dictionary.items(): if isinstance(v, list): new[Item(k)] = [Item(i) for i in v] else: new[Item(k)] = Item(v) return super(ItemDict, self).__init__(new) def __getitem__(self, key: ItemType): return super(ItemDict, self).__getitem__(Item(key)) def __setitem__(self, key: ItemType, value: ItemType): if isinstance(value, list): super(ItemDict, self).__setitem__(Item(key), [Item(i) for i in value]) else: super(ItemDict, self).__setitem__(Item(key), Item(value)) def __delitem__(self, key: ItemType): super(ItemDict, self).__delitem__(Item(key)) def __contains__(self, key: ItemType): return super(ItemDict, self).__contains__(Item(key)) def update(self, dictionary: Optional[dict] = None, **kwargs): dictionary = dictionary or {} super(ItemDict, self).update( { **{Item(k): Item(v) for k, v in dictionary.items()}, **{Item(k): Item(v) for k, v in kwargs.items()}, }, )