|
8 | 8 | import unittest
|
9 | 9 | import weakref
|
10 | 10 | from test import support
|
11 |
| -from test.support import import_helper, C_RECURSION_LIMIT |
| 11 | +from test.support import import_helper, get_c_recursion_limit |
12 | 12 |
|
13 | 13 |
|
14 | 14 | class DictTest(unittest.TestCase):
|
@@ -312,17 +312,34 @@ def __setitem__(self, key, value):
|
312 | 312 | self.assertRaises(Exc, baddict2.fromkeys, [1])
|
313 | 313 |
|
314 | 314 | # test fast path for dictionary inputs
|
| 315 | + res = dict(zip(range(6), [0]*6)) |
315 | 316 | d = dict(zip(range(6), range(6)))
|
316 |
| - self.assertEqual(dict.fromkeys(d, 0), dict(zip(range(6), [0]*6))) |
317 |
| - |
| 317 | + self.assertEqual(dict.fromkeys(d, 0), res) |
| 318 | + # test fast path for set inputs |
| 319 | + d = set(range(6)) |
| 320 | + self.assertEqual(dict.fromkeys(d, 0), res) |
| 321 | + # test slow path for other iterable inputs |
| 322 | + d = list(range(6)) |
| 323 | + self.assertEqual(dict.fromkeys(d, 0), res) |
| 324 | + |
| 325 | + # test fast path when object's constructor returns large non-empty dict |
318 | 326 | class baddict3(dict):
|
319 | 327 | def __new__(cls):
|
320 | 328 | return d
|
321 |
| - d = {i : i for i in range(10)} |
| 329 | + d = {i : i for i in range(1000)} |
322 | 330 | res = d.copy()
|
323 | 331 | res.update(a=None, b=None, c=None)
|
324 | 332 | self.assertEqual(baddict3.fromkeys({"a", "b", "c"}), res)
|
325 | 333 |
|
| 334 | + # test slow path when object is a proper subclass of dict |
| 335 | + class baddict4(dict): |
| 336 | + def __init__(self): |
| 337 | + dict.__init__(self, d) |
| 338 | + d = {i : i for i in range(1000)} |
| 339 | + res = d.copy() |
| 340 | + res.update(a=None, b=None, c=None) |
| 341 | + self.assertEqual(baddict4.fromkeys({"a", "b", "c"}), res) |
| 342 | + |
326 | 343 | def test_copy(self):
|
327 | 344 | d = {1: 1, 2: 2, 3: 3}
|
328 | 345 | self.assertIsNot(d.copy(), d)
|
@@ -596,10 +613,9 @@ def __repr__(self):
|
596 | 613 | d = {1: BadRepr()}
|
597 | 614 | self.assertRaises(Exc, repr, d)
|
598 | 615 |
|
599 |
| - @unittest.skipIf(sys.platform == 'win32', 'TODO: RUSTPYTHON Windows') |
600 | 616 | def test_repr_deep(self):
|
601 | 617 | d = {}
|
602 |
| - for i in range(C_RECURSION_LIMIT + 1): |
| 618 | + for i in range(get_c_recursion_limit() + 1): |
603 | 619 | d = {1: d}
|
604 | 620 | self.assertRaises(RecursionError, repr, d)
|
605 | 621 |
|
@@ -994,6 +1010,18 @@ class MyDict(dict):
|
994 | 1010 | pass
|
995 | 1011 | self._tracked(MyDict())
|
996 | 1012 |
|
| 1013 | + @support.cpython_only |
| 1014 | + def test_track_lazy_instance_dicts(self): |
| 1015 | + class C: |
| 1016 | + pass |
| 1017 | + o = C() |
| 1018 | + d = o.__dict__ |
| 1019 | + self._not_tracked(d) |
| 1020 | + o.untracked = 42 |
| 1021 | + self._not_tracked(d) |
| 1022 | + o.tracked = [] |
| 1023 | + self._tracked(d) |
| 1024 | + |
997 | 1025 | def make_shared_key_dict(self, n):
|
998 | 1026 | class C:
|
999 | 1027 | pass
|
@@ -1108,10 +1136,8 @@ class C:
|
1108 | 1136 | a = C()
|
1109 | 1137 | a.x = 1
|
1110 | 1138 | d = a.__dict__
|
1111 |
| - before_resize = sys.getsizeof(d) |
1112 | 1139 | d[2] = 2 # split table is resized to a generic combined table
|
1113 | 1140 |
|
1114 |
| - self.assertGreater(sys.getsizeof(d), before_resize) |
1115 | 1141 | self.assertEqual(list(d), ['x', 2])
|
1116 | 1142 |
|
1117 | 1143 | def test_iterator_pickling(self):
|
@@ -1485,6 +1511,24 @@ def test_dict_items_result_gc_reversed(self):
|
1485 | 1511 | gc.collect()
|
1486 | 1512 | self.assertTrue(gc.is_tracked(next(it)))
|
1487 | 1513 |
|
| 1514 | + def test_store_evilattr(self): |
| 1515 | + class EvilAttr: |
| 1516 | + def __init__(self, d): |
| 1517 | + self.d = d |
| 1518 | + |
| 1519 | + def __del__(self): |
| 1520 | + if 'attr' in self.d: |
| 1521 | + del self.d['attr'] |
| 1522 | + gc.collect() |
| 1523 | + |
| 1524 | + class Obj: |
| 1525 | + pass |
| 1526 | + |
| 1527 | + obj = Obj() |
| 1528 | + obj.__dict__ = {} |
| 1529 | + for _ in range(10): |
| 1530 | + obj.attr = EvilAttr(obj.__dict__) |
| 1531 | + |
1488 | 1532 | def test_str_nonstr(self):
|
1489 | 1533 | # cpython uses a different lookup function if the dict only contains
|
1490 | 1534 | # `str` keys. Make sure the unoptimized path is used when a non-`str`
|
@@ -1591,8 +1635,8 @@ class CAPITest(unittest.TestCase):
|
1591 | 1635 | # Test _PyDict_GetItem_KnownHash()
|
1592 | 1636 | @support.cpython_only
|
1593 | 1637 | def test_getitem_knownhash(self):
|
1594 |
| - _testcapi = import_helper.import_module('_testcapi') |
1595 |
| - dict_getitem_knownhash = _testcapi.dict_getitem_knownhash |
| 1638 | + _testinternalcapi = import_helper.import_module('_testinternalcapi') |
| 1639 | + dict_getitem_knownhash = _testinternalcapi.dict_getitem_knownhash |
1596 | 1640 |
|
1597 | 1641 | d = {'x': 1, 'y': 2, 'z': 3}
|
1598 | 1642 | self.assertEqual(dict_getitem_knownhash(d, 'x', hash('x')), 1)
|
|
0 commit comments