def test_popitem(self): # dict.popitem() for copymode in -1, +1: # -1: b has same structure as a # +1: b is a.copy() for log2size in range(10): size = 2**log2size a = Dict() b = Dict() for i in range(size): a[repr(i)] = i if copymode < 0: b[repr(i)] = i if copymode > 0: b = a.copy() for i in range(size): ka, va = ta = a.popitem() self.assertEqual(va, int(ka)) kb, vb = tb = b.popitem() self.assertEqual(vb, int(kb)) self.assertFalse(copymode < 0 and ta != tb) self.assertFalse(a) self.assertFalse(b) d = {} self.assertRaises(KeyError, d.popitem)
def test_values(self): d = Dict() self.assertEqual(set(d.values()), set()) d = Dict({1: 2}) self.assertEqual(set(d.values()), {2}) self.assertRaises(TypeError, d.values, None) self.assertEqual(repr(dict(a=1).values()), "dict_values([1])")
def test_dict_creation() -> None: d1 = {String("t1"): 1, String("t2"): 2} dict1 = Dict(d1) assert type(getattr(dict1, "id", None)) is UID d2 = dict({"t1": 1, "t2": 2}) dict2 = Dict(d2) dict2._id = UID() assert type(getattr(dict2, "id", None)) is UID d3 = UserDict({"t1": 1, "t2": 2}) dict3 = Dict(**d3) assert type(getattr(dict3, "id", None)) is UID assert dict1.keys() == dict2.keys() assert dict1.keys() == dict3.keys() # ValuesView uses object.__eq__ # https://stackoverflow.com/questions/34312674/why-are-the-values-of-an-ordereddict-not-equal assert dict1.values() != dict2.values() assert dict1.values() != dict3.values() assert dict1.items() == dict2.items() assert dict1.items() == dict3.items() it = list(iter(dict2.values())) assert len(it) == 2 assert type(it) is list
def test_update(self): for kw in "self", "dict", "other", "iterable": d = Dict() d.update(**{kw: 42}) self.assertEqual(list(d.items()), [(kw, 42)]) self.assertRaises(TypeError, Dict().update, 42) self.assertRaises(TypeError, Dict().update, {}, {}) self.assertRaises(TypeError, Dict.update)
def test_copy_maintains_tracking(self): class A: pass key = A() for d in (Dict(), Dict({"a": 1}), Dict({key: "val"})): d2 = d.copy() self.assertEqual(gc.is_tracked(d), gc.is_tracked(d2))
def test_get(self): d = Dict() self.assertIs(d.get("c"), SyNone) self.assertEqual(d.get("c", 3), 3) d = Dict({"a": 1, "b": 2}) self.assertEqual(d.get("c"), SyNone) self.assertEqual(d.get("c", 3), 3) self.assertEqual(d.get("a"), 1) self.assertEqual(d.get("a", 3), 1) self.assertRaises(TypeError, d.get) self.assertRaises(TypeError, d.get, None, None, None)
def test_contains(self): d = Dict() self.assertNotIn("a", d) self.assertFalse("a" in d) self.assertTrue("a" not in d) d = Dict({"a": 1, "b": 2}) self.assertIn("a", d) self.assertIn("b", d) self.assertNotIn("c", d) self.assertRaises(TypeError, d.__contains__)
def test_init(self): for kw in "self", "other", "iterable": self.assertEqual(list(Dict(**{kw: 42}).items()), [(kw, 42)]) self.assertEqual(list(Dict({}, dict=42).items()), [("dict", 42)]) self.assertEqual(list(Dict({}, dict=None).items()), [("dict", None)]) with self.assertWarnsRegex(DeprecationWarning, "'dict'"): self.assertEqual(list(Dict(dict={"a": 42}).items()), [("a", 42)]) self.assertRaises(TypeError, Dict, 42) self.assertRaises(TypeError, Dict, (), ()) self.assertRaises(TypeError, Dict.__init__)
def test_merge_and_mutate(self): class X: def __hash__(self): return 0 def __eq__(self, o): other.clear() return False test_list = [(i, 0) for i in range(1, 1337)] other = Dict(test_list) other[X()] = 0 d = Dict({X(): 0, 1: 1}) self.assertRaises(RuntimeError, d.update, other)
def test_dict_creation() -> None: d1 = {String("t1"): 1, String("t2"): 2} dict1 = Dict(d1) assert type(getattr(dict1, "id", None)) is UID d2 = dict({"t1": 1, "t2": 2}) dict2 = Dict(d2) dict2._id = UID() assert type(getattr(dict2, "id", None)) is UID d3 = UserDict({"t1": 1, "t2": 2}) dict3 = Dict(**d3) assert type(getattr(dict3, "id", None)) is UID assert dict1.keys() == dict2.keys() assert dict1.keys() == dict3.keys()
def test_bad_key(self): # Dictionary lookups should fail if __eq__() raises an exception. class CustomException(Exception): pass class BadDictKey: def __hash__(self): return hash(self.__class__) def __eq__(self, other): if isinstance(other, self.__class__): raise CustomException return other d = Dict() x1 = BadDictKey() x2 = BadDictKey() d[x1] = 1 for stmt in [ "d[x2] = 2", "z = d[x2]", "x2 in d", "d.get(x2)", "d.setdefault(x2, 42)", "d.pop(x2)", "d.update({x2: 2})", ]: with self.assertRaises(CustomException): exec(stmt, locals())
def test_mutating_iteration(self): # changing dict size during iteration d = Dict() d[1] = 1 with self.assertRaises(RuntimeError): for i in d: d[i + 1] = 1
def test_reverse_iterator_for_empty_dict(self): # bpo-38525: revered iterator should work properly # empty dict is directly used for reference count test # UserDict does not support reversed so we do not either with pytest.raises(TypeError): self.assertEqual(list(reversed(Dict())), []) self.assertEqual(list(reversed(Dict().items())), []) self.assertEqual(list(reversed(Dict().values())), []) self.assertEqual(list(reversed(Dict().keys())), []) # dict() and {} don't trigger the same code path self.assertEqual(list(reversed(dict())), []) self.assertEqual(list(reversed(dict().items())), []) self.assertEqual(list(reversed(dict().values())), []) self.assertEqual(list(reversed(dict().keys())), [])
def test_pop(self): # Tests for pop with specified key d = Dict() k, v = "abc", "def" d[k] = v self.assertRaises(KeyError, d.pop, "ghi") self.assertEqual(d.pop(k), v) self.assertEqual(len(d), 0) self.assertRaises(KeyError, d.pop, k) self.assertEqual(d.pop(k, v), v) d[k] = v self.assertEqual(d.pop(k, 1), v) self.assertRaises(TypeError, d.pop) class Exc(Exception): pass class BadHash(object): fail = False def __hash__(self): if self.fail: raise Exc() else: return 42 x = BadHash() d[x] = 42 x.fail = True self.assertRaises(Exc, d.pop, x)
def test_setitem_atomic_at_resize(self): class Hashed(object): def __init__(self): self.hash_count = 0 self.eq_count = 0 def __hash__(self): self.hash_count += 1 return 42 def __eq__(self, other): self.eq_count += 1 return id(self) == id(other) hashed1 = Hashed() # 5 items y = Dict({hashed1: 5, 0: 0, 1: 1, 2: 2, 3: 3}) hashed2 = Hashed() # 6th item forces a resize y[hashed2] = [] # this is different for UserDict which is 3 # we are subclassing UserDict so if we match UserDict that should be correct # self.assertEqual(hashed1.hash_count, 1) self.assertEqual(hashed1.hash_count, 3) self.assertEqual(hashed2.hash_count, 1) self.assertEqual(hashed1.eq_count + hashed2.eq_count, 1)
def test_setdefault(self): # dict.setdefault() d = Dict() self.assertIs(d.setdefault("key0"), SyNone) d.setdefault("key0", []) self.assertIs(d.setdefault("key0"), SyNone) d.setdefault("key", []).append(3) self.assertEqual(d["key"][0], 3) d.setdefault("key", []).append(4) self.assertEqual(len(d["key"]), 2) self.assertRaises(TypeError, d.setdefault) class Exc(Exception): pass class BadHash(object): fail = False def __hash__(self): if self.fail: raise Exc() else: return 42 x = BadHash() d[x] = 42 x.fail = True self.assertRaises(Exc, d.setdefault, x, [])
def test_dict_copy_order(self): # bpo-34320 od = collections.OrderedDict([("a", 1), ("b", 2)]) od.move_to_end("a") expected = list(od.items()) copy = Dict(od) self.assertEqual(list(copy.items()), expected) # dict subclass doesn't override __iter__ class CustomDict(Dict): pass pairs = [("a", 1), ("b", 2), ("c", 3)] d = CustomDict(pairs) self.assertEqual(pairs, list(Dict(d).items()))
def test_dict_serde() -> None: t1 = th.tensor([1, 2]) t2 = th.tensor([1, 3]) syft_list = Dict({Int(1): t1, Int(2): t2}) assert type(getattr(syft_list, "id", None)) is UID serialized = syft_list._object2proto() assert isinstance(serialized, Dict_PB) deserialized = Dict._proto2object(proto=serialized) assert isinstance(deserialized, Dict) assert deserialized.id == syft_list.id for deserialized_el, original_el in zip(deserialized, syft_list): assert deserialized_el == original_el
def test_fromkeys_operator_modifying_set_operand(self): # test fix for seg fault reported in issue 27945 part 4b. class X(int): def __hash__(self): return 13 def __eq__(self, other): if len(d) > 1: d.clear() return False d = {} # this is required to exist so that d can be constructed! d = {X(1), X(2)} try: Dict.fromkeys(d) # shouldn't crash except RuntimeError: # implementation defined pass
def test_dictitems_contains_use_after_free(self): class X: def __eq__(self, other): d.clear() return NotImplemented d = Dict({0: String("test")}) # TODO: we should be able to support set (0, X()) in d.items()
def test_init_use_after_free(self): class X: def __hash__(self): pair[:] = [] return 13 pair = [X(), 123] Dict([pair])
def test_reversed(self): d = Dict({"a": 1, "b": 2, "foo": 0, "c": 3, "d": 4}) del d["foo"] # UserDict does not support reversed so we do not either with pytest.raises(TypeError): r = reversed(d) self.assertEqual(list(r), list("dcba")) self.assertRaises(StopIteration, next, r)
def test_repr(self): d = Dict() self.assertEqual(repr(d), "{}") d[1] = 2 self.assertEqual(repr(d), "{1: 2}") d = Dict() d[1] = d self.assertEqual(repr(d), "{1: {...}}") class Exc(Exception): pass class BadRepr(object): def __repr__(self): raise Exc() d = Dict({1: BadRepr()}) self.assertRaises(Exc, repr, d)
def test_mutating_iteration_delete_over_values(self): # change dict content during iteration d = Dict() d[0] = 0 # python 3.8+ raise RuntimeError but older versions do not if sys.version_info >= (3, 8): with self.assertRaises(RuntimeError): for i in d.values(): del d[0] d[0] = 0
def test_literal_constructor(self): # check literal constructor for different sized dicts # (to exercise the BUILD_MAP oparg). for n in (0, 1, 6, 256, 400): items = [("".join(random.sample(string.ascii_letters, 8)), i) for i in range(n)] random.shuffle(items) formatted_items = (f"{k!r}: {v:d}" for k, v in items) dictliteral = "{" + ", ".join(formatted_items) + "}" self.assertEqual(eval(dictliteral), Dict(items))
def test_iterator_methods(method_name: str, root_client) -> None: d = Dict({"#1": 1, "#2": 2}) dptr = d.send(root_client) itemsptr = getattr(dptr, method_name)() assert type(itemsptr).__name__ == "IteratorPointer" for itemptr, local_item in zip(itemsptr, getattr(d, method_name)()): get_item = itemptr.get() assert get_item == local_item
def test_track_literals(self): # Test GC-optimization of dict literals x, y, z = 1.5, "a", (1, None) self._not_tracked(Dict()) self._not_tracked(Dict({x: (), y: x, z: 1})) self._not_tracked(Dict({1: "a", "b": 2})) self._not_tracked(Dict({1: 2, (None, True, False, ()): int})) self._not_tracked(Dict({1: object()})) # Dicts with mutable elements are always tracked, even if those # elements are not tracked right now. self._tracked(Dict({1: []})) self._tracked(Dict({1: ([], )})) self._tracked(Dict({1: {}})) self._tracked(Dict({1: set()}))
def check_reentrant_insertion(self, mutate): # This object will trigger mutation of the dict when replaced # by another value. Note this relies on refcounting: the test # won't achieve its purpose on fully-GCed Python implementations. class Mutating: def __del__(self): mutate(d) d = Dict({k: Mutating() for k in "abcdefghijklmnopqr"}) for k in list(d): d[k] = k
def test_copy_noncompact(self): # Dicts don't compact themselves on del/pop operations. # Copy will use a slow merging strategy that produces # a compacted copy when roughly 33% of dict is a non-used # keys-space (to optimize memory footprint). # In this test we want to hit the slow/compacting # branch of dict.copy() and make sure it works OK. d = Dict({k: k for k in range(1000)}) for k in range(950): del d[k] d2 = d.copy() self.assertEqual(d2, d)
def test_keys(self): d = Dict() self.assertEqual(set(d.keys()), set()) d = {"a": 1, "b": 2} k = d.keys() self.assertEqual(set(k), {"a", "b"}) self.assertIn("a", k) self.assertIn("b", k) self.assertIn("a", d) self.assertIn("b", d) self.assertRaises(TypeError, d.keys, None) self.assertEqual(repr(dict(a=1).keys()), "dict_keys(['a'])")