source: python/trunk/Lib/test/test_collections.py

Last change on this file was 391, checked in by dmik, 11 years ago

python: Merge vendor 2.7.6 to trunk.

  • Property svn:eol-style set to native
File size: 42.9 KB
Line 
1
2import unittest, doctest, operator
3import inspect
4from test import test_support
5from collections import namedtuple, Counter, OrderedDict
6from test import mapping_tests
7import pickle, cPickle, copy
8from random import randrange, shuffle
9import keyword
10import re
11import sys
12from collections import Hashable, Iterable, Iterator
13from collections import Sized, Container, Callable
14from collections import Set, MutableSet
15from collections import Mapping, MutableMapping
16from collections import Sequence, MutableSequence
17
18TestNT = namedtuple('TestNT', 'x y z') # type used for pickle tests
19
20py273_named_tuple_pickle = '''\
21ccopy_reg
22_reconstructor
23p0
24(ctest.test_collections
25TestNT
26p1
27c__builtin__
28tuple
29p2
30(I10
31I20
32I30
33tp3
34tp4
35Rp5
36ccollections
37OrderedDict
38p6
39((lp7
40(lp8
41S'x'
42p9
43aI10
44aa(lp10
45S'y'
46p11
47aI20
48aa(lp12
49S'z'
50p13
51aI30
52aatp14
53Rp15
54b.
55'''
56
57class TestNamedTuple(unittest.TestCase):
58
59 def test_factory(self):
60 Point = namedtuple('Point', 'x y')
61 self.assertEqual(Point.__name__, 'Point')
62 self.assertEqual(Point.__slots__, ())
63 self.assertEqual(Point.__module__, __name__)
64 self.assertEqual(Point.__getitem__, tuple.__getitem__)
65 self.assertEqual(Point._fields, ('x', 'y'))
66
67 self.assertRaises(ValueError, namedtuple, 'abc%', 'efg ghi') # type has non-alpha char
68 self.assertRaises(ValueError, namedtuple, 'class', 'efg ghi') # type has keyword
69 self.assertRaises(ValueError, namedtuple, '9abc', 'efg ghi') # type starts with digit
70
71 self.assertRaises(ValueError, namedtuple, 'abc', 'efg g%hi') # field with non-alpha char
72 self.assertRaises(ValueError, namedtuple, 'abc', 'abc class') # field has keyword
73 self.assertRaises(ValueError, namedtuple, 'abc', '8efg 9ghi') # field starts with digit
74 self.assertRaises(ValueError, namedtuple, 'abc', '_efg ghi') # field with leading underscore
75 self.assertRaises(ValueError, namedtuple, 'abc', 'efg efg ghi') # duplicate field
76
77 namedtuple('Point0', 'x1 y2') # Verify that numbers are allowed in names
78 namedtuple('_', 'a b c') # Test leading underscores in a typename
79
80 nt = namedtuple('nt', u'the quick brown fox') # check unicode input
81 self.assertNotIn("u'", repr(nt._fields))
82 nt = namedtuple('nt', (u'the', u'quick')) # check unicode input
83 self.assertNotIn("u'", repr(nt._fields))
84
85 self.assertRaises(TypeError, Point._make, [11]) # catch too few args
86 self.assertRaises(TypeError, Point._make, [11, 22, 33]) # catch too many args
87
88 @unittest.skipIf(sys.flags.optimize >= 2,
89 "Docstrings are omitted with -O2 and above")
90 def test_factory_doc_attr(self):
91 Point = namedtuple('Point', 'x y')
92 self.assertEqual(Point.__doc__, 'Point(x, y)')
93
94 def test_name_fixer(self):
95 for spec, renamed in [
96 [('efg', 'g%hi'), ('efg', '_1')], # field with non-alpha char
97 [('abc', 'class'), ('abc', '_1')], # field has keyword
98 [('8efg', '9ghi'), ('_0', '_1')], # field starts with digit
99 [('abc', '_efg'), ('abc', '_1')], # field with leading underscore
100 [('abc', 'efg', 'efg', 'ghi'), ('abc', 'efg', '_2', 'ghi')], # duplicate field
101 [('abc', '', 'x'), ('abc', '_1', 'x')], # fieldname is a space
102 ]:
103 self.assertEqual(namedtuple('NT', spec, rename=True)._fields, renamed)
104
105 def test_instance(self):
106 Point = namedtuple('Point', 'x y')
107 p = Point(11, 22)
108 self.assertEqual(p, Point(x=11, y=22))
109 self.assertEqual(p, Point(11, y=22))
110 self.assertEqual(p, Point(y=22, x=11))
111 self.assertEqual(p, Point(*(11, 22)))
112 self.assertEqual(p, Point(**dict(x=11, y=22)))
113 self.assertRaises(TypeError, Point, 1) # too few args
114 self.assertRaises(TypeError, Point, 1, 2, 3) # too many args
115 self.assertRaises(TypeError, eval, 'Point(XXX=1, y=2)', locals()) # wrong keyword argument
116 self.assertRaises(TypeError, eval, 'Point(x=1)', locals()) # missing keyword argument
117 self.assertEqual(repr(p), 'Point(x=11, y=22)')
118 self.assertNotIn('__weakref__', dir(p))
119 self.assertEqual(p, Point._make([11, 22])) # test _make classmethod
120 self.assertEqual(p._fields, ('x', 'y')) # test _fields attribute
121 self.assertEqual(p._replace(x=1), (1, 22)) # test _replace method
122 self.assertEqual(p._asdict(), dict(x=11, y=22)) # test _asdict method
123 self.assertEqual(vars(p), p._asdict()) # verify that vars() works
124
125 try:
126 p._replace(x=1, error=2)
127 except ValueError:
128 pass
129 else:
130 self._fail('Did not detect an incorrect fieldname')
131
132 # verify that field string can have commas
133 Point = namedtuple('Point', 'x, y')
134 p = Point(x=11, y=22)
135 self.assertEqual(repr(p), 'Point(x=11, y=22)')
136
137 # verify that fieldspec can be a non-string sequence
138 Point = namedtuple('Point', ('x', 'y'))
139 p = Point(x=11, y=22)
140 self.assertEqual(repr(p), 'Point(x=11, y=22)')
141
142 def test_tupleness(self):
143 Point = namedtuple('Point', 'x y')
144 p = Point(11, 22)
145
146 self.assertIsInstance(p, tuple)
147 self.assertEqual(p, (11, 22)) # matches a real tuple
148 self.assertEqual(tuple(p), (11, 22)) # coercable to a real tuple
149 self.assertEqual(list(p), [11, 22]) # coercable to a list
150 self.assertEqual(max(p), 22) # iterable
151 self.assertEqual(max(*p), 22) # star-able
152 x, y = p
153 self.assertEqual(p, (x, y)) # unpacks like a tuple
154 self.assertEqual((p[0], p[1]), (11, 22)) # indexable like a tuple
155 self.assertRaises(IndexError, p.__getitem__, 3)
156
157 self.assertEqual(p.x, x)
158 self.assertEqual(p.y, y)
159 self.assertRaises(AttributeError, eval, 'p.z', locals())
160
161 def test_odd_sizes(self):
162 Zero = namedtuple('Zero', '')
163 self.assertEqual(Zero(), ())
164 self.assertEqual(Zero._make([]), ())
165 self.assertEqual(repr(Zero()), 'Zero()')
166 self.assertEqual(Zero()._asdict(), {})
167 self.assertEqual(Zero()._fields, ())
168
169 Dot = namedtuple('Dot', 'd')
170 self.assertEqual(Dot(1), (1,))
171 self.assertEqual(Dot._make([1]), (1,))
172 self.assertEqual(Dot(1).d, 1)
173 self.assertEqual(repr(Dot(1)), 'Dot(d=1)')
174 self.assertEqual(Dot(1)._asdict(), {'d':1})
175 self.assertEqual(Dot(1)._replace(d=999), (999,))
176 self.assertEqual(Dot(1)._fields, ('d',))
177
178 n = 5000
179 import string, random
180 names = list(set(''.join([random.choice(string.ascii_letters)
181 for j in range(10)]) for i in range(n)))
182 n = len(names)
183 Big = namedtuple('Big', names)
184 b = Big(*range(n))
185 self.assertEqual(b, tuple(range(n)))
186 self.assertEqual(Big._make(range(n)), tuple(range(n)))
187 for pos, name in enumerate(names):
188 self.assertEqual(getattr(b, name), pos)
189 repr(b) # make sure repr() doesn't blow-up
190 d = b._asdict()
191 d_expected = dict(zip(names, range(n)))
192 self.assertEqual(d, d_expected)
193 b2 = b._replace(**dict([(names[1], 999),(names[-5], 42)]))
194 b2_expected = range(n)
195 b2_expected[1] = 999
196 b2_expected[-5] = 42
197 self.assertEqual(b2, tuple(b2_expected))
198 self.assertEqual(b._fields, tuple(names))
199
200 def test_pickle(self):
201 p = TestNT(x=10, y=20, z=30)
202 for module in pickle, cPickle:
203 loads = getattr(module, 'loads')
204 dumps = getattr(module, 'dumps')
205 for protocol in -1, 0, 1, 2:
206 q = loads(dumps(p, protocol))
207 self.assertEqual(p, q)
208 self.assertEqual(p._fields, q._fields)
209
210 def test_copy(self):
211 p = TestNT(x=10, y=20, z=30)
212 for copier in copy.copy, copy.deepcopy:
213 q = copier(p)
214 self.assertEqual(p, q)
215 self.assertEqual(p._fields, q._fields)
216
217 def test_name_conflicts(self):
218 # Some names like "self", "cls", "tuple", "itemgetter", and "property"
219 # failed when used as field names. Test to make sure these now work.
220 T = namedtuple('T', 'itemgetter property self cls tuple')
221 t = T(1, 2, 3, 4, 5)
222 self.assertEqual(t, (1,2,3,4,5))
223 newt = t._replace(itemgetter=10, property=20, self=30, cls=40, tuple=50)
224 self.assertEqual(newt, (10,20,30,40,50))
225
226 # Broader test of all interesting names in a template
227 with test_support.captured_stdout() as template:
228 T = namedtuple('T', 'x', verbose=True)
229 words = set(re.findall('[A-Za-z]+', template.getvalue()))
230 words -= set(keyword.kwlist)
231 T = namedtuple('T', words)
232 # test __new__
233 values = tuple(range(len(words)))
234 t = T(*values)
235 self.assertEqual(t, values)
236 t = T(**dict(zip(T._fields, values)))
237 self.assertEqual(t, values)
238 # test _make
239 t = T._make(values)
240 self.assertEqual(t, values)
241 # exercise __repr__
242 repr(t)
243 # test _asdict
244 self.assertEqual(t._asdict(), dict(zip(T._fields, values)))
245 # test _replace
246 t = T._make(values)
247 newvalues = tuple(v*10 for v in values)
248 newt = t._replace(**dict(zip(T._fields, newvalues)))
249 self.assertEqual(newt, newvalues)
250 # test _fields
251 self.assertEqual(T._fields, tuple(words))
252 # test __getnewargs__
253 self.assertEqual(t.__getnewargs__(), values)
254
255 def test_pickling_bug_18015(self):
256 # http://bugs.python.org/issue18015
257 pt = pickle.loads(py273_named_tuple_pickle)
258 self.assertEqual(pt.x, 10)
259
260class ABCTestCase(unittest.TestCase):
261
262 def validate_abstract_methods(self, abc, *names):
263 methodstubs = dict.fromkeys(names, lambda s, *args: 0)
264
265 # everything should work will all required methods are present
266 C = type('C', (abc,), methodstubs)
267 C()
268
269 # instantiation should fail if a required method is missing
270 for name in names:
271 stubs = methodstubs.copy()
272 del stubs[name]
273 C = type('C', (abc,), stubs)
274 self.assertRaises(TypeError, C, name)
275
276 def validate_isinstance(self, abc, name):
277 stub = lambda s, *args: 0
278
279 # new-style class
280 C = type('C', (object,), {name: stub})
281 self.assertIsInstance(C(), abc)
282 self.assertTrue(issubclass(C, abc))
283 # old-style class
284 class C: pass
285 setattr(C, name, stub)
286 self.assertIsInstance(C(), abc)
287 self.assertTrue(issubclass(C, abc))
288
289 # new-style class
290 C = type('C', (object,), {'__hash__': None})
291 self.assertNotIsInstance(C(), abc)
292 self.assertFalse(issubclass(C, abc))
293 # old-style class
294 class C: pass
295 self.assertNotIsInstance(C(), abc)
296 self.assertFalse(issubclass(C, abc))
297
298 def validate_comparison(self, instance):
299 ops = ['lt', 'gt', 'le', 'ge', 'ne', 'or', 'and', 'xor', 'sub']
300 operators = {}
301 for op in ops:
302 name = '__' + op + '__'
303 operators[name] = getattr(operator, name)
304
305 class Other:
306 def __init__(self):
307 self.right_side = False
308 def __eq__(self, other):
309 self.right_side = True
310 return True
311 __lt__ = __eq__
312 __gt__ = __eq__
313 __le__ = __eq__
314 __ge__ = __eq__
315 __ne__ = __eq__
316 __ror__ = __eq__
317 __rand__ = __eq__
318 __rxor__ = __eq__
319 __rsub__ = __eq__
320
321 for name, op in operators.items():
322 if not hasattr(instance, name):
323 continue
324 other = Other()
325 op(instance, other)
326 self.assertTrue(other.right_side,'Right side not called for %s.%s'
327 % (type(instance), name))
328
329class TestOneTrickPonyABCs(ABCTestCase):
330
331 def test_Hashable(self):
332 # Check some non-hashables
333 non_samples = [list(), set(), dict()]
334 for x in non_samples:
335 self.assertNotIsInstance(x, Hashable)
336 self.assertFalse(issubclass(type(x), Hashable), repr(type(x)))
337 # Check some hashables
338 samples = [None,
339 int(), float(), complex(),
340 str(),
341 tuple(), frozenset(),
342 int, list, object, type,
343 ]
344 for x in samples:
345 self.assertIsInstance(x, Hashable)
346 self.assertTrue(issubclass(type(x), Hashable), repr(type(x)))
347 self.assertRaises(TypeError, Hashable)
348 # Check direct subclassing
349 class H(Hashable):
350 def __hash__(self):
351 return super(H, self).__hash__()
352 __eq__ = Hashable.__eq__ # Silence Py3k warning
353 self.assertEqual(hash(H()), 0)
354 self.assertFalse(issubclass(int, H))
355 self.validate_abstract_methods(Hashable, '__hash__')
356 self.validate_isinstance(Hashable, '__hash__')
357
358 def test_Iterable(self):
359 # Check some non-iterables
360 non_samples = [None, 42, 3.14, 1j]
361 for x in non_samples:
362 self.assertNotIsInstance(x, Iterable)
363 self.assertFalse(issubclass(type(x), Iterable), repr(type(x)))
364 # Check some iterables
365 samples = [str(),
366 tuple(), list(), set(), frozenset(), dict(),
367 dict().keys(), dict().items(), dict().values(),
368 (lambda: (yield))(),
369 (x for x in []),
370 ]
371 for x in samples:
372 self.assertIsInstance(x, Iterable)
373 self.assertTrue(issubclass(type(x), Iterable), repr(type(x)))
374 # Check direct subclassing
375 class I(Iterable):
376 def __iter__(self):
377 return super(I, self).__iter__()
378 self.assertEqual(list(I()), [])
379 self.assertFalse(issubclass(str, I))
380 self.validate_abstract_methods(Iterable, '__iter__')
381 self.validate_isinstance(Iterable, '__iter__')
382
383 def test_Iterator(self):
384 non_samples = [None, 42, 3.14, 1j, "".encode('ascii'), "", (), [],
385 {}, set()]
386 for x in non_samples:
387 self.assertNotIsInstance(x, Iterator)
388 self.assertFalse(issubclass(type(x), Iterator), repr(type(x)))
389 samples = [iter(str()),
390 iter(tuple()), iter(list()), iter(dict()),
391 iter(set()), iter(frozenset()),
392 iter(dict().keys()), iter(dict().items()),
393 iter(dict().values()),
394 (lambda: (yield))(),
395 (x for x in []),
396 ]
397 for x in samples:
398 self.assertIsInstance(x, Iterator)
399 self.assertTrue(issubclass(type(x), Iterator), repr(type(x)))
400 self.validate_abstract_methods(Iterator, 'next', '__iter__')
401
402 # Issue 10565
403 class NextOnly:
404 def __next__(self):
405 yield 1
406 raise StopIteration
407 self.assertNotIsInstance(NextOnly(), Iterator)
408 class NextOnlyNew(object):
409 def __next__(self):
410 yield 1
411 raise StopIteration
412 self.assertNotIsInstance(NextOnlyNew(), Iterator)
413
414 def test_Sized(self):
415 non_samples = [None, 42, 3.14, 1j,
416 (lambda: (yield))(),
417 (x for x in []),
418 ]
419 for x in non_samples:
420 self.assertNotIsInstance(x, Sized)
421 self.assertFalse(issubclass(type(x), Sized), repr(type(x)))
422 samples = [str(),
423 tuple(), list(), set(), frozenset(), dict(),
424 dict().keys(), dict().items(), dict().values(),
425 ]
426 for x in samples:
427 self.assertIsInstance(x, Sized)
428 self.assertTrue(issubclass(type(x), Sized), repr(type(x)))
429 self.validate_abstract_methods(Sized, '__len__')
430 self.validate_isinstance(Sized, '__len__')
431
432 def test_Container(self):
433 non_samples = [None, 42, 3.14, 1j,
434 (lambda: (yield))(),
435 (x for x in []),
436 ]
437 for x in non_samples:
438 self.assertNotIsInstance(x, Container)
439 self.assertFalse(issubclass(type(x), Container), repr(type(x)))
440 samples = [str(),
441 tuple(), list(), set(), frozenset(), dict(),
442 dict().keys(), dict().items(),
443 ]
444 for x in samples:
445 self.assertIsInstance(x, Container)
446 self.assertTrue(issubclass(type(x), Container), repr(type(x)))
447 self.validate_abstract_methods(Container, '__contains__')
448 self.validate_isinstance(Container, '__contains__')
449
450 def test_Callable(self):
451 non_samples = [None, 42, 3.14, 1j,
452 "", "".encode('ascii'), (), [], {}, set(),
453 (lambda: (yield))(),
454 (x for x in []),
455 ]
456 for x in non_samples:
457 self.assertNotIsInstance(x, Callable)
458 self.assertFalse(issubclass(type(x), Callable), repr(type(x)))
459 samples = [lambda: None,
460 type, int, object,
461 len,
462 list.append, [].append,
463 ]
464 for x in samples:
465 self.assertIsInstance(x, Callable)
466 self.assertTrue(issubclass(type(x), Callable), repr(type(x)))
467 self.validate_abstract_methods(Callable, '__call__')
468 self.validate_isinstance(Callable, '__call__')
469
470 def test_direct_subclassing(self):
471 for B in Hashable, Iterable, Iterator, Sized, Container, Callable:
472 class C(B):
473 pass
474 self.assertTrue(issubclass(C, B))
475 self.assertFalse(issubclass(int, C))
476
477 def test_registration(self):
478 for B in Hashable, Iterable, Iterator, Sized, Container, Callable:
479 class C:
480 __metaclass__ = type
481 __hash__ = None # Make sure it isn't hashable by default
482 self.assertFalse(issubclass(C, B), B.__name__)
483 B.register(C)
484 self.assertTrue(issubclass(C, B))
485
486class WithSet(MutableSet):
487
488 def __init__(self, it=()):
489 self.data = set(it)
490
491 def __len__(self):
492 return len(self.data)
493
494 def __iter__(self):
495 return iter(self.data)
496
497 def __contains__(self, item):
498 return item in self.data
499
500 def add(self, item):
501 self.data.add(item)
502
503 def discard(self, item):
504 self.data.discard(item)
505
506class TestCollectionABCs(ABCTestCase):
507
508 # XXX For now, we only test some virtual inheritance properties.
509 # We should also test the proper behavior of the collection ABCs
510 # as real base classes or mix-in classes.
511
512 def test_Set(self):
513 for sample in [set, frozenset]:
514 self.assertIsInstance(sample(), Set)
515 self.assertTrue(issubclass(sample, Set))
516 self.validate_abstract_methods(Set, '__contains__', '__iter__', '__len__')
517 class MySet(Set):
518 def __contains__(self, x):
519 return False
520 def __len__(self):
521 return 0
522 def __iter__(self):
523 return iter([])
524 self.validate_comparison(MySet())
525
526 def test_hash_Set(self):
527 class OneTwoThreeSet(Set):
528 def __init__(self):
529 self.contents = [1, 2, 3]
530 def __contains__(self, x):
531 return x in self.contents
532 def __len__(self):
533 return len(self.contents)
534 def __iter__(self):
535 return iter(self.contents)
536 def __hash__(self):
537 return self._hash()
538 a, b = OneTwoThreeSet(), OneTwoThreeSet()
539 self.assertTrue(hash(a) == hash(b))
540
541 def test_MutableSet(self):
542 self.assertIsInstance(set(), MutableSet)
543 self.assertTrue(issubclass(set, MutableSet))
544 self.assertNotIsInstance(frozenset(), MutableSet)
545 self.assertFalse(issubclass(frozenset, MutableSet))
546 self.validate_abstract_methods(MutableSet, '__contains__', '__iter__', '__len__',
547 'add', 'discard')
548
549 def test_issue_5647(self):
550 # MutableSet.__iand__ mutated the set during iteration
551 s = WithSet('abcd')
552 s &= WithSet('cdef') # This used to fail
553 self.assertEqual(set(s), set('cd'))
554
555 def test_issue_4920(self):
556 # MutableSet.pop() method did not work
557 class MySet(collections.MutableSet):
558 __slots__=['__s']
559 def __init__(self,items=None):
560 if items is None:
561 items=[]
562 self.__s=set(items)
563 def __contains__(self,v):
564 return v in self.__s
565 def __iter__(self):
566 return iter(self.__s)
567 def __len__(self):
568 return len(self.__s)
569 def add(self,v):
570 result=v not in self.__s
571 self.__s.add(v)
572 return result
573 def discard(self,v):
574 result=v in self.__s
575 self.__s.discard(v)
576 return result
577 def __repr__(self):
578 return "MySet(%s)" % repr(list(self))
579 s = MySet([5,43,2,1])
580 self.assertEqual(s.pop(), 1)
581
582 def test_issue8750(self):
583 empty = WithSet()
584 full = WithSet(range(10))
585 s = WithSet(full)
586 s -= s
587 self.assertEqual(s, empty)
588 s = WithSet(full)
589 s ^= s
590 self.assertEqual(s, empty)
591 s = WithSet(full)
592 s &= s
593 self.assertEqual(s, full)
594 s |= s
595 self.assertEqual(s, full)
596
597 def test_Mapping(self):
598 for sample in [dict]:
599 self.assertIsInstance(sample(), Mapping)
600 self.assertTrue(issubclass(sample, Mapping))
601 self.validate_abstract_methods(Mapping, '__contains__', '__iter__', '__len__',
602 '__getitem__')
603 class MyMapping(collections.Mapping):
604 def __len__(self):
605 return 0
606 def __getitem__(self, i):
607 raise IndexError
608 def __iter__(self):
609 return iter(())
610 self.validate_comparison(MyMapping())
611
612 def test_MutableMapping(self):
613 for sample in [dict]:
614 self.assertIsInstance(sample(), MutableMapping)
615 self.assertTrue(issubclass(sample, MutableMapping))
616 self.validate_abstract_methods(MutableMapping, '__contains__', '__iter__', '__len__',
617 '__getitem__', '__setitem__', '__delitem__')
618
619 def test_Sequence(self):
620 for sample in [tuple, list, str]:
621 self.assertIsInstance(sample(), Sequence)
622 self.assertTrue(issubclass(sample, Sequence))
623 self.assertTrue(issubclass(basestring, Sequence))
624 self.assertIsInstance(range(10), Sequence)
625 self.assertTrue(issubclass(xrange, Sequence))
626 self.assertTrue(issubclass(str, Sequence))
627 self.validate_abstract_methods(Sequence, '__contains__', '__iter__', '__len__',
628 '__getitem__')
629
630 def test_MutableSequence(self):
631 for sample in [tuple, str]:
632 self.assertNotIsInstance(sample(), MutableSequence)
633 self.assertFalse(issubclass(sample, MutableSequence))
634 for sample in [list]:
635 self.assertIsInstance(sample(), MutableSequence)
636 self.assertTrue(issubclass(sample, MutableSequence))
637 self.assertFalse(issubclass(basestring, MutableSequence))
638 self.validate_abstract_methods(MutableSequence, '__contains__', '__iter__',
639 '__len__', '__getitem__', '__setitem__', '__delitem__', 'insert')
640
641class TestCounter(unittest.TestCase):
642
643 def test_basics(self):
644 c = Counter('abcaba')
645 self.assertEqual(c, Counter({'a':3 , 'b': 2, 'c': 1}))
646 self.assertEqual(c, Counter(a=3, b=2, c=1))
647 self.assertIsInstance(c, dict)
648 self.assertIsInstance(c, Mapping)
649 self.assertTrue(issubclass(Counter, dict))
650 self.assertTrue(issubclass(Counter, Mapping))
651 self.assertEqual(len(c), 3)
652 self.assertEqual(sum(c.values()), 6)
653 self.assertEqual(sorted(c.values()), [1, 2, 3])
654 self.assertEqual(sorted(c.keys()), ['a', 'b', 'c'])
655 self.assertEqual(sorted(c), ['a', 'b', 'c'])
656 self.assertEqual(sorted(c.items()),
657 [('a', 3), ('b', 2), ('c', 1)])
658 self.assertEqual(c['b'], 2)
659 self.assertEqual(c['z'], 0)
660 with test_support.check_py3k_warnings():
661 self.assertEqual(c.has_key('c'), True)
662 self.assertEqual(c.has_key('z'), False)
663 self.assertEqual(c.__contains__('c'), True)
664 self.assertEqual(c.__contains__('z'), False)
665 self.assertEqual(c.get('b', 10), 2)
666 self.assertEqual(c.get('z', 10), 10)
667 self.assertEqual(c, dict(a=3, b=2, c=1))
668 self.assertEqual(repr(c), "Counter({'a': 3, 'b': 2, 'c': 1})")
669 self.assertEqual(c.most_common(), [('a', 3), ('b', 2), ('c', 1)])
670 for i in range(5):
671 self.assertEqual(c.most_common(i),
672 [('a', 3), ('b', 2), ('c', 1)][:i])
673 self.assertEqual(''.join(sorted(c.elements())), 'aaabbc')
674 c['a'] += 1 # increment an existing value
675 c['b'] -= 2 # sub existing value to zero
676 del c['c'] # remove an entry
677 del c['c'] # make sure that del doesn't raise KeyError
678 c['d'] -= 2 # sub from a missing value
679 c['e'] = -5 # directly assign a missing value
680 c['f'] += 4 # add to a missing value
681 self.assertEqual(c, dict(a=4, b=0, d=-2, e=-5, f=4))
682 self.assertEqual(''.join(sorted(c.elements())), 'aaaaffff')
683 self.assertEqual(c.pop('f'), 4)
684 self.assertNotIn('f', c)
685 for i in range(3):
686 elem, cnt = c.popitem()
687 self.assertNotIn(elem, c)
688 c.clear()
689 self.assertEqual(c, {})
690 self.assertEqual(repr(c), 'Counter()')
691 self.assertRaises(NotImplementedError, Counter.fromkeys, 'abc')
692 self.assertRaises(TypeError, hash, c)
693 c.update(dict(a=5, b=3))
694 c.update(c=1)
695 c.update(Counter('a' * 50 + 'b' * 30))
696 c.update() # test case with no args
697 c.__init__('a' * 500 + 'b' * 300)
698 c.__init__('cdc')
699 c.__init__()
700 self.assertEqual(c, dict(a=555, b=333, c=3, d=1))
701 self.assertEqual(c.setdefault('d', 5), 1)
702 self.assertEqual(c['d'], 1)
703 self.assertEqual(c.setdefault('e', 5), 5)
704 self.assertEqual(c['e'], 5)
705
706 def test_copying(self):
707 # Check that counters are copyable, deepcopyable, picklable, and
708 #have a repr/eval round-trip
709 words = Counter('which witch had which witches wrist watch'.split())
710 update_test = Counter()
711 update_test.update(words)
712 for i, dup in enumerate([
713 words.copy(),
714 copy.copy(words),
715 copy.deepcopy(words),
716 pickle.loads(pickle.dumps(words, 0)),
717 pickle.loads(pickle.dumps(words, 1)),
718 pickle.loads(pickle.dumps(words, 2)),
719 pickle.loads(pickle.dumps(words, -1)),
720 cPickle.loads(cPickle.dumps(words, 0)),
721 cPickle.loads(cPickle.dumps(words, 1)),
722 cPickle.loads(cPickle.dumps(words, 2)),
723 cPickle.loads(cPickle.dumps(words, -1)),
724 eval(repr(words)),
725 update_test,
726 Counter(words),
727 ]):
728 msg = (i, dup, words)
729 self.assertTrue(dup is not words)
730 self.assertEqual(dup, words)
731 self.assertEqual(len(dup), len(words))
732 self.assertEqual(type(dup), type(words))
733
734 def test_copy_subclass(self):
735 class MyCounter(Counter):
736 pass
737 c = MyCounter('slartibartfast')
738 d = c.copy()
739 self.assertEqual(d, c)
740 self.assertEqual(len(d), len(c))
741 self.assertEqual(type(d), type(c))
742
743 def test_conversions(self):
744 # Convert to: set, list, dict
745 s = 'she sells sea shells by the sea shore'
746 self.assertEqual(sorted(Counter(s).elements()), sorted(s))
747 self.assertEqual(sorted(Counter(s)), sorted(set(s)))
748 self.assertEqual(dict(Counter(s)), dict(Counter(s).items()))
749 self.assertEqual(set(Counter(s)), set(s))
750
751 def test_invariant_for_the_in_operator(self):
752 c = Counter(a=10, b=-2, c=0)
753 for elem in c:
754 self.assertTrue(elem in c)
755 self.assertIn(elem, c)
756
757 def test_multiset_operations(self):
758 # Verify that adding a zero counter will strip zeros and negatives
759 c = Counter(a=10, b=-2, c=0) + Counter()
760 self.assertEqual(dict(c), dict(a=10))
761
762 elements = 'abcd'
763 for i in range(1000):
764 # test random pairs of multisets
765 p = Counter(dict((elem, randrange(-2,4)) for elem in elements))
766 p.update(e=1, f=-1, g=0)
767 q = Counter(dict((elem, randrange(-2,4)) for elem in elements))
768 q.update(h=1, i=-1, j=0)
769 for counterop, numberop in [
770 (Counter.__add__, lambda x, y: max(0, x+y)),
771 (Counter.__sub__, lambda x, y: max(0, x-y)),
772 (Counter.__or__, lambda x, y: max(0,x,y)),
773 (Counter.__and__, lambda x, y: max(0, min(x,y))),
774 ]:
775 result = counterop(p, q)
776 for x in elements:
777 self.assertEqual(numberop(p[x], q[x]), result[x],
778 (counterop, x, p, q))
779 # verify that results exclude non-positive counts
780 self.assertTrue(x>0 for x in result.values())
781
782 elements = 'abcdef'
783 for i in range(100):
784 # verify that random multisets with no repeats are exactly like sets
785 p = Counter(dict((elem, randrange(0, 2)) for elem in elements))
786 q = Counter(dict((elem, randrange(0, 2)) for elem in elements))
787 for counterop, setop in [
788 (Counter.__sub__, set.__sub__),
789 (Counter.__or__, set.__or__),
790 (Counter.__and__, set.__and__),
791 ]:
792 counter_result = counterop(p, q)
793 set_result = setop(set(p.elements()), set(q.elements()))
794 self.assertEqual(counter_result, dict.fromkeys(set_result, 1))
795
796 def test_subtract(self):
797 c = Counter(a=-5, b=0, c=5, d=10, e=15,g=40)
798 c.subtract(a=1, b=2, c=-3, d=10, e=20, f=30, h=-50)
799 self.assertEqual(c, Counter(a=-6, b=-2, c=8, d=0, e=-5, f=-30, g=40, h=50))
800 c = Counter(a=-5, b=0, c=5, d=10, e=15,g=40)
801 c.subtract(Counter(a=1, b=2, c=-3, d=10, e=20, f=30, h=-50))
802 self.assertEqual(c, Counter(a=-6, b=-2, c=8, d=0, e=-5, f=-30, g=40, h=50))
803 c = Counter('aaabbcd')
804 c.subtract('aaaabbcce')
805 self.assertEqual(c, Counter(a=-1, b=0, c=-1, d=1, e=-1))
806
807class TestOrderedDict(unittest.TestCase):
808
809 def test_init(self):
810 with self.assertRaises(TypeError):
811 OrderedDict([('a', 1), ('b', 2)], None) # too many args
812 pairs = [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)]
813 self.assertEqual(sorted(OrderedDict(dict(pairs)).items()), pairs) # dict input
814 self.assertEqual(sorted(OrderedDict(**dict(pairs)).items()), pairs) # kwds input
815 self.assertEqual(list(OrderedDict(pairs).items()), pairs) # pairs input
816 self.assertEqual(list(OrderedDict([('a', 1), ('b', 2), ('c', 9), ('d', 4)],
817 c=3, e=5).items()), pairs) # mixed input
818
819 # make sure no positional args conflict with possible kwdargs
820 self.assertEqual(inspect.getargspec(OrderedDict.__dict__['__init__']).args,
821 ['self'])
822
823 # Make sure that direct calls to __init__ do not clear previous contents
824 d = OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 44), ('e', 55)])
825 d.__init__([('e', 5), ('f', 6)], g=7, d=4)
826 self.assertEqual(list(d.items()),
827 [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5), ('f', 6), ('g', 7)])
828
829 def test_update(self):
830 with self.assertRaises(TypeError):
831 OrderedDict().update([('a', 1), ('b', 2)], None) # too many args
832 pairs = [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)]
833 od = OrderedDict()
834 od.update(dict(pairs))
835 self.assertEqual(sorted(od.items()), pairs) # dict input
836 od = OrderedDict()
837 od.update(**dict(pairs))
838 self.assertEqual(sorted(od.items()), pairs) # kwds input
839 od = OrderedDict()
840 od.update(pairs)
841 self.assertEqual(list(od.items()), pairs) # pairs input
842 od = OrderedDict()
843 od.update([('a', 1), ('b', 2), ('c', 9), ('d', 4)], c=3, e=5)
844 self.assertEqual(list(od.items()), pairs) # mixed input
845
846 # Issue 9137: Named argument called 'other' or 'self'
847 # shouldn't be treated specially.
848 od = OrderedDict()
849 od.update(self=23)
850 self.assertEqual(list(od.items()), [('self', 23)])
851 od = OrderedDict()
852 od.update(other={})
853 self.assertEqual(list(od.items()), [('other', {})])
854 od = OrderedDict()
855 od.update(red=5, blue=6, other=7, self=8)
856 self.assertEqual(sorted(list(od.items())),
857 [('blue', 6), ('other', 7), ('red', 5), ('self', 8)])
858
859 # Make sure that direct calls to update do not clear previous contents
860 # add that updates items are not moved to the end
861 d = OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 44), ('e', 55)])
862 d.update([('e', 5), ('f', 6)], g=7, d=4)
863 self.assertEqual(list(d.items()),
864 [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5), ('f', 6), ('g', 7)])
865
866 def test_abc(self):
867 self.assertIsInstance(OrderedDict(), MutableMapping)
868 self.assertTrue(issubclass(OrderedDict, MutableMapping))
869
870 def test_clear(self):
871 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
872 shuffle(pairs)
873 od = OrderedDict(pairs)
874 self.assertEqual(len(od), len(pairs))
875 od.clear()
876 self.assertEqual(len(od), 0)
877
878 def test_delitem(self):
879 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
880 od = OrderedDict(pairs)
881 del od['a']
882 self.assertNotIn('a', od)
883 with self.assertRaises(KeyError):
884 del od['a']
885 self.assertEqual(list(od.items()), pairs[:2] + pairs[3:])
886
887 def test_setitem(self):
888 od = OrderedDict([('d', 1), ('b', 2), ('c', 3), ('a', 4), ('e', 5)])
889 od['c'] = 10 # existing element
890 od['f'] = 20 # new element
891 self.assertEqual(list(od.items()),
892 [('d', 1), ('b', 2), ('c', 10), ('a', 4), ('e', 5), ('f', 20)])
893
894 def test_iterators(self):
895 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
896 shuffle(pairs)
897 od = OrderedDict(pairs)
898 self.assertEqual(list(od), [t[0] for t in pairs])
899 self.assertEqual(od.keys()[:], [t[0] for t in pairs])
900 self.assertEqual(od.values()[:], [t[1] for t in pairs])
901 self.assertEqual(od.items()[:], pairs)
902 self.assertEqual(list(od.iterkeys()), [t[0] for t in pairs])
903 self.assertEqual(list(od.itervalues()), [t[1] for t in pairs])
904 self.assertEqual(list(od.iteritems()), pairs)
905 self.assertEqual(list(reversed(od)),
906 [t[0] for t in reversed(pairs)])
907
908 def test_popitem(self):
909 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
910 shuffle(pairs)
911 od = OrderedDict(pairs)
912 while pairs:
913 self.assertEqual(od.popitem(), pairs.pop())
914 with self.assertRaises(KeyError):
915 od.popitem()
916 self.assertEqual(len(od), 0)
917
918 def test_pop(self):
919 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
920 shuffle(pairs)
921 od = OrderedDict(pairs)
922 shuffle(pairs)
923 while pairs:
924 k, v = pairs.pop()
925 self.assertEqual(od.pop(k), v)
926 with self.assertRaises(KeyError):
927 od.pop('xyz')
928 self.assertEqual(len(od), 0)
929 self.assertEqual(od.pop(k, 12345), 12345)
930
931 # make sure pop still works when __missing__ is defined
932 class Missing(OrderedDict):
933 def __missing__(self, key):
934 return 0
935 m = Missing(a=1)
936 self.assertEqual(m.pop('b', 5), 5)
937 self.assertEqual(m.pop('a', 6), 1)
938 self.assertEqual(m.pop('a', 6), 6)
939 with self.assertRaises(KeyError):
940 m.pop('a')
941
942 def test_equality(self):
943 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
944 shuffle(pairs)
945 od1 = OrderedDict(pairs)
946 od2 = OrderedDict(pairs)
947 self.assertEqual(od1, od2) # same order implies equality
948 pairs = pairs[2:] + pairs[:2]
949 od2 = OrderedDict(pairs)
950 self.assertNotEqual(od1, od2) # different order implies inequality
951 # comparison to regular dict is not order sensitive
952 self.assertEqual(od1, dict(od2))
953 self.assertEqual(dict(od2), od1)
954 # different length implied inequality
955 self.assertNotEqual(od1, OrderedDict(pairs[:-1]))
956
957 def test_copying(self):
958 # Check that ordered dicts are copyable, deepcopyable, picklable,
959 # and have a repr/eval round-trip
960 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
961 od = OrderedDict(pairs)
962 update_test = OrderedDict()
963 update_test.update(od)
964 for i, dup in enumerate([
965 od.copy(),
966 copy.copy(od),
967 copy.deepcopy(od),
968 pickle.loads(pickle.dumps(od, 0)),
969 pickle.loads(pickle.dumps(od, 1)),
970 pickle.loads(pickle.dumps(od, 2)),
971 pickle.loads(pickle.dumps(od, -1)),
972 eval(repr(od)),
973 update_test,
974 OrderedDict(od),
975 ]):
976 self.assertTrue(dup is not od)
977 self.assertEqual(dup, od)
978 self.assertEqual(list(dup.items()), list(od.items()))
979 self.assertEqual(len(dup), len(od))
980 self.assertEqual(type(dup), type(od))
981
982 def test_yaml_linkage(self):
983 # Verify that __reduce__ is setup in a way that supports PyYAML's dump() feature.
984 # In yaml, lists are native but tuples are not.
985 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
986 od = OrderedDict(pairs)
987 # yaml.dump(od) -->
988 # '!!python/object/apply:__main__.OrderedDict\n- - [a, 1]\n - [b, 2]\n'
989 self.assertTrue(all(type(pair)==list for pair in od.__reduce__()[1]))
990
991 def test_reduce_not_too_fat(self):
992 # do not save instance dictionary if not needed
993 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
994 od = OrderedDict(pairs)
995 self.assertEqual(len(od.__reduce__()), 2)
996 od.x = 10
997 self.assertEqual(len(od.__reduce__()), 3)
998
999 def test_repr(self):
1000 od = OrderedDict([('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)])
1001 self.assertEqual(repr(od),
1002 "OrderedDict([('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)])")
1003 self.assertEqual(eval(repr(od)), od)
1004 self.assertEqual(repr(OrderedDict()), "OrderedDict()")
1005
1006 def test_repr_recursive(self):
1007 # See issue #9826
1008 od = OrderedDict.fromkeys('abc')
1009 od['x'] = od
1010 self.assertEqual(repr(od),
1011 "OrderedDict([('a', None), ('b', None), ('c', None), ('x', ...)])")
1012
1013 def test_setdefault(self):
1014 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
1015 shuffle(pairs)
1016 od = OrderedDict(pairs)
1017 pair_order = list(od.items())
1018 self.assertEqual(od.setdefault('a', 10), 3)
1019 # make sure order didn't change
1020 self.assertEqual(list(od.items()), pair_order)
1021 self.assertEqual(od.setdefault('x', 10), 10)
1022 # make sure 'x' is added to the end
1023 self.assertEqual(list(od.items())[-1], ('x', 10))
1024
1025 # make sure setdefault still works when __missing__ is defined
1026 class Missing(OrderedDict):
1027 def __missing__(self, key):
1028 return 0
1029 self.assertEqual(Missing().setdefault(5, 9), 9)
1030
1031 def test_reinsert(self):
1032 # Given insert a, insert b, delete a, re-insert a,
1033 # verify that a is now later than b.
1034 od = OrderedDict()
1035 od['a'] = 1
1036 od['b'] = 2
1037 del od['a']
1038 od['a'] = 1
1039 self.assertEqual(list(od.items()), [('b', 2), ('a', 1)])
1040
1041 def test_views(self):
1042 s = 'the quick brown fox jumped over a lazy dog yesterday before dawn'.split()
1043 od = OrderedDict.fromkeys(s)
1044 self.assertEqual(list(od.viewkeys()), s)
1045 self.assertEqual(list(od.viewvalues()), [None for k in s])
1046 self.assertEqual(list(od.viewitems()), [(k, None) for k in s])
1047
1048 def test_override_update(self):
1049 # Verify that subclasses can override update() without breaking __init__()
1050 class MyOD(OrderedDict):
1051 def update(self, *args, **kwds):
1052 raise Exception()
1053 items = [('a', 1), ('c', 3), ('b', 2)]
1054 self.assertEqual(list(MyOD(items).items()), items)
1055
1056class GeneralMappingTests(mapping_tests.BasicTestMappingProtocol):
1057 type2test = OrderedDict
1058
1059 def test_popitem(self):
1060 d = self._empty_mapping()
1061 self.assertRaises(KeyError, d.popitem)
1062
1063class MyOrderedDict(OrderedDict):
1064 pass
1065
1066class SubclassMappingTests(mapping_tests.BasicTestMappingProtocol):
1067 type2test = MyOrderedDict
1068
1069 def test_popitem(self):
1070 d = self._empty_mapping()
1071 self.assertRaises(KeyError, d.popitem)
1072
1073import collections
1074
1075def test_main(verbose=None):
1076 NamedTupleDocs = doctest.DocTestSuite(module=collections)
1077 test_classes = [TestNamedTuple, NamedTupleDocs, TestOneTrickPonyABCs,
1078 TestCollectionABCs, TestCounter,
1079 TestOrderedDict, GeneralMappingTests, SubclassMappingTests]
1080 test_support.run_unittest(*test_classes)
1081 test_support.run_doctest(collections, verbose)
1082
1083if __name__ == "__main__":
1084 test_main(verbose=True)
Note: See TracBrowser for help on using the repository browser.