123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252 |
- from collections import defaultdict as _defaultdict
- from toolz.dicttoolz import (merge, merge_with, valmap, keymap, update_in,
- assoc, dissoc, keyfilter, valfilter, itemmap,
- itemfilter, assoc_in)
- from toolz.utils import raises
- from toolz.compatibility import PY3
- def inc(x):
- return x + 1
- def iseven(i):
- return i % 2 == 0
- class TestDict(object):
- """Test typical usage: dict inputs, no factory keyword.
- Class attributes:
- D: callable that inputs a dict and creates or returns a MutableMapping
- kw: kwargs dict to specify "factory" keyword (if applicable)
- """
- D = dict
- kw = {}
- def test_merge(self):
- D, kw = self.D, self.kw
- assert merge(D({1: 1, 2: 2}), D({3: 4}), **kw) == D({1: 1, 2: 2, 3: 4})
- def test_merge_iterable_arg(self):
- D, kw = self.D, self.kw
- assert merge([D({1: 1, 2: 2}), D({3: 4})], **kw) == D({1: 1, 2: 2, 3: 4})
- def test_merge_with(self):
- D, kw = self.D, self.kw
- dicts = D({1: 1, 2: 2}), D({1: 10, 2: 20})
- assert merge_with(sum, *dicts, **kw) == D({1: 11, 2: 22})
- assert merge_with(tuple, *dicts, **kw) == D({1: (1, 10), 2: (2, 20)})
- dicts = D({1: 1, 2: 2, 3: 3}), D({1: 10, 2: 20})
- assert merge_with(sum, *dicts, **kw) == D({1: 11, 2: 22, 3: 3})
- assert merge_with(tuple, *dicts, **kw) == D({1: (1, 10), 2: (2, 20), 3: (3,)})
- assert not merge_with(sum)
- def test_merge_with_iterable_arg(self):
- D, kw = self.D, self.kw
- dicts = D({1: 1, 2: 2}), D({1: 10, 2: 20})
- assert merge_with(sum, *dicts, **kw) == D({1: 11, 2: 22})
- assert merge_with(sum, dicts, **kw) == D({1: 11, 2: 22})
- assert merge_with(sum, iter(dicts), **kw) == D({1: 11, 2: 22})
- def test_valmap(self):
- D, kw = self.D, self.kw
- assert valmap(inc, D({1: 1, 2: 2}), **kw) == D({1: 2, 2: 3})
- def test_keymap(self):
- D, kw = self.D, self.kw
- assert keymap(inc, D({1: 1, 2: 2}), **kw) == D({2: 1, 3: 2})
- def test_itemmap(self):
- D, kw = self.D, self.kw
- assert itemmap(reversed, D({1: 2, 2: 4}), **kw) == D({2: 1, 4: 2})
- def test_valfilter(self):
- D, kw = self.D, self.kw
- assert valfilter(iseven, D({1: 2, 2: 3}), **kw) == D({1: 2})
- def test_keyfilter(self):
- D, kw = self.D, self.kw
- assert keyfilter(iseven, D({1: 2, 2: 3}), **kw) == D({2: 3})
- def test_itemfilter(self):
- D, kw = self.D, self.kw
- assert itemfilter(lambda item: iseven(item[0]), D({1: 2, 2: 3}), **kw) == D({2: 3})
- assert itemfilter(lambda item: iseven(item[1]), D({1: 2, 2: 3}), **kw) == D({1: 2})
- def test_assoc(self):
- D, kw = self.D, self.kw
- assert assoc(D({}), "a", 1, **kw) == D({"a": 1})
- assert assoc(D({"a": 1}), "a", 3, **kw) == D({"a": 3})
- assert assoc(D({"a": 1}), "b", 3, **kw) == D({"a": 1, "b": 3})
- # Verify immutability:
- d = D({'x': 1})
- oldd = d
- assoc(d, 'x', 2, **kw)
- assert d is oldd
- def test_dissoc(self):
- D, kw = self.D, self.kw
- assert dissoc(D({"a": 1}), "a") == D({})
- assert dissoc(D({"a": 1, "b": 2}), "a") == D({"b": 2})
- assert dissoc(D({"a": 1, "b": 2}), "b") == D({"a": 1})
- assert dissoc(D({"a": 1, "b": 2}), "a", "b") == D({})
- assert dissoc(D({"a": 1}), "a") == dissoc(dissoc(D({"a": 1}), "a"), "a")
- # Verify immutability:
- d = D({'x': 1})
- oldd = d
- d2 = dissoc(d, 'x')
- assert d is oldd
- assert d2 is not oldd
- def test_assoc_in(self):
- D, kw = self.D, self.kw
- assert assoc_in(D({"a": 1}), ["a"], 2, **kw) == D({"a": 2})
- assert (assoc_in(D({"a": D({"b": 1})}), ["a", "b"], 2, **kw) ==
- D({"a": D({"b": 2})}))
- assert assoc_in(D({}), ["a", "b"], 1, **kw) == D({"a": D({"b": 1})})
- # Verify immutability:
- d = D({'x': 1})
- oldd = d
- d2 = assoc_in(d, ['x'], 2, **kw)
- assert d is oldd
- assert d2 is not oldd
- def test_update_in(self):
- D, kw = self.D, self.kw
- assert update_in(D({"a": 0}), ["a"], inc, **kw) == D({"a": 1})
- assert update_in(D({"a": 0, "b": 1}), ["b"], str, **kw) == D({"a": 0, "b": "1"})
- assert (update_in(D({"t": 1, "v": D({"a": 0})}), ["v", "a"], inc, **kw) ==
- D({"t": 1, "v": D({"a": 1})}))
- # Handle one missing key.
- assert update_in(D({}), ["z"], str, None, **kw) == D({"z": "None"})
- assert update_in(D({}), ["z"], inc, 0, **kw) == D({"z": 1})
- assert update_in(D({}), ["z"], lambda x: x+"ar", default="b", **kw) == D({"z": "bar"})
- # Same semantics as Clojure for multiple missing keys, ie. recursively
- # create nested empty dictionaries to the depth specified by the
- # keys with the innermost value set to f(default).
- assert update_in(D({}), [0, 1], inc, default=-1, **kw) == D({0: D({1: 0})})
- assert update_in(D({}), [0, 1], str, default=100, **kw) == D({0: D({1: "100"})})
- assert (update_in(D({"foo": "bar", 1: 50}), ["d", 1, 0], str, 20, **kw) ==
- D({"foo": "bar", 1: 50, "d": D({1: D({0: "20"})})}))
- # Verify immutability:
- d = D({'x': 1})
- oldd = d
- update_in(d, ['x'], inc, **kw)
- assert d is oldd
- def test_factory(self):
- D, kw = self.D, self.kw
- assert merge(defaultdict(int, D({1: 2})), D({2: 3})) == {1: 2, 2: 3}
- assert (merge(defaultdict(int, D({1: 2})), D({2: 3}),
- factory=lambda: defaultdict(int)) ==
- defaultdict(int, D({1: 2, 2: 3})))
- assert not (merge(defaultdict(int, D({1: 2})), D({2: 3}),
- factory=lambda: defaultdict(int)) == {1: 2, 2: 3})
- assert raises(TypeError, lambda: merge(D({1: 2}), D({2: 3}), factoryy=dict))
- class defaultdict(_defaultdict):
- def __eq__(self, other):
- return (super(defaultdict, self).__eq__(other) and
- isinstance(other, _defaultdict) and
- self.default_factory == other.default_factory)
- class TestDefaultDict(TestDict):
- """Test defaultdict as input and factory
- Class attributes:
- D: callable that inputs a dict and creates or returns a MutableMapping
- kw: kwargs dict to specify "factory" keyword (if applicable)
- """
- @staticmethod
- def D(dict_):
- return defaultdict(int, dict_)
- kw = {'factory': lambda: defaultdict(int)}
- class CustomMapping(object):
- """Define methods of the MutableMapping protocol required by dicttoolz"""
- def __init__(self, *args, **kwargs):
- self._d = dict(*args, **kwargs)
- def __getitem__(self, key):
- return self._d[key]
- def __setitem__(self, key, val):
- self._d[key] = val
- def __delitem__(self, key):
- del self._d[key]
- def __iter__(self):
- return iter(self._d)
- def __len__(self):
- return len(self._d)
- def __contains__(self, key):
- return key in self._d
- def __eq__(self, other):
- return isinstance(other, CustomMapping) and self._d == other._d
- def __ne__(self, other):
- return not isinstance(other, CustomMapping) or self._d != other._d
- def keys(self):
- return self._d.keys()
- def values(self):
- return self._d.values()
- def items(self):
- return self._d.items()
- def update(self, *args, **kwargs):
- self._d.update(*args, **kwargs)
- # Should we require these to be defined for Python 2?
- if not PY3:
- def iterkeys(self):
- return self._d.iterkeys()
- def itervalues(self):
- return self._d.itervalues()
- def iteritems(self):
- return self._d.iteritems()
- # Unused methods that are part of the MutableMapping protocol
- #def get(self, key, *args):
- # return self._d.get(key, *args)
- #def pop(self, key, *args):
- # return self._d.pop(key, *args)
- #def popitem(self, key):
- # return self._d.popitem()
- #def clear(self):
- # self._d.clear()
- #def setdefault(self, key, *args):
- # return self._d.setdefault(self, key, *args)
- class TestCustomMapping(TestDict):
- """Test CustomMapping as input and factory
- Class attributes:
- D: callable that inputs a dict and creates or returns a MutableMapping
- kw: kwargs dict to specify "factory" keyword (if applicable)
- """
- D = CustomMapping
- kw = {'factory': lambda: CustomMapping()}
|