Source code for pypey.dyct

"""
Pipeable versions of ``dict``, ``collections.defaultdict`` and ``collections.Counter``
"""
from __future__ import annotations

from collections import Counter, defaultdict, UserDict
from typing import TypeVar, Iterable, Tuple, Generic, Optional, Union, Set

from pypey.func import Y, Fn
from pypey.pype import Pype

K = TypeVar('K')
V = TypeVar('V')


[docs]class Dyct(Generic[K, V], UserDict): """ A pipeable version of ``dict`` containing a superset of its methods """ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs)
[docs] def set(self, key: K, value: V) -> Dyct[K, V]: """ sets given key to given value :param key: key to add/overwrite :param value: value to (re-)set :return: this ``Dyct`` """ self[key] = value return self
[docs] def pype(self) -> Pype[Tuple[K, V]]: """ Return this ``Dyct``-'s items as a ``Pype`` :return: ``Pype`` containing pairs of key, values """ return Pype(self.items())
[docs] def reverse(self, overwrite: bool = True) -> Dyct[V, Union[K, Set[K]]]: """ Reverses keys and values in this ``Dyct``. To prevent keys mapping to equal values from being lost, set ``overwrite`` to ``False`` and they will be kept in a ``Set``. :param overwrite: ``True`` if keys should be overwritten ``False`` if they should be preserved in a ``Set``. :return: a new ``Dyct`` with keys for values and values for keys """ if not overwrite: value_to_keys = defaultdict(set) for key, value in self.items(): value_to_keys[value].add(key) return Dyct(value_to_keys) return Dyct({value: key for key, value in self.items()})
[docs]class DefDyct(Generic[K, V], defaultdict): """ A pipeable version of ``collections.defaultdict`` containing a superset of its methods """ def __init__(self: DefDyct[K, V], default_factory: Optional[Fn[..., Y]], fn: Optional[Fn[[V, V], Y]] = None, *args, **kwargs): super().__init__(default_factory, *args, **kwargs) self.fn = fn
[docs] def add(self: DefDyct[K, V], key: K, value: V) -> DefDyct[K, V]: """ Updates value associated with given key with given value, using ``fn`` passed in in constructor If ``fn`` is None, then inplace addition will be used. :param key: key to add :param value: value to add :return: this ``DefDyct`` """ if self.fn is None: self[key] += value else: self.fn(self[key], value) return self
[docs] def pype(self: DefDyct[K, V]) -> Pype[Tuple[K, V]]: """ Return this ``DefDyct``-'s items as a ``Pype`` :return: ``Pype`` containing pairs of key, values """ return Pype(self.items())
[docs]class CountDyct(Generic[K], Counter): """ A pipeable version of ``collections.Counter`` containing a superset of its methods """ def __init__(self: CountDyct[K], counts: Iterable[K] = ()): super().__init__(counts)
[docs] def inc(self: CountDyct[K], item: K, count: int = 1) -> CountDyct[K]: """ Increments counts of ``item`` by ``count``. :param item: item to be incremented :param count: increment :return: this ``CountDyct`` """ self[item] += count return self
[docs] def pype(self: CountDyct[K]) -> Pype[Tuple[K, int]]: """ Return this ``CountDyct``-'s items as a ``Pype`` :return: ``Pype`` containing pairs of key, count """ return Pype(item for item in self.items())