2 from test
import test_support
4 import UserDict
, random
, string
8 class DictTest(unittest
.TestCase
):
9 def test_constructor(self
):
10 # calling built-in types without argument must return empty
11 self
.assertEqual(dict(), {})
12 self
.assertIsNot(dict(), {})
14 def test_literal_constructor(self
):
15 # check literal constructor for different sized dicts
16 # (to exercise the BUILD_MAP oparg).
17 for n
in (0, 1, 6, 256, 400):
18 items
= [(''.join(random
.sample(string
.letters
, 8)), i
)
21 formatted_items
= ('{!r}: {:d}'.format(k
, v
) for k
, v
in items
)
22 dictliteral
= '{' + ', '.join(formatted_items
) + '}'
23 self
.assertEqual(eval(dictliteral
), dict(items
))
26 self
.assertIs(not {}, True)
27 self
.assertTrue({1: 2})
28 self
.assertIs(bool({}), False)
29 self
.assertIs(bool({1: 2}), True)
33 self
.assertEqual(d
.keys(), [])
36 self
.assertTrue(d
.has_key('a'))
37 self
.assertTrue(d
.has_key('b'))
39 self
.assertRaises(TypeError, d
.keys
, None)
41 def test_values(self
):
43 self
.assertEqual(d
.values(), [])
45 self
.assertEqual(d
.values(), [2])
47 self
.assertRaises(TypeError, d
.values
, None)
51 self
.assertEqual(d
.items(), [])
54 self
.assertEqual(d
.items(), [(1, 2)])
56 self
.assertRaises(TypeError, d
.items
, None)
58 def test_has_key(self
):
60 self
.assertFalse(d
.has_key('a'))
64 self
.assertEqual(k
, ['a', 'b'])
66 self
.assertRaises(TypeError, d
.has_key
)
68 def test_contains(self
):
70 self
.assertNotIn('a', d
)
71 self
.assertFalse('a' in d
)
72 self
.assertTrue('a' not in d
)
76 self
.assertNotIn('c', d
)
78 self
.assertRaises(TypeError, d
.__contains
__)
82 self
.assertEqual(len(d
), 0)
84 self
.assertEqual(len(d
), 2)
86 def test_getitem(self
):
88 self
.assertEqual(d
['a'], 1)
89 self
.assertEqual(d
['b'], 2)
92 self
.assertEqual(d
['c'], 3)
93 self
.assertEqual(d
['a'], 4)
95 self
.assertEqual(d
, {'a': 4, 'c': 3})
97 self
.assertRaises(TypeError, d
.__getitem
__)
100 def __eq__(self
, other
):
107 self
.assertRaises(KeyError, d
.__getitem
__, 23)
109 class Exc(Exception): pass
111 class BadHash(object):
122 self
.assertRaises(Exc
, d
.__getitem
__, x
)
124 def test_clear(self
):
127 self
.assertEqual(d
, {})
129 self
.assertRaises(TypeError, d
.clear
, None)
131 def test_update(self
):
135 d
.update({1:1, 2:2, 3:3})
136 self
.assertEqual(d
, {1:1, 2:2, 3:3})
139 self
.assertEqual(d
, {1:1, 2:2, 3:3})
141 self
.assertRaises((TypeError, AttributeError), d
.update
, None)
143 class SimpleUserDict
:
145 self
.d
= {1:1, 2:2, 3:3}
148 def __getitem__(self
, i
):
151 d
.update(SimpleUserDict())
152 self
.assertEqual(d
, {1:1, 2:2, 3:3})
154 class Exc(Exception): pass
157 class FailingUserDict
:
160 self
.assertRaises(Exc
, d
.update
, FailingUserDict())
162 class FailingUserDict
:
175 def __getitem__(self
, key
):
177 self
.assertRaises(Exc
, d
.update
, FailingUserDict())
179 class FailingUserDict
:
187 if self
.i
<= ord('z'):
193 def __getitem__(self
, key
):
195 self
.assertRaises(Exc
, d
.update
, FailingUserDict())
197 class badseq(object):
203 self
.assertRaises(Exc
, {}.update
, badseq())
205 self
.assertRaises(ValueError, {}.update
, [(1, 2, 3)])
207 def test_fromkeys(self
):
208 self
.assertEqual(dict.fromkeys('abc'), {'a':None, 'b':None, 'c':None})
210 self
.assertIsNot(d
.fromkeys('abc'), d
)
211 self
.assertEqual(d
.fromkeys('abc'), {'a':None, 'b':None, 'c':None})
212 self
.assertEqual(d
.fromkeys((4,5),0), {4:0, 5:0})
213 self
.assertEqual(d
.fromkeys([]), {})
216 self
.assertEqual(d
.fromkeys(g()), {1:None})
217 self
.assertRaises(TypeError, {}.fromkeys
, 3)
218 class dictlike(dict): pass
219 self
.assertEqual(dictlike
.fromkeys('a'), {'a':None})
220 self
.assertEqual(dictlike().fromkeys('a'), {'a':None})
221 self
.assertIsInstance(dictlike
.fromkeys('a'), dictlike
)
222 self
.assertIsInstance(dictlike().fromkeys('a'), dictlike
)
225 return UserDict
.UserDict()
226 ud
= mydict
.fromkeys('ab')
227 self
.assertEqual(ud
, {'a':None, 'b':None})
228 self
.assertIsInstance(ud
, UserDict
.UserDict
)
229 self
.assertRaises(TypeError, dict.fromkeys
)
231 class Exc(Exception): pass
233 class baddict1(dict):
237 self
.assertRaises(Exc
, baddict1
.fromkeys
, [1])
239 class BadSeq(object):
245 self
.assertRaises(Exc
, dict.fromkeys
, BadSeq())
247 class baddict2(dict):
248 def __setitem__(self
, key
, value
):
251 self
.assertRaises(Exc
, baddict2
.fromkeys
, [1])
253 # test fast path for dictionary inputs
254 d
= dict(zip(range(6), range(6)))
255 self
.assertEqual(dict.fromkeys(d
, 0), dict(zip(range(6), [0]*6)))
259 self
.assertEqual(d
.copy(), {1:1, 2:2, 3:3})
260 self
.assertEqual({}.copy(), {})
261 self
.assertRaises(TypeError, d
.copy
, None)
265 self
.assertIs(d
.get('c'), None)
266 self
.assertEqual(d
.get('c', 3), 3)
268 self
.assertIs(d
.get('c'), None)
269 self
.assertEqual(d
.get('c', 3), 3)
270 self
.assertEqual(d
.get('a'), 1)
271 self
.assertEqual(d
.get('a', 3), 1)
272 self
.assertRaises(TypeError, d
.get
)
273 self
.assertRaises(TypeError, d
.get
, None, None, None)
275 def test_setdefault(self
):
278 self
.assertIs(d
.setdefault('key0'), None)
279 d
.setdefault('key0', [])
280 self
.assertIs(d
.setdefault('key0'), None)
281 d
.setdefault('key', []).append(3)
282 self
.assertEqual(d
['key'][0], 3)
283 d
.setdefault('key', []).append(4)
284 self
.assertEqual(len(d
['key']), 2)
285 self
.assertRaises(TypeError, d
.setdefault
)
287 class Exc(Exception): pass
289 class BadHash(object):
300 self
.assertRaises(Exc
, d
.setdefault
, x
, [])
302 def test_popitem(self
):
304 for copymode
in -1, +1:
305 # -1: b has same structure as a
307 for log2size
in range(12):
311 for i
in range(size
):
317 for i
in range(size
):
318 ka
, va
= ta
= a
.popitem()
319 self
.assertEqual(va
, int(ka
))
320 kb
, vb
= tb
= b
.popitem()
321 self
.assertEqual(vb
, int(kb
))
322 self
.assertFalse(copymode
< 0 and ta
!= tb
)
327 self
.assertRaises(KeyError, d
.popitem
)
330 # Tests for pop with specified key
334 self
.assertRaises(KeyError, d
.pop
, 'ghi')
336 self
.assertEqual(d
.pop(k
), v
)
337 self
.assertEqual(len(d
), 0)
339 self
.assertRaises(KeyError, d
.pop
, k
)
341 # verify longs/ints get same value when key > 32 bits
342 # (for 64-bit archs). See SF bug #689659.
343 x
= 4503599627370496L
345 h
= {x
: 'anything', y
: 'something else'}
346 self
.assertEqual(h
[x
], h
[y
])
348 self
.assertEqual(d
.pop(k
, v
), v
)
350 self
.assertEqual(d
.pop(k
, 1), v
)
352 self
.assertRaises(TypeError, d
.pop
)
354 class Exc(Exception): pass
356 class BadHash(object):
367 self
.assertRaises(Exc
, d
.pop
, x
)
369 def test_mutatingiteration(self
):
370 # changing dict size during iteration
373 with self
.assertRaises(RuntimeError):
379 self
.assertEqual(repr(d
), '{}')
381 self
.assertEqual(repr(d
), '{1: 2}')
384 self
.assertEqual(repr(d
), '{1: {...}}')
386 class Exc(Exception): pass
388 class BadRepr(object):
393 self
.assertRaises(Exc
, repr, d
)
396 self
.assertFalse({} < {})
397 self
.assertFalse({1: 2} < {1L: 2L})
399 class Exc(Exception): pass
401 class BadCmp(object):
402 def __eq__(self
, other
):
410 with self
.assertRaises(Exc
):
413 def test_missing(self
):
414 # Make sure dict doesn't have a __missing__ method
415 self
.assertFalse(hasattr(dict, "__missing__"))
416 self
.assertFalse(hasattr({}, "__missing__"))
417 # Test several cases:
418 # (D) subclass defines __missing__ method returning a value
419 # (E) subclass defines __missing__ method raising RuntimeError
420 # (F) subclass sets __missing__ instance variable (no effect)
421 # (G) subclass doesn't define __missing__ at a all
423 def __missing__(self
, key
):
426 self
.assertEqual(d
[1], 2)
427 self
.assertEqual(d
[3], 4)
428 self
.assertNotIn(2, d
)
429 self
.assertNotIn(2, d
.keys())
430 self
.assertEqual(d
[2], 42)
433 def __missing__(self
, key
):
434 raise RuntimeError(key
)
436 with self
.assertRaises(RuntimeError) as c
:
438 self
.assertEqual(c
.exception
.args
, (42,))
442 # An instance variable __missing__ should have no effect
443 self
.__missing
__ = lambda key
: None
445 with self
.assertRaises(KeyError) as c
:
447 self
.assertEqual(c
.exception
.args
, (42,))
452 with self
.assertRaises(KeyError) as c
:
454 self
.assertEqual(c
.exception
.args
, (42,))
456 def test_tuple_keyerror(self
):
459 with self
.assertRaises(KeyError) as c
:
461 self
.assertEqual(c
.exception
.args
, ((1,),))
463 def test_bad_key(self
):
464 # Dictionary lookups should fail if __cmp__() raises an exception.
465 class CustomException(Exception):
470 return hash(self
.__class
__)
472 def __cmp__(self
, other
):
473 if isinstance(other
, self
.__class
__):
474 raise CustomException
481 for stmt
in ['d[x2] = 2',
486 'd.setdefault(x2, 42)',
488 'd.update({x2: 2})']:
489 with self
.assertRaises(CustomException
):
490 exec stmt
in locals()
492 def test_resize1(self
):
493 # Dict resizing bug, found by Jack Jansen in 2.2 CVS development.
494 # This version got an assert failure in debug build, infinite loop in
495 # release build. Unfortunately, provoking this kind of stuff requires
496 # a mix of inserts and deletes hitting exactly the right hash codes in
497 # exactly the right order, and I can't think of a randomized approach
498 # that would be *likely* to hit a failing case in reasonable time.
505 for i
in range(5, 9): # i==8 was the problem
508 def test_resize2(self
):
509 # Another dict resizing bug (SF bug #1456209).
510 # This caused Segmentation faults or Illegal instructions.
515 def __eq__(self
, other
):
526 # now trigger a resize
530 def test_empty_presized_dict_in_freelist(self
):
531 # Bug #3537: if an empty but presized dict with a size larger
532 # than 7 was in the freelist, it triggered an assertion failure
533 with self
.assertRaises(ZeroDivisionError):
534 d
= {'a': 1 // 0, 'b': None, 'c': None, 'd': None, 'e': None,
535 'f': None, 'g': None, 'h': None}
538 def test_container_iterator(self
):
539 # Bug #3680: tp_traverse was not implemented for dictiter objects
542 iterators
= (dict.iteritems
, dict.itervalues
, dict.iterkeys
)
545 ref
= weakref
.ref(obj
)
550 self
.assertIs(ref(), None, "Cycle was not collected")
552 def _not_tracked(self
, t
):
553 # Nested containers can take several collections to untrack
556 self
.assertFalse(gc
.is_tracked(t
), t
)
558 def _tracked(self
, t
):
559 self
.assertTrue(gc
.is_tracked(t
), t
)
562 self
.assertTrue(gc
.is_tracked(t
), t
)
564 @test_support.cpython_only
565 def test_track_literals(self
):
566 # Test GC-optimization of dict literals
567 x
, y
, z
, w
= 1.5, "a", (1, None), []
569 self
._not
_tracked
({})
570 self
._not
_tracked
({x
:(), y
:x
, z
:1})
571 self
._not
_tracked
({1: "a", "b": 2})
572 self
._not
_tracked
({1: 2, (None, True, False, ()): int})
573 self
._not
_tracked
({1: object()})
575 # Dicts with mutable elements are always tracked, even if those
576 # elements are not tracked right now.
577 self
._tracked
({1: []})
578 self
._tracked
({1: ([],)})
579 self
._tracked
({1: {}})
580 self
._tracked
({1: set()})
582 @test_support.cpython_only
583 def test_track_dynamic(self
):
584 # Test GC-optimization of dynamically-created dicts
585 class MyObject(object):
587 x
, y
, z
, w
, o
= 1.5, "a", (1, object()), [], MyObject()
597 self
._not
_tracked
(d
.copy())
600 self
._tracked
(d
.copy())
603 self
._not
_tracked
(d
.copy())
605 # dd isn't tracked right now, but it may mutate and therefore d
606 # which contains it must be tracked.
610 self
._not
_tracked
(dd
)
615 d
= dict.fromkeys([x
, y
, z
])
619 self
._not
_tracked
(dd
)
620 d
= dict.fromkeys([x
, y
, z
, o
])
626 d
= dict(x
=x
, y
=y
, z
=z
)
628 d
= dict(x
=x
, y
=y
, z
=z
, w
=w
)
631 d
.update(x
=x
, y
=y
, z
=z
)
636 d
= dict([(x
, y
), (z
, 1)])
638 d
= dict([(x
, y
), (z
, w
)])
641 d
.update([(x
, y
), (z
, 1)])
643 d
.update([(x
, y
), (z
, w
)])
646 @test_support.cpython_only
647 def test_track_subtypes(self
):
648 # Dict subtypes are always tracked
651 self
._tracked
(MyDict())
654 from test
import mapping_tests
656 class GeneralMappingTests(mapping_tests
.BasicTestMappingProtocol
):
662 class SubclassMappingTests(mapping_tests
.BasicTestMappingProtocol
):
666 with test_support
.check_py3k_warnings(
667 ('dict(.has_key..| inequality comparisons) not supported in 3.x',
668 DeprecationWarning)):
669 test_support
.run_unittest(
672 SubclassMappingTests
,
675 if __name__
== "__main__":