1 """Unit tests for collections.py."""
3 import unittest
, doctest
5 from test
import support
6 from collections
import namedtuple
, Counter
, OrderedDict
7 from test
import mapping_tests
9 from random
import randrange
, shuffle
13 from collections
import Hashable
, Iterable
, Iterator
14 from collections
import Sized
, Container
, Callable
15 from collections
import Set
, MutableSet
16 from collections
import Mapping
, MutableMapping
17 from collections
import Sequence
, MutableSequence
18 from collections
import ByteString
20 TestNT
= namedtuple('TestNT', 'x y z') # type used for pickle tests
22 class TestNamedTuple(unittest
.TestCase
):
24 def test_factory(self
):
25 Point
= namedtuple('Point', 'x y')
26 self
.assertEqual(Point
.__name
__, 'Point')
27 self
.assertEqual(Point
.__doc
__, 'Point(x, y)')
28 self
.assertEqual(Point
.__slots
__, ())
29 self
.assertEqual(Point
.__module
__, __name__
)
30 self
.assertEqual(Point
.__getitem
__, tuple.__getitem
__)
31 self
.assertEqual(Point
._fields
, ('x', 'y'))
33 self
.assertRaises(ValueError, namedtuple
, 'abc%', 'efg ghi') # type has non-alpha char
34 self
.assertRaises(ValueError, namedtuple
, 'class', 'efg ghi') # type has keyword
35 self
.assertRaises(ValueError, namedtuple
, '9abc', 'efg ghi') # type starts with digit
37 self
.assertRaises(ValueError, namedtuple
, 'abc', 'efg g%hi') # field with non-alpha char
38 self
.assertRaises(ValueError, namedtuple
, 'abc', 'abc class') # field has keyword
39 self
.assertRaises(ValueError, namedtuple
, 'abc', '8efg 9ghi') # field starts with digit
40 self
.assertRaises(ValueError, namedtuple
, 'abc', '_efg ghi') # field with leading underscore
41 self
.assertRaises(ValueError, namedtuple
, 'abc', 'efg efg ghi') # duplicate field
43 namedtuple('Point0', 'x1 y2') # Verify that numbers are allowed in names
44 namedtuple('_', 'a b c') # Test leading underscores in a typename
46 nt
= namedtuple('nt', 'the quick brown fox') # check unicode input
47 self
.assert_("u'" not in repr(nt
._fields
))
48 nt
= namedtuple('nt', ('the', 'quick')) # check unicode input
49 self
.assert_("u'" not in repr(nt
._fields
))
51 self
.assertRaises(TypeError, Point
._make
, [11]) # catch too few args
52 self
.assertRaises(TypeError, Point
._make
, [11, 22, 33]) # catch too many args
54 def test_name_fixer(self
):
55 for spec
, renamed
in [
56 [('efg', 'g%hi'), ('efg', '_1')], # field with non-alpha char
57 [('abc', 'class'), ('abc', '_1')], # field has keyword
58 [('8efg', '9ghi'), ('_0', '_1')], # field starts with digit
59 [('abc', '_efg'), ('abc', '_1')], # field with leading underscore
60 [('abc', 'efg', 'efg', 'ghi'), ('abc', 'efg', '_2', 'ghi')], # duplicate field
61 [('abc', '', 'x'), ('abc', '_1', 'x')], # fieldname is a space
63 self
.assertEqual(namedtuple('NT', spec
, rename
=True)._fields
, renamed
)
65 def test_instance(self
):
66 Point
= namedtuple('Point', 'x y')
68 self
.assertEqual(p
, Point(x
=11, y
=22))
69 self
.assertEqual(p
, Point(11, y
=22))
70 self
.assertEqual(p
, Point(y
=22, x
=11))
71 self
.assertEqual(p
, Point(*(11, 22)))
72 self
.assertEqual(p
, Point(**dict(x
=11, y
=22)))
73 self
.assertRaises(TypeError, Point
, 1) # too few args
74 self
.assertRaises(TypeError, Point
, 1, 2, 3) # too many args
75 self
.assertRaises(TypeError, eval, 'Point(XXX=1, y=2)', locals()) # wrong keyword argument
76 self
.assertRaises(TypeError, eval, 'Point(x=1)', locals()) # missing keyword argument
77 self
.assertEqual(repr(p
), 'Point(x=11, y=22)')
78 self
.assert_('__dict__' not in dir(p
)) # verify instance has no dict
79 self
.assert_('__weakref__' not in dir(p
))
80 self
.assertEqual(p
, Point
._make
([11, 22])) # test _make classmethod
81 self
.assertEqual(p
._fields
, ('x', 'y')) # test _fields attribute
82 self
.assertEqual(p
._replace
(x
=1), (1, 22)) # test _replace method
83 self
.assertEqual(p
._asdict
(), dict(x
=11, y
=22)) # test _asdict method
86 p
._replace
(x
=1, error
=2)
90 self
._fail
('Did not detect an incorrect fieldname')
92 # verify that field string can have commas
93 Point
= namedtuple('Point', 'x, y')
95 self
.assertEqual(repr(p
), 'Point(x=11, y=22)')
97 # verify that fieldspec can be a non-string sequence
98 Point
= namedtuple('Point', ('x', 'y'))
100 self
.assertEqual(repr(p
), 'Point(x=11, y=22)')
102 def test_tupleness(self
):
103 Point
= namedtuple('Point', 'x y')
106 self
.assert_(isinstance(p
, tuple))
107 self
.assertEqual(p
, (11, 22)) # matches a real tuple
108 self
.assertEqual(tuple(p
), (11, 22)) # coercable to a real tuple
109 self
.assertEqual(list(p
), [11, 22]) # coercable to a list
110 self
.assertEqual(max(p
), 22) # iterable
111 self
.assertEqual(max(*p
), 22) # star-able
113 self
.assertEqual(p
, (x
, y
)) # unpacks like a tuple
114 self
.assertEqual((p
[0], p
[1]), (11, 22)) # indexable like a tuple
115 self
.assertRaises(IndexError, p
.__getitem
__, 3)
117 self
.assertEqual(p
.x
, x
)
118 self
.assertEqual(p
.y
, y
)
119 self
.assertRaises(AttributeError, eval, 'p.z', locals())
121 def test_odd_sizes(self
):
122 Zero
= namedtuple('Zero', '')
123 self
.assertEqual(Zero(), ())
124 self
.assertEqual(Zero
._make
([]), ())
125 self
.assertEqual(repr(Zero()), 'Zero()')
126 self
.assertEqual(Zero()._asdict
(), {})
127 self
.assertEqual(Zero()._fields
, ())
129 Dot
= namedtuple('Dot', 'd')
130 self
.assertEqual(Dot(1), (1,))
131 self
.assertEqual(Dot
._make
([1]), (1,))
132 self
.assertEqual(Dot(1).d
, 1)
133 self
.assertEqual(repr(Dot(1)), 'Dot(d=1)')
134 self
.assertEqual(Dot(1)._asdict
(), {'d':1})
135 self
.assertEqual(Dot(1)._replace
(d
=999), (999,))
136 self
.assertEqual(Dot(1)._fields
, ('d',))
139 n
= 254 # SyntaxError: more than 255 arguments:
140 import string
, random
141 names
= list(set(''.join([random
.choice(string
.ascii_letters
)
142 for j
in range(10)]) for i
in range(n
)))
144 Big
= namedtuple('Big', names
)
146 self
.assertEqual(b
, tuple(range(n
)))
147 self
.assertEqual(Big
._make
(range(n
)), tuple(range(n
)))
148 for pos
, name
in enumerate(names
):
149 self
.assertEqual(getattr(b
, name
), pos
)
150 repr(b
) # make sure repr() doesn't blow-up
152 d_expected
= dict(zip(names
, range(n
)))
153 self
.assertEqual(d
, d_expected
)
154 b2
= b
._replace
(**dict([(names
[1], 999),(names
[-5], 42)]))
155 b2_expected
= list(range(n
))
158 self
.assertEqual(b2
, tuple(b2_expected
))
159 self
.assertEqual(b
._fields
, tuple(names
))
161 def test_pickle(self
):
162 p
= TestNT(x
=10, y
=20, z
=30)
163 for module
in (pickle
,):
164 loads
= getattr(module
, 'loads')
165 dumps
= getattr(module
, 'dumps')
166 for protocol
in -1, 0, 1, 2:
167 q
= loads(dumps(p
, protocol
))
168 self
.assertEqual(p
, q
)
169 self
.assertEqual(p
._fields
, q
._fields
)
172 p
= TestNT(x
=10, y
=20, z
=30)
173 for copier
in copy
.copy
, copy
.deepcopy
:
175 self
.assertEqual(p
, q
)
176 self
.assertEqual(p
._fields
, q
._fields
)
178 def test_name_conflicts(self
):
179 # Some names like "self", "cls", "tuple", "itemgetter", and "property"
180 # failed when used as field names. Test to make sure these now work.
181 T
= namedtuple('T', 'itemgetter property self cls tuple')
183 self
.assertEqual(t
, (1,2,3,4,5))
184 newt
= t
._replace
(itemgetter
=10, property=20, self
=30, cls
=40, tuple=50)
185 self
.assertEqual(newt
, (10,20,30,40,50))
187 # Broader test of all interesting names in a template
188 with support
.captured_stdout() as template
:
189 T
= namedtuple('T', 'x', verbose
=True)
190 words
= set(re
.findall('[A-Za-z]+', template
.getvalue()))
191 words
-= set(keyword
.kwlist
)
192 T
= namedtuple('T', words
)
194 values
= tuple(range(len(words
)))
196 self
.assertEqual(t
, values
)
197 t
= T(**dict(zip(T
._fields
, values
)))
198 self
.assertEqual(t
, values
)
201 self
.assertEqual(t
, values
)
205 self
.assertEqual(t
._asdict
(), dict(zip(T
._fields
, values
)))
208 newvalues
= tuple(v
*10 for v
in values
)
209 newt
= t
._replace
(**dict(zip(T
._fields
, newvalues
)))
210 self
.assertEqual(newt
, newvalues
)
212 self
.assertEqual(T
._fields
, tuple(words
))
213 # test __getnewargs__
214 self
.assertEqual(t
.__getnewargs
__(), values
)
216 class ABCTestCase(unittest
.TestCase
):
218 def validate_abstract_methods(self
, abc
, *names
):
219 methodstubs
= dict.fromkeys(names
, lambda s
, *args
: 0)
221 # everything should work will all required methods are present
222 C
= type('C', (abc
,), methodstubs
)
225 # instantiation should fail if a required method is missing
227 stubs
= methodstubs
.copy()
229 C
= type('C', (abc
,), stubs
)
230 self
.assertRaises(TypeError, C
, name
)
233 class TestOneTrickPonyABCs(ABCTestCase
):
235 def test_Hashable(self
):
236 # Check some non-hashables
237 non_samples
= [bytearray(), list(), set(), dict()]
238 for x
in non_samples
:
239 self
.failIf(isinstance(x
, Hashable
), repr(x
))
240 self
.failIf(issubclass(type(x
), Hashable
), repr(type(x
)))
241 # Check some hashables
243 int(), float(), complex(),
245 tuple(), frozenset(),
246 int, list, object, type, bytes()
249 self
.failUnless(isinstance(x
, Hashable
), repr(x
))
250 self
.failUnless(issubclass(type(x
), Hashable
), repr(type(x
)))
251 self
.assertRaises(TypeError, Hashable
)
252 # Check direct subclassing
255 return super().__hash
__()
256 self
.assertEqual(hash(H()), 0)
257 self
.failIf(issubclass(int, H
))
258 self
.validate_abstract_methods(Hashable
, '__hash__')
260 def test_Iterable(self
):
261 # Check some non-iterables
262 non_samples
= [None, 42, 3.14, 1j
]
263 for x
in non_samples
:
264 self
.failIf(isinstance(x
, Iterable
), repr(x
))
265 self
.failIf(issubclass(type(x
), Iterable
), repr(type(x
)))
266 # Check some iterables
267 samples
= [bytes(), str(),
268 tuple(), list(), set(), frozenset(), dict(),
269 dict().keys(), dict().items(), dict().values(),
274 self
.failUnless(isinstance(x
, Iterable
), repr(x
))
275 self
.failUnless(issubclass(type(x
), Iterable
), repr(type(x
)))
276 # Check direct subclassing
279 return super().__iter
__()
280 self
.assertEqual(list(I()), [])
281 self
.failIf(issubclass(str, I
))
282 self
.validate_abstract_methods(Iterable
, '__iter__')
284 def test_Iterator(self
):
285 non_samples
= [None, 42, 3.14, 1j
, b
"", "", (), [], {}, set()]
286 for x
in non_samples
:
287 self
.failIf(isinstance(x
, Iterator
), repr(x
))
288 self
.failIf(issubclass(type(x
), Iterator
), repr(type(x
)))
289 samples
= [iter(bytes()), iter(str()),
290 iter(tuple()), iter(list()), iter(dict()),
291 iter(set()), iter(frozenset()),
292 iter(dict().keys()), iter(dict().items()),
293 iter(dict().values()),
298 self
.failUnless(isinstance(x
, Iterator
), repr(x
))
299 self
.failUnless(issubclass(type(x
), Iterator
), repr(type(x
)))
300 self
.validate_abstract_methods(Iterator
, '__next__')
302 def test_Sized(self
):
303 non_samples
= [None, 42, 3.14, 1j
,
307 for x
in non_samples
:
308 self
.failIf(isinstance(x
, Sized
), repr(x
))
309 self
.failIf(issubclass(type(x
), Sized
), repr(type(x
)))
310 samples
= [bytes(), str(),
311 tuple(), list(), set(), frozenset(), dict(),
312 dict().keys(), dict().items(), dict().values(),
315 self
.failUnless(isinstance(x
, Sized
), repr(x
))
316 self
.failUnless(issubclass(type(x
), Sized
), repr(type(x
)))
317 self
.validate_abstract_methods(Sized
, '__len__')
319 def test_Container(self
):
320 non_samples
= [None, 42, 3.14, 1j
,
324 for x
in non_samples
:
325 self
.failIf(isinstance(x
, Container
), repr(x
))
326 self
.failIf(issubclass(type(x
), Container
), repr(type(x
)))
327 samples
= [bytes(), str(),
328 tuple(), list(), set(), frozenset(), dict(),
329 dict().keys(), dict().items(),
332 self
.failUnless(isinstance(x
, Container
), repr(x
))
333 self
.failUnless(issubclass(type(x
), Container
), repr(type(x
)))
334 self
.validate_abstract_methods(Container
, '__contains__')
336 def test_Callable(self
):
337 non_samples
= [None, 42, 3.14, 1j
,
338 "", b
"", (), [], {}, set(),
342 for x
in non_samples
:
343 self
.failIf(isinstance(x
, Callable
), repr(x
))
344 self
.failIf(issubclass(type(x
), Callable
), repr(type(x
)))
345 samples
= [lambda: None,
348 list.append
, [].append
,
351 self
.failUnless(isinstance(x
, Callable
), repr(x
))
352 self
.failUnless(issubclass(type(x
), Callable
), repr(type(x
)))
353 self
.validate_abstract_methods(Callable
, '__call__')
355 def test_direct_subclassing(self
):
356 for B
in Hashable
, Iterable
, Iterator
, Sized
, Container
, Callable
:
359 self
.failUnless(issubclass(C
, B
))
360 self
.failIf(issubclass(int, C
))
362 def test_registration(self
):
363 for B
in Hashable
, Iterable
, Iterator
, Sized
, Container
, Callable
:
365 __hash__
= None # Make sure it isn't hashable by default
366 self
.failIf(issubclass(C
, B
), B
.__name
__)
368 self
.failUnless(issubclass(C
, B
))
370 class WithSet(MutableSet
):
372 def __init__(self
, it
=()):
376 return len(self
.data
)
379 return iter(self
.data
)
381 def __contains__(self
, item
):
382 return item
in self
.data
387 def discard(self
, item
):
388 self
.data
.discard(item
)
390 class TestCollectionABCs(ABCTestCase
):
392 # XXX For now, we only test some virtual inheritance properties.
393 # We should also test the proper behavior of the collection ABCs
394 # as real base classes or mix-in classes.
397 for sample
in [set, frozenset]:
398 self
.failUnless(isinstance(sample(), Set
))
399 self
.failUnless(issubclass(sample
, Set
))
400 self
.validate_abstract_methods(Set
, '__contains__', '__iter__', '__len__')
402 def test_hash_Set(self
):
403 class OneTwoThreeSet(Set
):
405 self
.contents
= [1, 2, 3]
406 def __contains__(self
, x
):
407 return x
in self
.contents
409 return len(self
.contents
)
411 return iter(self
.contents
)
414 a
, b
= OneTwoThreeSet(), OneTwoThreeSet()
415 self
.failUnless(hash(a
) == hash(b
))
417 def test_MutableSet(self
):
418 self
.failUnless(isinstance(set(), MutableSet
))
419 self
.failUnless(issubclass(set, MutableSet
))
420 self
.failIf(isinstance(frozenset(), MutableSet
))
421 self
.failIf(issubclass(frozenset, MutableSet
))
422 self
.validate_abstract_methods(MutableSet
, '__contains__', '__iter__', '__len__',
425 def test_issue_5647(self
):
426 # MutableSet.__iand__ mutated the set during iteration
428 s
&= WithSet('cdef') # This used to fail
429 self
.assertEqual(set(s
), set('cd'))
431 def test_issue_4920(self
):
432 # MutableSet.pop() method did not work
433 class MySet(collections
.MutableSet
):
435 def __init__(self
,items
=None):
439 def __contains__(self
,v
):
442 return iter(self
.__s
)
446 result
=v
not in self
.__s
454 return "MySet(%s)" % repr(list(self
))
455 s
= MySet([5,43,2,1])
456 self
.assertEqual(s
.pop(), 1)
458 def test_Mapping(self
):
459 for sample
in [dict]:
460 self
.failUnless(isinstance(sample(), Mapping
))
461 self
.failUnless(issubclass(sample
, Mapping
))
462 self
.validate_abstract_methods(Mapping
, '__contains__', '__iter__', '__len__',
465 def test_MutableMapping(self
):
466 for sample
in [dict]:
467 self
.failUnless(isinstance(sample(), MutableMapping
))
468 self
.failUnless(issubclass(sample
, MutableMapping
))
469 self
.validate_abstract_methods(MutableMapping
, '__contains__', '__iter__', '__len__',
470 '__getitem__', '__setitem__', '__delitem__')
472 def test_Sequence(self
):
473 for sample
in [tuple, list, bytes
, str]:
474 self
.failUnless(isinstance(sample(), Sequence
))
475 self
.failUnless(issubclass(sample
, Sequence
))
476 self
.failUnless(isinstance(range(10), Sequence
))
477 self
.failUnless(issubclass(range, Sequence
))
478 self
.failUnless(issubclass(str, Sequence
))
479 self
.validate_abstract_methods(Sequence
, '__contains__', '__iter__', '__len__',
482 def test_ByteString(self
):
483 for sample
in [bytes
, bytearray
]:
484 self
.failUnless(isinstance(sample(), ByteString
))
485 self
.failUnless(issubclass(sample
, ByteString
))
486 for sample
in [str, list, tuple]:
487 self
.failIf(isinstance(sample(), ByteString
))
488 self
.failIf(issubclass(sample
, ByteString
))
489 self
.failIf(isinstance(memoryview(b
""), ByteString
))
490 self
.failIf(issubclass(memoryview
, ByteString
))
492 def test_MutableSequence(self
):
493 for sample
in [tuple, str, bytes
]:
494 self
.failIf(isinstance(sample(), MutableSequence
))
495 self
.failIf(issubclass(sample
, MutableSequence
))
496 for sample
in [list, bytearray
]:
497 self
.failUnless(isinstance(sample(), MutableSequence
))
498 self
.failUnless(issubclass(sample
, MutableSequence
))
499 self
.failIf(issubclass(str, MutableSequence
))
500 self
.validate_abstract_methods(MutableSequence
, '__contains__', '__iter__',
501 '__len__', '__getitem__', '__setitem__', '__delitem__', 'insert')
503 class TestCounter(unittest
.TestCase
):
505 def test_basics(self
):
506 c
= Counter('abcaba')
507 self
.assertEqual(c
, Counter({'a':3 , 'b': 2, 'c': 1}))
508 self
.assertEqual(c
, Counter(a
=3, b
=2, c
=1))
509 self
.assert_(isinstance(c
, dict))
510 self
.assert_(isinstance(c
, Mapping
))
511 self
.assert_(issubclass(Counter
, dict))
512 self
.assert_(issubclass(Counter
, Mapping
))
513 self
.assertEqual(len(c
), 3)
514 self
.assertEqual(sum(c
.values()), 6)
515 self
.assertEqual(sorted(c
.values()), [1, 2, 3])
516 self
.assertEqual(sorted(c
.keys()), ['a', 'b', 'c'])
517 self
.assertEqual(sorted(c
), ['a', 'b', 'c'])
518 self
.assertEqual(sorted(c
.items()),
519 [('a', 3), ('b', 2), ('c', 1)])
520 self
.assertEqual(c
['b'], 2)
521 self
.assertEqual(c
['z'], 0)
522 self
.assertEqual(c
.__contains
__('c'), True)
523 self
.assertEqual(c
.__contains
__('z'), False)
524 self
.assertEqual(c
.get('b', 10), 2)
525 self
.assertEqual(c
.get('z', 10), 10)
526 self
.assertEqual(c
, dict(a
=3, b
=2, c
=1))
527 self
.assertEqual(repr(c
), "Counter({'a': 3, 'b': 2, 'c': 1})")
528 self
.assertEqual(c
.most_common(), [('a', 3), ('b', 2), ('c', 1)])
530 self
.assertEqual(c
.most_common(i
),
531 [('a', 3), ('b', 2), ('c', 1)][:i
])
532 self
.assertEqual(''.join(sorted(c
.elements())), 'aaabbc')
533 c
['a'] += 1 # increment an existing value
534 c
['b'] -= 2 # sub existing value to zero
535 del c
['c'] # remove an entry
536 del c
['c'] # make sure that del doesn't raise KeyError
537 c
['d'] -= 2 # sub from a missing value
538 c
['e'] = -5 # directly assign a missing value
539 c
['f'] += 4 # add to a missing value
540 self
.assertEqual(c
, dict(a
=4, b
=0, d
=-2, e
=-5, f
=4))
541 self
.assertEqual(''.join(sorted(c
.elements())), 'aaaaffff')
542 self
.assertEqual(c
.pop('f'), 4)
543 self
.assertEqual('f' in c
, False)
545 elem
, cnt
= c
.popitem()
546 self
.assertEqual(elem
in c
, False)
548 self
.assertEqual(c
, {})
549 self
.assertEqual(repr(c
), 'Counter()')
550 self
.assertRaises(NotImplementedError, Counter
.fromkeys
, 'abc')
551 self
.assertRaises(TypeError, hash, c
)
552 c
.update(dict(a
=5, b
=3))
554 c
.update(Counter('a' * 50 + 'b' * 30))
555 c
.update() # test case with no args
556 c
.__init
__('a' * 500 + 'b' * 300)
559 self
.assertEqual(c
, dict(a
=555, b
=333, c
=3, d
=1))
560 self
.assertEqual(c
.setdefault('d', 5), 1)
561 self
.assertEqual(c
['d'], 1)
562 self
.assertEqual(c
.setdefault('e', 5), 5)
563 self
.assertEqual(c
['e'], 5)
565 def test_copying(self
):
566 # Check that counters are copyable, deepcopyable, picklable, and
567 #have a repr/eval round-trip
568 words
= Counter('which witch had which witches wrist watch'.split())
569 update_test
= Counter()
570 update_test
.update(words
)
571 for i
, dup
in enumerate([
574 copy
.deepcopy(words
),
575 pickle
.loads(pickle
.dumps(words
, 0)),
576 pickle
.loads(pickle
.dumps(words
, 1)),
577 pickle
.loads(pickle
.dumps(words
, 2)),
578 pickle
.loads(pickle
.dumps(words
, -1)),
583 msg
= (i
, dup
, words
)
584 self
.assert_(dup
is not words
)
585 self
.assertEquals(dup
, words
)
586 self
.assertEquals(len(dup
), len(words
))
587 self
.assertEquals(type(dup
), type(words
))
589 def test_conversions(self
):
590 # Convert to: set, list, dict
591 s
= 'she sells sea shells by the sea shore'
592 self
.assertEqual(sorted(Counter(s
).elements()), sorted(s
))
593 self
.assertEqual(sorted(Counter(s
)), sorted(set(s
)))
594 self
.assertEqual(dict(Counter(s
)), dict(Counter(s
).items()))
595 self
.assertEqual(set(Counter(s
)), set(s
))
597 def test_invariant_for_the_in_operator(self
):
598 c
= Counter(a
=10, b
=-2, c
=0)
600 self
.assert_(elem
in c
)
602 def test_multiset_operations(self
):
603 # Verify that adding a zero counter will strip zeros and negatives
604 c
= Counter(a
=10, b
=-2, c
=0) + Counter()
605 self
.assertEqual(dict(c
), dict(a
=10))
608 for i
in range(1000):
609 # test random pairs of multisets
610 p
= Counter(dict((elem
, randrange(-2,4)) for elem
in elements
))
611 p
.update(e
=1, f
=-1, g
=0)
612 q
= Counter(dict((elem
, randrange(-2,4)) for elem
in elements
))
613 q
.update(h
=1, i
=-1, j
=0)
614 for counterop
, numberop
in [
615 (Counter
.__add
__, lambda x
, y
: max(0, x
+y
)),
616 (Counter
.__sub
__, lambda x
, y
: max(0, x
-y
)),
617 (Counter
.__or
__, lambda x
, y
: max(0,x
,y
)),
618 (Counter
.__and
__, lambda x
, y
: max(0, min(x
,y
))),
620 result
= counterop(p
, q
)
622 self
.assertEqual(numberop(p
[x
], q
[x
]), result
[x
],
623 (counterop
, x
, p
, q
))
624 # verify that results exclude non-positive counts
625 self
.assert_(x
>0 for x
in result
.values())
629 # verify that random multisets with no repeats are exactly like sets
630 p
= Counter(dict((elem
, randrange(0, 2)) for elem
in elements
))
631 q
= Counter(dict((elem
, randrange(0, 2)) for elem
in elements
))
632 for counterop
, setop
in [
633 (Counter
.__sub
__, set.__sub
__),
634 (Counter
.__or
__, set.__or
__),
635 (Counter
.__and
__, set.__and
__),
637 counter_result
= counterop(p
, q
)
638 set_result
= setop(set(p
.elements()), set(q
.elements()))
639 self
.assertEqual(counter_result
, dict.fromkeys(set_result
, 1))
642 class TestOrderedDict(unittest
.TestCase
):
645 with self
.assertRaises(TypeError):
646 OrderedDict([('a', 1), ('b', 2)], None) # too many args
647 pairs
= [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)]
648 self
.assertEqual(sorted(OrderedDict(dict(pairs
)).items()), pairs
) # dict input
649 self
.assertEqual(sorted(OrderedDict(**dict(pairs
)).items()), pairs
) # kwds input
650 self
.assertEqual(list(OrderedDict(pairs
).items()), pairs
) # pairs input
651 self
.assertEqual(list(OrderedDict([('a', 1), ('b', 2), ('c', 9), ('d', 4)],
652 c
=3, e
=5).items()), pairs
) # mixed input
654 # make sure no positional args conflict with possible kwdargs
655 self
.assertEqual(inspect
.getargspec(OrderedDict
.__dict
__['__init__']).args
,
658 # Make sure that direct calls to __init__ do not clear previous contents
659 d
= OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 44), ('e', 55)])
660 d
.__init
__([('e', 5), ('f', 6)], g
=7, d
=4)
661 self
.assertEqual(list(d
.items()),
662 [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5), ('f', 6), ('g', 7)])
664 def test_update(self
):
665 with self
.assertRaises(TypeError):
666 OrderedDict().update([('a', 1), ('b', 2)], None) # too many args
667 pairs
= [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)]
669 od
.update(dict(pairs
))
670 self
.assertEqual(sorted(od
.items()), pairs
) # dict input
672 od
.update(**dict(pairs
))
673 self
.assertEqual(sorted(od
.items()), pairs
) # kwds input
676 self
.assertEqual(list(od
.items()), pairs
) # pairs input
678 od
.update([('a', 1), ('b', 2), ('c', 9), ('d', 4)], c
=3, e
=5)
679 self
.assertEqual(list(od
.items()), pairs
) # mixed input
681 # Make sure that direct calls to update do not clear previous contents
682 # add that updates items are not moved to the end
683 d
= OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 44), ('e', 55)])
684 d
.update([('e', 5), ('f', 6)], g
=7, d
=4)
685 self
.assertEqual(list(d
.items()),
686 [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5), ('f', 6), ('g', 7)])
688 def test_clear(self
):
689 pairs
= [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
691 od
= OrderedDict(pairs
)
692 self
.assertEqual(len(od
), len(pairs
))
694 self
.assertEqual(len(od
), 0)
696 def test_delitem(self
):
697 pairs
= [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
698 od
= OrderedDict(pairs
)
700 self
.assert_('a' not in od
)
701 with self
.assertRaises(KeyError):
703 self
.assertEqual(list(od
.items()), pairs
[:2] + pairs
[3:])
705 def test_setitem(self
):
706 od
= OrderedDict([('d', 1), ('b', 2), ('c', 3), ('a', 4), ('e', 5)])
707 od
['c'] = 10 # existing element
708 od
['f'] = 20 # new element
709 self
.assertEqual(list(od
.items()),
710 [('d', 1), ('b', 2), ('c', 10), ('a', 4), ('e', 5), ('f', 20)])
712 def test_iterators(self
):
713 pairs
= [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
715 od
= OrderedDict(pairs
)
716 self
.assertEqual(list(od
), [t
[0] for t
in pairs
])
717 self
.assertEqual(list(od
.keys()), [t
[0] for t
in pairs
])
718 self
.assertEqual(list(od
.values()), [t
[1] for t
in pairs
])
719 self
.assertEqual(list(od
.items()), pairs
)
720 self
.assertEqual(list(reversed(od
)),
721 [t
[0] for t
in reversed(pairs
)])
723 def test_popitem(self
):
724 pairs
= [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
726 od
= OrderedDict(pairs
)
728 self
.assertEqual(od
.popitem(), pairs
.pop())
729 with self
.assertRaises(KeyError):
731 self
.assertEqual(len(od
), 0)
734 pairs
= [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
736 od
= OrderedDict(pairs
)
740 self
.assertEqual(od
.pop(k
), v
)
741 with self
.assertRaises(KeyError):
743 self
.assertEqual(len(od
), 0)
744 self
.assertEqual(od
.pop(k
, 12345), 12345)
746 def test_equality(self
):
747 pairs
= [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
749 od1
= OrderedDict(pairs
)
750 od2
= OrderedDict(pairs
)
751 self
.assertEqual(od1
, od2
) # same order implies equality
752 pairs
= pairs
[2:] + pairs
[:2]
753 od2
= OrderedDict(pairs
)
754 self
.assertNotEqual(od1
, od2
) # different order implies inequality
755 # comparison to regular dict is not order sensitive
756 self
.assertEqual(od1
, dict(od2
))
757 self
.assertEqual(dict(od2
), od1
)
758 # different length implied inequality
759 self
.assertNotEqual(od1
, OrderedDict(pairs
[:-1]))
761 def test_copying(self
):
762 # Check that ordered dicts are copyable, deepcopyable, picklable,
763 # and have a repr/eval round-trip
764 pairs
= [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
765 od
= OrderedDict(pairs
)
766 update_test
= OrderedDict()
767 update_test
.update(od
)
768 for i
, dup
in enumerate([
772 pickle
.loads(pickle
.dumps(od
, 0)),
773 pickle
.loads(pickle
.dumps(od
, 1)),
774 pickle
.loads(pickle
.dumps(od
, 2)),
775 pickle
.loads(pickle
.dumps(od
, 3)),
776 pickle
.loads(pickle
.dumps(od
, -1)),
781 self
.assert_(dup
is not od
)
782 self
.assertEquals(dup
, od
)
783 self
.assertEquals(list(dup
.items()), list(od
.items()))
784 self
.assertEquals(len(dup
), len(od
))
785 self
.assertEquals(type(dup
), type(od
))
787 def test_yaml_linkage(self
):
788 # Verify that __reduce__ is setup in a way that supports PyYAML's dump() feature.
789 # In yaml, lists are native but tuples are not.
790 pairs
= [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
791 od
= OrderedDict(pairs
)
793 # '!!python/object/apply:__main__.OrderedDict\n- - [a, 1]\n - [b, 2]\n'
794 self
.assert_(all(type(pair
)==list for pair
in od
.__reduce
__()[1]))
796 def test_reduce_not_too_fat(self
):
797 # do not save instance dictionary if not needed
798 pairs
= [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
799 od
= OrderedDict(pairs
)
800 self
.assertEqual(len(od
.__reduce
__()), 2)
802 self
.assertEqual(len(od
.__reduce
__()), 3)
805 od
= OrderedDict([('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)])
806 self
.assertEqual(repr(od
),
807 "OrderedDict([('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)])")
808 self
.assertEqual(eval(repr(od
)), od
)
809 self
.assertEqual(repr(OrderedDict()), "OrderedDict()")
811 def test_setdefault(self
):
812 pairs
= [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
814 od
= OrderedDict(pairs
)
815 pair_order
= list(od
.items())
816 self
.assertEqual(od
.setdefault('a', 10), 3)
817 # make sure order didn't change
818 self
.assertEqual(list(od
.items()), pair_order
)
819 self
.assertEqual(od
.setdefault('x', 10), 10)
820 # make sure 'x' is added to the end
821 self
.assertEqual(list(od
.items())[-1], ('x', 10))
823 def test_reinsert(self
):
824 # Given insert a, insert b, delete a, re-insert a,
825 # verify that a is now later than b.
831 self
.assertEqual(list(od
.items()), [('b', 2), ('a', 1)])
835 class GeneralMappingTests(mapping_tests
.BasicTestMappingProtocol
):
836 type2test
= OrderedDict
838 def test_popitem(self
):
839 d
= self
._empty
_mapping
()
840 self
.assertRaises(KeyError, d
.popitem
)
842 class MyOrderedDict(OrderedDict
):
845 class SubclassMappingTests(mapping_tests
.BasicTestMappingProtocol
):
846 type2test
= MyOrderedDict
848 def test_popitem(self
):
849 d
= self
._empty
_mapping
()
850 self
.assertRaises(KeyError, d
.popitem
)
853 import doctest
, collections
855 def test_main(verbose
=None):
856 NamedTupleDocs
= doctest
.DocTestSuite(module
=collections
)
857 test_classes
= [TestNamedTuple
, NamedTupleDocs
, TestOneTrickPonyABCs
,
858 TestCollectionABCs
, TestCounter
,
859 TestOrderedDict
, GeneralMappingTests
, SubclassMappingTests
]
860 support
.run_unittest(*test_classes
)
861 support
.run_doctest(collections
, verbose
)
864 if __name__
== "__main__":
865 test_main(verbose
=True)