blob: a94b5da860f75d12eeb2612e812a296a159aa82a [file] [log] [blame]
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001"""Unit tests for collections.py."""
2
Benjamin Peterson4ad6bd52010-05-21 20:55:22 +00003import unittest, doctest, operator
Raymond Hettingerf6d3e8e2011-03-23 20:33:30 -07004from test.support import TESTFN, forget, unlink
Raymond Hettinger2d32f632009-03-02 21:24:57 +00005import inspect
Benjamin Petersonee8712c2008-05-20 21:35:26 +00006from test import support
Raymond Hettinger426e0522011-01-03 02:12:02 +00007from collections import namedtuple, Counter, OrderedDict, _count_elements
Raymond Hettinger2d32f632009-03-02 21:24:57 +00008from test import mapping_tests
Georg Brandlc28e1fa2008-06-10 19:20:26 +00009import pickle, copy
Raymond Hettinger2d32f632009-03-02 21:24:57 +000010from random import randrange, shuffle
Raymond Hettinger499b2ee2009-05-27 01:53:46 +000011import keyword
12import re
R. David Murray378c0cf2010-02-24 01:46:21 +000013import sys
Raymond Hettinger57d1a882011-02-23 00:46:28 +000014from collections import UserDict
Raymond Hettinger9fe1ccf2011-02-26 01:02:51 +000015from collections import ChainMap
Raymond Hettinger57d1a882011-02-23 00:46:28 +000016from collections.abc import Hashable, Iterable, Iterator
17from collections.abc import Sized, Container, Callable
18from collections.abc import Set, MutableSet
19from collections.abc import Mapping, MutableMapping, KeysView, ItemsView
20from collections.abc import Sequence, MutableSequence
21from collections.abc import ByteString
Guido van Rossumcd16bf62007-06-13 18:07:49 +000022
Raymond Hettinger499e1932011-02-23 07:56:53 +000023
24################################################################################
Raymond Hettinger9fe1ccf2011-02-26 01:02:51 +000025### ChainMap (helper class for configparser and the string module)
Raymond Hettinger499e1932011-02-23 07:56:53 +000026################################################################################
27
28class TestChainMap(unittest.TestCase):
29
30 def test_basics(self):
31 c = ChainMap()
32 c['a'] = 1
33 c['b'] = 2
34 d = c.new_child()
35 d['b'] = 20
36 d['c'] = 30
37 self.assertEqual(d.maps, [{'b':20, 'c':30}, {'a':1, 'b':2}]) # check internal state
38 self.assertEqual(d.items(), dict(a=1, b=20, c=30).items()) # check items/iter/getitem
39 self.assertEqual(len(d), 3) # check len
40 for key in 'abc': # check contains
41 self.assertIn(key, d)
42 for k, v in dict(a=1, b=20, c=30, z=100).items(): # check get
43 self.assertEqual(d.get(k, 100), v)
44
45 del d['b'] # unmask a value
46 self.assertEqual(d.maps, [{'c':30}, {'a':1, 'b':2}]) # check internal state
47 self.assertEqual(d.items(), dict(a=1, b=2, c=30).items()) # check items/iter/getitem
48 self.assertEqual(len(d), 3) # check len
49 for key in 'abc': # check contains
50 self.assertIn(key, d)
51 for k, v in dict(a=1, b=2, c=30, z=100).items(): # check get
52 self.assertEqual(d.get(k, 100), v)
53 self.assertIn(repr(d), [ # check repr
54 type(d).__name__ + "({'c': 30}, {'a': 1, 'b': 2})",
55 type(d).__name__ + "({'c': 30}, {'b': 2, 'a': 1})"
56 ])
57
58 for e in d.copy(), copy.copy(d): # check shallow copies
59 self.assertEqual(d, e)
60 self.assertEqual(d.maps, e.maps)
61 self.assertIsNot(d, e)
62 self.assertIsNot(d.maps[0], e.maps[0])
63 for m1, m2 in zip(d.maps[1:], e.maps[1:]):
64 self.assertIs(m1, m2)
65
Serhiy Storchakabad12572014-12-15 14:03:42 +020066 # check deep copies
67 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
68 e = pickle.loads(pickle.dumps(d, proto))
69 self.assertEqual(d, e)
70 self.assertEqual(d.maps, e.maps)
71 self.assertIsNot(d, e)
72 for m1, m2 in zip(d.maps, e.maps):
73 self.assertIsNot(m1, m2, e)
74 for e in [copy.deepcopy(d),
Raymond Hettinger499e1932011-02-23 07:56:53 +000075 eval(repr(d))
Serhiy Storchakabad12572014-12-15 14:03:42 +020076 ]:
Raymond Hettinger499e1932011-02-23 07:56:53 +000077 self.assertEqual(d, e)
78 self.assertEqual(d.maps, e.maps)
79 self.assertIsNot(d, e)
80 for m1, m2 in zip(d.maps, e.maps):
81 self.assertIsNot(m1, m2, e)
82
Raymond Hettingerd0321312011-02-26 06:53:58 +000083 f = d.new_child()
84 f['b'] = 5
85 self.assertEqual(f.maps, [{'b': 5}, {'c':30}, {'a':1, 'b':2}])
86 self.assertEqual(f.parents.maps, [{'c':30}, {'a':1, 'b':2}]) # check parents
87 self.assertEqual(f['b'], 5) # find first in chain
88 self.assertEqual(f.parents['b'], 2) # look beyond maps[0]
Raymond Hettinger499e1932011-02-23 07:56:53 +000089
90 def test_contructor(self):
Raymond Hettingerd0321312011-02-26 06:53:58 +000091 self.assertEqual(ChainMap().maps, [{}]) # no-args --> one new dict
Raymond Hettinger499e1932011-02-23 07:56:53 +000092 self.assertEqual(ChainMap({1:2}).maps, [{1:2}]) # 1 arg --> list
93
Raymond Hettingerd0321312011-02-26 06:53:58 +000094 def test_bool(self):
95 self.assertFalse(ChainMap())
96 self.assertFalse(ChainMap({}, {}))
97 self.assertTrue(ChainMap({1:2}, {}))
98 self.assertTrue(ChainMap({}, {1:2}))
99
Raymond Hettinger499e1932011-02-23 07:56:53 +0000100 def test_missing(self):
101 class DefaultChainMap(ChainMap):
102 def __missing__(self, key):
103 return 999
104 d = DefaultChainMap(dict(a=1, b=2), dict(b=20, c=30))
105 for k, v in dict(a=1, b=2, c=30, d=999).items():
106 self.assertEqual(d[k], v) # check __getitem__ w/missing
107 for k, v in dict(a=1, b=2, c=30, d=77).items():
108 self.assertEqual(d.get(k, 77), v) # check get() w/ missing
109 for k, v in dict(a=True, b=True, c=True, d=False).items():
110 self.assertEqual(k in d, v) # check __contains__ w/missing
111 self.assertEqual(d.pop('a', 1001), 1, d)
112 self.assertEqual(d.pop('a', 1002), 1002) # check pop() w/missing
113 self.assertEqual(d.popitem(), ('b', 2)) # check popitem() w/missing
114 with self.assertRaises(KeyError):
115 d.popitem()
116
117 def test_dict_coercion(self):
118 d = ChainMap(dict(a=1, b=2), dict(b=20, c=30))
119 self.assertEqual(dict(d), dict(a=1, b=2, c=30))
120 self.assertEqual(dict(d.items()), dict(a=1, b=2, c=30))
121
Vinay Sajip1ba81ee2013-01-11 23:39:53 +0000122 def test_new_child(self):
123 'Tests for changes for issue #16613.'
124 c = ChainMap()
125 c['a'] = 1
126 c['b'] = 2
127 m = {'b':20, 'c': 30}
128 d = c.new_child(m)
129 self.assertEqual(d.maps, [{'b':20, 'c':30}, {'a':1, 'b':2}]) # check internal state
130 self.assertIs(m, d.maps[0])
131
132 # Use a different map than a dict
133 class lowerdict(dict):
134 def __getitem__(self, key):
135 if isinstance(key, str):
136 key = key.lower()
137 return dict.__getitem__(self, key)
138 def __contains__(self, key):
139 if isinstance(key, str):
140 key = key.lower()
141 return dict.__contains__(self, key)
142
143 c = ChainMap()
144 c['a'] = 1
145 c['b'] = 2
146 m = lowerdict(b=20, c=30)
147 d = c.new_child(m)
148 self.assertIs(m, d.maps[0])
149 for key in 'abc': # check contains
150 self.assertIn(key, d)
151 for k, v in dict(a=1, B=20, C=30, z=100).items(): # check get
152 self.assertEqual(d.get(k, 100), v)
153
Raymond Hettinger499e1932011-02-23 07:56:53 +0000154
155################################################################################
156### Named Tuples
157################################################################################
158
Georg Brandlc28e1fa2008-06-10 19:20:26 +0000159TestNT = namedtuple('TestNT', 'x y z') # type used for pickle tests
Guido van Rossumd8faa362007-04-27 19:54:29 +0000160
161class TestNamedTuple(unittest.TestCase):
162
163 def test_factory(self):
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000164 Point = namedtuple('Point', 'x y')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000165 self.assertEqual(Point.__name__, 'Point')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000166 self.assertEqual(Point.__slots__, ())
167 self.assertEqual(Point.__module__, __name__)
168 self.assertEqual(Point.__getitem__, tuple.__getitem__)
Christian Heimesfaf2f632008-01-06 16:59:19 +0000169 self.assertEqual(Point._fields, ('x', 'y'))
Raymond Hettinger2ebea412011-03-23 12:52:23 -0700170 self.assertIn('class Point(tuple)', Point._source)
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000171
172 self.assertRaises(ValueError, namedtuple, 'abc%', 'efg ghi') # type has non-alpha char
173 self.assertRaises(ValueError, namedtuple, 'class', 'efg ghi') # type has keyword
174 self.assertRaises(ValueError, namedtuple, '9abc', 'efg ghi') # type starts with digit
175
176 self.assertRaises(ValueError, namedtuple, 'abc', 'efg g%hi') # field with non-alpha char
177 self.assertRaises(ValueError, namedtuple, 'abc', 'abc class') # field has keyword
178 self.assertRaises(ValueError, namedtuple, 'abc', '8efg 9ghi') # field starts with digit
Christian Heimes0449f632007-12-15 01:27:15 +0000179 self.assertRaises(ValueError, namedtuple, 'abc', '_efg ghi') # field with leading underscore
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000180 self.assertRaises(ValueError, namedtuple, 'abc', 'efg efg ghi') # duplicate field
181
182 namedtuple('Point0', 'x1 y2') # Verify that numbers are allowed in names
Christian Heimes0449f632007-12-15 01:27:15 +0000183 namedtuple('_', 'a b c') # Test leading underscores in a typename
Guido van Rossumd8faa362007-04-27 19:54:29 +0000184
Benjamin Petersone9bbc8b2008-09-28 02:06:32 +0000185 nt = namedtuple('nt', 'the quick brown fox') # check unicode input
Benjamin Peterson577473f2010-01-19 00:09:57 +0000186 self.assertNotIn("u'", repr(nt._fields))
Benjamin Petersone9bbc8b2008-09-28 02:06:32 +0000187 nt = namedtuple('nt', ('the', 'quick')) # check unicode input
Benjamin Peterson577473f2010-01-19 00:09:57 +0000188 self.assertNotIn("u'", repr(nt._fields))
Benjamin Petersone9bbc8b2008-09-28 02:06:32 +0000189
Christian Heimesfaf2f632008-01-06 16:59:19 +0000190 self.assertRaises(TypeError, Point._make, [11]) # catch too few args
191 self.assertRaises(TypeError, Point._make, [11, 22, 33]) # catch too many args
192
R. David Murray378c0cf2010-02-24 01:46:21 +0000193 @unittest.skipIf(sys.flags.optimize >= 2,
194 "Docstrings are omitted with -O2 and above")
195 def test_factory_doc_attr(self):
196 Point = namedtuple('Point', 'x y')
197 self.assertEqual(Point.__doc__, 'Point(x, y)')
198
Benjamin Petersona86f2c02009-02-10 02:41:10 +0000199 def test_name_fixer(self):
200 for spec, renamed in [
Raymond Hettinger56145242009-04-02 22:31:59 +0000201 [('efg', 'g%hi'), ('efg', '_1')], # field with non-alpha char
202 [('abc', 'class'), ('abc', '_1')], # field has keyword
203 [('8efg', '9ghi'), ('_0', '_1')], # field starts with digit
204 [('abc', '_efg'), ('abc', '_1')], # field with leading underscore
205 [('abc', 'efg', 'efg', 'ghi'), ('abc', 'efg', '_2', 'ghi')], # duplicate field
206 [('abc', '', 'x'), ('abc', '_1', 'x')], # fieldname is a space
Benjamin Petersona86f2c02009-02-10 02:41:10 +0000207 ]:
208 self.assertEqual(namedtuple('NT', spec, rename=True)._fields, renamed)
209
Guido van Rossumd8faa362007-04-27 19:54:29 +0000210 def test_instance(self):
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000211 Point = namedtuple('Point', 'x y')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000212 p = Point(11, 22)
213 self.assertEqual(p, Point(x=11, y=22))
214 self.assertEqual(p, Point(11, y=22))
215 self.assertEqual(p, Point(y=22, x=11))
216 self.assertEqual(p, Point(*(11, 22)))
217 self.assertEqual(p, Point(**dict(x=11, y=22)))
218 self.assertRaises(TypeError, Point, 1) # too few args
219 self.assertRaises(TypeError, Point, 1, 2, 3) # too many args
220 self.assertRaises(TypeError, eval, 'Point(XXX=1, y=2)', locals()) # wrong keyword argument
221 self.assertRaises(TypeError, eval, 'Point(x=1)', locals()) # missing keyword argument
222 self.assertEqual(repr(p), 'Point(x=11, y=22)')
Benjamin Peterson577473f2010-01-19 00:09:57 +0000223 self.assertNotIn('__weakref__', dir(p))
Christian Heimesfaf2f632008-01-06 16:59:19 +0000224 self.assertEqual(p, Point._make([11, 22])) # test _make classmethod
Christian Heimes0449f632007-12-15 01:27:15 +0000225 self.assertEqual(p._fields, ('x', 'y')) # test _fields attribute
226 self.assertEqual(p._replace(x=1), (1, 22)) # test _replace method
Raymond Hettinger163e9822013-05-18 00:05:20 -0700227 self.assertEqual(p._asdict(), dict(x=11, y=22)) # test _asdict method
228 self.assertEqual(vars(p), p._asdict()) # verify that vars() works
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000229
Guido van Rossum3d392eb2007-11-16 00:35:22 +0000230 try:
Christian Heimesfaf2f632008-01-06 16:59:19 +0000231 p._replace(x=1, error=2)
232 except ValueError:
Guido van Rossum3d392eb2007-11-16 00:35:22 +0000233 pass
234 else:
Christian Heimesfaf2f632008-01-06 16:59:19 +0000235 self._fail('Did not detect an incorrect fieldname')
Guido van Rossum3d392eb2007-11-16 00:35:22 +0000236
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000237 # verify that field string can have commas
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000238 Point = namedtuple('Point', 'x, y')
239 p = Point(x=11, y=22)
240 self.assertEqual(repr(p), 'Point(x=11, y=22)')
241
242 # verify that fieldspec can be a non-string sequence
243 Point = namedtuple('Point', ('x', 'y'))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000244 p = Point(x=11, y=22)
245 self.assertEqual(repr(p), 'Point(x=11, y=22)')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000246
247 def test_tupleness(self):
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000248 Point = namedtuple('Point', 'x y')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000249 p = Point(11, 22)
250
Ezio Melottie9615932010-01-24 19:26:24 +0000251 self.assertIsInstance(p, tuple)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000252 self.assertEqual(p, (11, 22)) # matches a real tuple
253 self.assertEqual(tuple(p), (11, 22)) # coercable to a real tuple
254 self.assertEqual(list(p), [11, 22]) # coercable to a list
255 self.assertEqual(max(p), 22) # iterable
256 self.assertEqual(max(*p), 22) # star-able
257 x, y = p
258 self.assertEqual(p, (x, y)) # unpacks like a tuple
259 self.assertEqual((p[0], p[1]), (11, 22)) # indexable like a tuple
260 self.assertRaises(IndexError, p.__getitem__, 3)
261
262 self.assertEqual(p.x, x)
263 self.assertEqual(p.y, y)
264 self.assertRaises(AttributeError, eval, 'p.z', locals())
265
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000266 def test_odd_sizes(self):
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000267 Zero = namedtuple('Zero', '')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000268 self.assertEqual(Zero(), ())
Christian Heimesfaf2f632008-01-06 16:59:19 +0000269 self.assertEqual(Zero._make([]), ())
Christian Heimes99170a52007-12-19 02:07:34 +0000270 self.assertEqual(repr(Zero()), 'Zero()')
271 self.assertEqual(Zero()._asdict(), {})
272 self.assertEqual(Zero()._fields, ())
273
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000274 Dot = namedtuple('Dot', 'd')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000275 self.assertEqual(Dot(1), (1,))
Christian Heimesfaf2f632008-01-06 16:59:19 +0000276 self.assertEqual(Dot._make([1]), (1,))
Christian Heimes99170a52007-12-19 02:07:34 +0000277 self.assertEqual(Dot(1).d, 1)
278 self.assertEqual(repr(Dot(1)), 'Dot(d=1)')
279 self.assertEqual(Dot(1)._asdict(), {'d':1})
280 self.assertEqual(Dot(1)._replace(d=999), (999,))
281 self.assertEqual(Dot(1)._fields, ('d',))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000282
Georg Brandlc28e1fa2008-06-10 19:20:26 +0000283 # n = 5000
Christian Heimes99170a52007-12-19 02:07:34 +0000284 n = 254 # SyntaxError: more than 255 arguments:
285 import string, random
Georg Brandlb533e262008-05-25 18:19:30 +0000286 names = list(set(''.join([random.choice(string.ascii_letters)
287 for j in range(10)]) for i in range(n)))
288 n = len(names)
Christian Heimes99170a52007-12-19 02:07:34 +0000289 Big = namedtuple('Big', names)
290 b = Big(*range(n))
291 self.assertEqual(b, tuple(range(n)))
Christian Heimesfaf2f632008-01-06 16:59:19 +0000292 self.assertEqual(Big._make(range(n)), tuple(range(n)))
Christian Heimes99170a52007-12-19 02:07:34 +0000293 for pos, name in enumerate(names):
294 self.assertEqual(getattr(b, name), pos)
295 repr(b) # make sure repr() doesn't blow-up
296 d = b._asdict()
297 d_expected = dict(zip(names, range(n)))
298 self.assertEqual(d, d_expected)
299 b2 = b._replace(**dict([(names[1], 999),(names[-5], 42)]))
300 b2_expected = list(range(n))
301 b2_expected[1] = 999
302 b2_expected[-5] = 42
303 self.assertEqual(b2, tuple(b2_expected))
304 self.assertEqual(b._fields, tuple(names))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000305
Georg Brandlc28e1fa2008-06-10 19:20:26 +0000306 def test_pickle(self):
307 p = TestNT(x=10, y=20, z=30)
308 for module in (pickle,):
309 loads = getattr(module, 'loads')
310 dumps = getattr(module, 'dumps')
Eric V. Smith4d5d69d2014-02-05 10:33:14 -0500311 for protocol in range(-1, module.HIGHEST_PROTOCOL + 1):
Georg Brandlc28e1fa2008-06-10 19:20:26 +0000312 q = loads(dumps(p, protocol))
313 self.assertEqual(p, q)
314 self.assertEqual(p._fields, q._fields)
Raymond Hettingerb98dcc12013-05-03 02:24:15 -0700315 self.assertNotIn(b'OrderedDict', dumps(p, protocol))
Georg Brandlc28e1fa2008-06-10 19:20:26 +0000316
317 def test_copy(self):
318 p = TestNT(x=10, y=20, z=30)
319 for copier in copy.copy, copy.deepcopy:
320 q = copier(p)
321 self.assertEqual(p, q)
322 self.assertEqual(p._fields, q._fields)
323
Raymond Hettinger089ba7f2009-05-27 00:38:24 +0000324 def test_name_conflicts(self):
325 # Some names like "self", "cls", "tuple", "itemgetter", and "property"
326 # failed when used as field names. Test to make sure these now work.
327 T = namedtuple('T', 'itemgetter property self cls tuple')
328 t = T(1, 2, 3, 4, 5)
329 self.assertEqual(t, (1,2,3,4,5))
330 newt = t._replace(itemgetter=10, property=20, self=30, cls=40, tuple=50)
331 self.assertEqual(newt, (10,20,30,40,50))
332
Raymond Hettinger499b2ee2009-05-27 01:53:46 +0000333 # Broader test of all interesting names in a template
334 with support.captured_stdout() as template:
335 T = namedtuple('T', 'x', verbose=True)
336 words = set(re.findall('[A-Za-z]+', template.getvalue()))
337 words -= set(keyword.kwlist)
338 T = namedtuple('T', words)
339 # test __new__
340 values = tuple(range(len(words)))
341 t = T(*values)
342 self.assertEqual(t, values)
343 t = T(**dict(zip(T._fields, values)))
344 self.assertEqual(t, values)
345 # test _make
346 t = T._make(values)
347 self.assertEqual(t, values)
348 # exercise __repr__
349 repr(t)
350 # test _asdict
351 self.assertEqual(t._asdict(), dict(zip(T._fields, values)))
352 # test _replace
353 t = T._make(values)
354 newvalues = tuple(v*10 for v in values)
355 newt = t._replace(**dict(zip(T._fields, newvalues)))
356 self.assertEqual(newt, newvalues)
357 # test _fields
358 self.assertEqual(T._fields, tuple(words))
359 # test __getnewargs__
360 self.assertEqual(t.__getnewargs__(), values)
361
Raymond Hettingerd331ce92010-08-08 01:13:42 +0000362 def test_repr(self):
363 with support.captured_stdout() as template:
364 A = namedtuple('A', 'x', verbose=True)
365 self.assertEqual(repr(A(1)), 'A(x=1)')
366 # repr should show the name of the subclass
367 class B(A):
368 pass
369 self.assertEqual(repr(B(1)), 'B(x=1)')
370
Raymond Hettingerf6d3e8e2011-03-23 20:33:30 -0700371 def test_source(self):
372 # verify that _source can be run through exec()
Raymond Hettingerd4652fa2011-03-24 09:45:43 -0700373 tmp = namedtuple('NTColor', 'red green blue')
374 globals().pop('NTColor', None) # remove artifacts from other tests
Raymond Hettingerf6d3e8e2011-03-23 20:33:30 -0700375 exec(tmp._source, globals())
Raymond Hettingerd4652fa2011-03-24 09:45:43 -0700376 self.assertIn('NTColor', globals())
377 c = NTColor(10, 20, 30)
Raymond Hettingerf6d3e8e2011-03-23 20:33:30 -0700378 self.assertEqual((c.red, c.green, c.blue), (10, 20, 30))
Raymond Hettingerd4652fa2011-03-24 09:45:43 -0700379 self.assertEqual(NTColor._fields, ('red', 'green', 'blue'))
380 globals().pop('NTColor', None) # clean-up after this test
Raymond Hettingerf6d3e8e2011-03-23 20:33:30 -0700381
Raymond Hettingerd331ce92010-08-08 01:13:42 +0000382
Raymond Hettinger499e1932011-02-23 07:56:53 +0000383################################################################################
384### Abstract Base Classes
385################################################################################
386
Raymond Hettingerae650182009-01-28 23:33:59 +0000387class ABCTestCase(unittest.TestCase):
388
389 def validate_abstract_methods(self, abc, *names):
390 methodstubs = dict.fromkeys(names, lambda s, *args: 0)
391
392 # everything should work will all required methods are present
393 C = type('C', (abc,), methodstubs)
394 C()
395
396 # instantiation should fail if a required method is missing
397 for name in names:
398 stubs = methodstubs.copy()
399 del stubs[name]
400 C = type('C', (abc,), stubs)
401 self.assertRaises(TypeError, C, name)
402
Florent Xiclunace153f62010-03-08 15:34:35 +0000403 def validate_isinstance(self, abc, name):
404 stub = lambda s, *args: 0
405
406 C = type('C', (object,), {'__hash__': None})
407 setattr(C, name, stub)
408 self.assertIsInstance(C(), abc)
409 self.assertTrue(issubclass(C, abc))
410
411 C = type('C', (object,), {'__hash__': None})
412 self.assertNotIsInstance(C(), abc)
413 self.assertFalse(issubclass(C, abc))
Raymond Hettingerae650182009-01-28 23:33:59 +0000414
Benjamin Peterson4ad6bd52010-05-21 20:55:22 +0000415 def validate_comparison(self, instance):
416 ops = ['lt', 'gt', 'le', 'ge', 'ne', 'or', 'and', 'xor', 'sub']
417 operators = {}
418 for op in ops:
419 name = '__' + op + '__'
420 operators[name] = getattr(operator, name)
421
422 class Other:
423 def __init__(self):
424 self.right_side = False
425 def __eq__(self, other):
426 self.right_side = True
427 return True
428 __lt__ = __eq__
429 __gt__ = __eq__
430 __le__ = __eq__
431 __ge__ = __eq__
432 __ne__ = __eq__
433 __ror__ = __eq__
434 __rand__ = __eq__
435 __rxor__ = __eq__
436 __rsub__ = __eq__
437
438 for name, op in operators.items():
439 if not hasattr(instance, name):
440 continue
441 other = Other()
442 op(instance, other)
443 self.assertTrue(other.right_side,'Right side not called for %s.%s'
444 % (type(instance), name))
445
Raymond Hettingerae650182009-01-28 23:33:59 +0000446class TestOneTrickPonyABCs(ABCTestCase):
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000447
448 def test_Hashable(self):
449 # Check some non-hashables
Guido van Rossum254348e2007-11-21 19:29:53 +0000450 non_samples = [bytearray(), list(), set(), dict()]
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000451 for x in non_samples:
Ezio Melottie9615932010-01-24 19:26:24 +0000452 self.assertNotIsInstance(x, Hashable)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000453 self.assertFalse(issubclass(type(x), Hashable), repr(type(x)))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000454 # Check some hashables
455 samples = [None,
456 int(), float(), complex(),
Guido van Rossum07d4e782007-07-03 16:59:47 +0000457 str(),
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000458 tuple(), frozenset(),
Guido van Rossum98297ee2007-11-06 21:34:58 +0000459 int, list, object, type, bytes()
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000460 ]
461 for x in samples:
Ezio Melottie9615932010-01-24 19:26:24 +0000462 self.assertIsInstance(x, Hashable)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000463 self.assertTrue(issubclass(type(x), Hashable), repr(type(x)))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000464 self.assertRaises(TypeError, Hashable)
465 # Check direct subclassing
466 class H(Hashable):
467 def __hash__(self):
468 return super().__hash__()
469 self.assertEqual(hash(H()), 0)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000470 self.assertFalse(issubclass(int, H))
Raymond Hettingerae650182009-01-28 23:33:59 +0000471 self.validate_abstract_methods(Hashable, '__hash__')
Florent Xiclunace153f62010-03-08 15:34:35 +0000472 self.validate_isinstance(Hashable, '__hash__')
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000473
474 def test_Iterable(self):
475 # Check some non-iterables
476 non_samples = [None, 42, 3.14, 1j]
477 for x in non_samples:
Ezio Melottie9615932010-01-24 19:26:24 +0000478 self.assertNotIsInstance(x, Iterable)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000479 self.assertFalse(issubclass(type(x), Iterable), repr(type(x)))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000480 # Check some iterables
Guido van Rossum07d4e782007-07-03 16:59:47 +0000481 samples = [bytes(), str(),
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000482 tuple(), list(), set(), frozenset(), dict(),
483 dict().keys(), dict().items(), dict().values(),
484 (lambda: (yield))(),
485 (x for x in []),
486 ]
487 for x in samples:
Ezio Melottie9615932010-01-24 19:26:24 +0000488 self.assertIsInstance(x, Iterable)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000489 self.assertTrue(issubclass(type(x), Iterable), repr(type(x)))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000490 # Check direct subclassing
491 class I(Iterable):
492 def __iter__(self):
493 return super().__iter__()
494 self.assertEqual(list(I()), [])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000495 self.assertFalse(issubclass(str, I))
Raymond Hettingerae650182009-01-28 23:33:59 +0000496 self.validate_abstract_methods(Iterable, '__iter__')
Florent Xiclunace153f62010-03-08 15:34:35 +0000497 self.validate_isinstance(Iterable, '__iter__')
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000498
499 def test_Iterator(self):
Guido van Rossum07d4e782007-07-03 16:59:47 +0000500 non_samples = [None, 42, 3.14, 1j, b"", "", (), [], {}, set()]
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000501 for x in non_samples:
Ezio Melottie9615932010-01-24 19:26:24 +0000502 self.assertNotIsInstance(x, Iterator)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000503 self.assertFalse(issubclass(type(x), Iterator), repr(type(x)))
Guido van Rossum07d4e782007-07-03 16:59:47 +0000504 samples = [iter(bytes()), iter(str()),
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000505 iter(tuple()), iter(list()), iter(dict()),
506 iter(set()), iter(frozenset()),
507 iter(dict().keys()), iter(dict().items()),
508 iter(dict().values()),
509 (lambda: (yield))(),
510 (x for x in []),
511 ]
512 for x in samples:
Ezio Melottie9615932010-01-24 19:26:24 +0000513 self.assertIsInstance(x, Iterator)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000514 self.assertTrue(issubclass(type(x), Iterator), repr(type(x)))
Raymond Hettingeread22222010-11-29 03:56:12 +0000515 self.validate_abstract_methods(Iterator, '__next__', '__iter__')
516
517 # Issue 10565
518 class NextOnly:
519 def __next__(self):
520 yield 1
Raymond Hettingerbb6c0aa2014-11-22 22:14:41 -0800521 return
Raymond Hettingeread22222010-11-29 03:56:12 +0000522 self.assertNotIsInstance(NextOnly(), Iterator)
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000523
524 def test_Sized(self):
525 non_samples = [None, 42, 3.14, 1j,
526 (lambda: (yield))(),
527 (x for x in []),
528 ]
529 for x in non_samples:
Ezio Melottie9615932010-01-24 19:26:24 +0000530 self.assertNotIsInstance(x, Sized)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000531 self.assertFalse(issubclass(type(x), Sized), repr(type(x)))
Guido van Rossum07d4e782007-07-03 16:59:47 +0000532 samples = [bytes(), str(),
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000533 tuple(), list(), set(), frozenset(), dict(),
534 dict().keys(), dict().items(), dict().values(),
535 ]
536 for x in samples:
Ezio Melottie9615932010-01-24 19:26:24 +0000537 self.assertIsInstance(x, Sized)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000538 self.assertTrue(issubclass(type(x), Sized), repr(type(x)))
Raymond Hettingerae650182009-01-28 23:33:59 +0000539 self.validate_abstract_methods(Sized, '__len__')
Florent Xiclunace153f62010-03-08 15:34:35 +0000540 self.validate_isinstance(Sized, '__len__')
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000541
542 def test_Container(self):
543 non_samples = [None, 42, 3.14, 1j,
544 (lambda: (yield))(),
545 (x for x in []),
546 ]
547 for x in non_samples:
Ezio Melottie9615932010-01-24 19:26:24 +0000548 self.assertNotIsInstance(x, Container)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000549 self.assertFalse(issubclass(type(x), Container), repr(type(x)))
Guido van Rossum07d4e782007-07-03 16:59:47 +0000550 samples = [bytes(), str(),
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000551 tuple(), list(), set(), frozenset(), dict(),
552 dict().keys(), dict().items(),
553 ]
554 for x in samples:
Ezio Melottie9615932010-01-24 19:26:24 +0000555 self.assertIsInstance(x, Container)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000556 self.assertTrue(issubclass(type(x), Container), repr(type(x)))
Raymond Hettingerae650182009-01-28 23:33:59 +0000557 self.validate_abstract_methods(Container, '__contains__')
Florent Xiclunace153f62010-03-08 15:34:35 +0000558 self.validate_isinstance(Container, '__contains__')
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000559
560 def test_Callable(self):
561 non_samples = [None, 42, 3.14, 1j,
562 "", b"", (), [], {}, set(),
563 (lambda: (yield))(),
564 (x for x in []),
565 ]
566 for x in non_samples:
Ezio Melottie9615932010-01-24 19:26:24 +0000567 self.assertNotIsInstance(x, Callable)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000568 self.assertFalse(issubclass(type(x), Callable), repr(type(x)))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000569 samples = [lambda: None,
570 type, int, object,
571 len,
572 list.append, [].append,
573 ]
574 for x in samples:
Ezio Melottie9615932010-01-24 19:26:24 +0000575 self.assertIsInstance(x, Callable)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000576 self.assertTrue(issubclass(type(x), Callable), repr(type(x)))
Raymond Hettingerae650182009-01-28 23:33:59 +0000577 self.validate_abstract_methods(Callable, '__call__')
Florent Xiclunace153f62010-03-08 15:34:35 +0000578 self.validate_isinstance(Callable, '__call__')
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000579
580 def test_direct_subclassing(self):
581 for B in Hashable, Iterable, Iterator, Sized, Container, Callable:
582 class C(B):
583 pass
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000584 self.assertTrue(issubclass(C, B))
585 self.assertFalse(issubclass(int, C))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000586
587 def test_registration(self):
588 for B in Hashable, Iterable, Iterator, Sized, Container, Callable:
589 class C:
590 __hash__ = None # Make sure it isn't hashable by default
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000591 self.assertFalse(issubclass(C, B), B.__name__)
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000592 B.register(C)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000593 self.assertTrue(issubclass(C, B))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000594
Raymond Hettinger3f10a952009-04-01 19:05:50 +0000595class WithSet(MutableSet):
596
597 def __init__(self, it=()):
598 self.data = set(it)
599
600 def __len__(self):
601 return len(self.data)
602
603 def __iter__(self):
604 return iter(self.data)
605
606 def __contains__(self, item):
607 return item in self.data
608
609 def add(self, item):
610 self.data.add(item)
611
612 def discard(self, item):
613 self.data.discard(item)
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000614
Raymond Hettingerae650182009-01-28 23:33:59 +0000615class TestCollectionABCs(ABCTestCase):
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000616
617 # XXX For now, we only test some virtual inheritance properties.
618 # We should also test the proper behavior of the collection ABCs
619 # as real base classes or mix-in classes.
620
621 def test_Set(self):
622 for sample in [set, frozenset]:
Ezio Melottie9615932010-01-24 19:26:24 +0000623 self.assertIsInstance(sample(), Set)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000624 self.assertTrue(issubclass(sample, Set))
Raymond Hettingerae650182009-01-28 23:33:59 +0000625 self.validate_abstract_methods(Set, '__contains__', '__iter__', '__len__')
Benjamin Peterson4ad6bd52010-05-21 20:55:22 +0000626 class MySet(Set):
627 def __contains__(self, x):
628 return False
629 def __len__(self):
630 return 0
631 def __iter__(self):
632 return iter([])
633 self.validate_comparison(MySet())
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000634
Benjamin Peterson41181742008-07-02 20:22:54 +0000635 def test_hash_Set(self):
636 class OneTwoThreeSet(Set):
637 def __init__(self):
638 self.contents = [1, 2, 3]
639 def __contains__(self, x):
640 return x in self.contents
641 def __len__(self):
642 return len(self.contents)
643 def __iter__(self):
644 return iter(self.contents)
645 def __hash__(self):
646 return self._hash()
647 a, b = OneTwoThreeSet(), OneTwoThreeSet()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000648 self.assertTrue(hash(a) == hash(b))
Benjamin Peterson41181742008-07-02 20:22:54 +0000649
Raymond Hettinger2d452ee2014-05-25 18:28:39 -0700650 def test_isdisjoint_Set(self):
651 class MySet(Set):
652 def __init__(self, itr):
653 self.contents = itr
654 def __contains__(self, x):
655 return x in self.contents
656 def __iter__(self):
657 return iter(self.contents)
658 def __len__(self):
659 return len([x for x in self.contents])
660 s1 = MySet((1, 2, 3))
661 s2 = MySet((4, 5, 6))
662 s3 = MySet((1, 5, 6))
663 self.assertTrue(s1.isdisjoint(s2))
664 self.assertFalse(s1.isdisjoint(s3))
665
666 def test_equality_Set(self):
667 class MySet(Set):
668 def __init__(self, itr):
669 self.contents = itr
670 def __contains__(self, x):
671 return x in self.contents
672 def __iter__(self):
673 return iter(self.contents)
674 def __len__(self):
675 return len([x for x in self.contents])
676 s1 = MySet((1,))
677 s2 = MySet((1, 2))
678 s3 = MySet((3, 4))
679 s4 = MySet((3, 4))
680 self.assertTrue(s2 > s1)
681 self.assertTrue(s1 < s2)
682 self.assertFalse(s2 <= s1)
683 self.assertFalse(s2 <= s3)
684 self.assertFalse(s1 >= s2)
685 self.assertEqual(s3, s4)
686 self.assertNotEqual(s2, s3)
687
688 def test_arithmetic_Set(self):
689 class MySet(Set):
690 def __init__(self, itr):
691 self.contents = itr
692 def __contains__(self, x):
693 return x in self.contents
694 def __iter__(self):
695 return iter(self.contents)
696 def __len__(self):
697 return len([x for x in self.contents])
698 s1 = MySet((1, 2, 3))
699 s2 = MySet((3, 4, 5))
700 s3 = s1 & s2
701 self.assertEqual(s3, MySet((3,)))
702
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000703 def test_MutableSet(self):
Ezio Melottie9615932010-01-24 19:26:24 +0000704 self.assertIsInstance(set(), MutableSet)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000705 self.assertTrue(issubclass(set, MutableSet))
Ezio Melottie9615932010-01-24 19:26:24 +0000706 self.assertNotIsInstance(frozenset(), MutableSet)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000707 self.assertFalse(issubclass(frozenset, MutableSet))
Raymond Hettingerae650182009-01-28 23:33:59 +0000708 self.validate_abstract_methods(MutableSet, '__contains__', '__iter__', '__len__',
709 'add', 'discard')
710
Raymond Hettinger3f10a952009-04-01 19:05:50 +0000711 def test_issue_5647(self):
712 # MutableSet.__iand__ mutated the set during iteration
713 s = WithSet('abcd')
714 s &= WithSet('cdef') # This used to fail
715 self.assertEqual(set(s), set('cd'))
716
Raymond Hettingerae650182009-01-28 23:33:59 +0000717 def test_issue_4920(self):
718 # MutableSet.pop() method did not work
Raymond Hettinger57d1a882011-02-23 00:46:28 +0000719 class MySet(MutableSet):
Raymond Hettingerae650182009-01-28 23:33:59 +0000720 __slots__=['__s']
721 def __init__(self,items=None):
722 if items is None:
723 items=[]
724 self.__s=set(items)
725 def __contains__(self,v):
726 return v in self.__s
727 def __iter__(self):
728 return iter(self.__s)
729 def __len__(self):
730 return len(self.__s)
731 def add(self,v):
732 result=v not in self.__s
733 self.__s.add(v)
734 return result
735 def discard(self,v):
736 result=v in self.__s
737 self.__s.discard(v)
738 return result
739 def __repr__(self):
740 return "MySet(%s)" % repr(list(self))
741 s = MySet([5,43,2,1])
742 self.assertEqual(s.pop(), 1)
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000743
Daniel Stutzbach31da5b22010-08-24 20:49:57 +0000744 def test_issue8750(self):
745 empty = WithSet()
746 full = WithSet(range(10))
747 s = WithSet(full)
748 s -= s
749 self.assertEqual(s, empty)
750 s = WithSet(full)
751 s ^= s
752 self.assertEqual(s, empty)
753 s = WithSet(full)
754 s &= s
755 self.assertEqual(s, full)
756 s |= s
757 self.assertEqual(s, full)
758
Andrew Svetlovbcac6ad2012-11-01 13:28:54 +0200759 def test_issue16373(self):
760 # Recursion error comparing comparable and noncomparable
761 # Set instances
762 class MyComparableSet(Set):
763 def __contains__(self, x):
764 return False
765 def __len__(self):
766 return 0
767 def __iter__(self):
768 return iter([])
769 class MyNonComparableSet(Set):
770 def __contains__(self, x):
771 return False
772 def __len__(self):
773 return 0
774 def __iter__(self):
775 return iter([])
776 def __le__(self, x):
777 return NotImplemented
778 def __lt__(self, x):
779 return NotImplemented
780
781 cs = MyComparableSet()
782 ncs = MyNonComparableSet()
Raymond Hettingerdd5e53a2014-05-26 00:09:04 -0700783 self.assertFalse(ncs < cs)
784 self.assertTrue(ncs <= cs)
785 self.assertFalse(ncs > cs)
786 self.assertTrue(ncs >= cs)
787
788 def assertSameSet(self, s1, s2):
789 # coerce both to a real set then check equality
790 self.assertSetEqual(set(s1), set(s2))
791
792 def test_Set_interoperability_with_real_sets(self):
793 # Issue: 8743
794 class ListSet(Set):
795 def __init__(self, elements=()):
796 self.data = []
797 for elem in elements:
798 if elem not in self.data:
799 self.data.append(elem)
800 def __contains__(self, elem):
801 return elem in self.data
802 def __iter__(self):
803 return iter(self.data)
804 def __len__(self):
805 return len(self.data)
806 def __repr__(self):
807 return 'Set({!r})'.format(self.data)
808
809 r1 = set('abc')
810 r2 = set('bcd')
811 r3 = set('abcde')
812 f1 = ListSet('abc')
813 f2 = ListSet('bcd')
814 f3 = ListSet('abcde')
815 l1 = list('abccba')
816 l2 = list('bcddcb')
817 l3 = list('abcdeedcba')
818
819 target = r1 & r2
820 self.assertSameSet(f1 & f2, target)
821 self.assertSameSet(f1 & r2, target)
822 self.assertSameSet(r2 & f1, target)
823 self.assertSameSet(f1 & l2, target)
824
825 target = r1 | r2
826 self.assertSameSet(f1 | f2, target)
827 self.assertSameSet(f1 | r2, target)
828 self.assertSameSet(r2 | f1, target)
829 self.assertSameSet(f1 | l2, target)
830
831 fwd_target = r1 - r2
832 rev_target = r2 - r1
833 self.assertSameSet(f1 - f2, fwd_target)
834 self.assertSameSet(f2 - f1, rev_target)
835 self.assertSameSet(f1 - r2, fwd_target)
836 self.assertSameSet(f2 - r1, rev_target)
837 self.assertSameSet(r1 - f2, fwd_target)
838 self.assertSameSet(r2 - f1, rev_target)
839 self.assertSameSet(f1 - l2, fwd_target)
840 self.assertSameSet(f2 - l1, rev_target)
841
842 target = r1 ^ r2
843 self.assertSameSet(f1 ^ f2, target)
844 self.assertSameSet(f1 ^ r2, target)
845 self.assertSameSet(r2 ^ f1, target)
846 self.assertSameSet(f1 ^ l2, target)
847
848 # Don't change the following to use assertLess or other
849 # "more specific" unittest assertions. The current
850 # assertTrue/assertFalse style makes the pattern of test
851 # case combinations clear and allows us to know for sure
852 # the exact operator being invoked.
853
854 # proper subset
855 self.assertTrue(f1 < f3)
856 self.assertFalse(f1 < f1)
857 self.assertFalse(f1 < f2)
858 self.assertTrue(r1 < f3)
859 self.assertFalse(r1 < f1)
860 self.assertFalse(r1 < f2)
861 self.assertTrue(r1 < r3)
862 self.assertFalse(r1 < r1)
863 self.assertFalse(r1 < r2)
Andrew Svetlovbcac6ad2012-11-01 13:28:54 +0200864 with self.assertRaises(TypeError):
Raymond Hettingerdd5e53a2014-05-26 00:09:04 -0700865 f1 < l3
Andrew Svetlovbcac6ad2012-11-01 13:28:54 +0200866 with self.assertRaises(TypeError):
Raymond Hettingerdd5e53a2014-05-26 00:09:04 -0700867 f1 < l1
Andrew Svetlovbcac6ad2012-11-01 13:28:54 +0200868 with self.assertRaises(TypeError):
Raymond Hettingerdd5e53a2014-05-26 00:09:04 -0700869 f1 < l2
870
871 # any subset
872 self.assertTrue(f1 <= f3)
873 self.assertTrue(f1 <= f1)
874 self.assertFalse(f1 <= f2)
875 self.assertTrue(r1 <= f3)
876 self.assertTrue(r1 <= f1)
877 self.assertFalse(r1 <= f2)
878 self.assertTrue(r1 <= r3)
879 self.assertTrue(r1 <= r1)
880 self.assertFalse(r1 <= r2)
Andrew Svetlovbcac6ad2012-11-01 13:28:54 +0200881 with self.assertRaises(TypeError):
Raymond Hettingerdd5e53a2014-05-26 00:09:04 -0700882 f1 <= l3
883 with self.assertRaises(TypeError):
884 f1 <= l1
885 with self.assertRaises(TypeError):
886 f1 <= l2
887
888 # proper superset
889 self.assertTrue(f3 > f1)
890 self.assertFalse(f1 > f1)
891 self.assertFalse(f2 > f1)
892 self.assertTrue(r3 > r1)
893 self.assertFalse(f1 > r1)
894 self.assertFalse(f2 > r1)
895 self.assertTrue(r3 > r1)
896 self.assertFalse(r1 > r1)
897 self.assertFalse(r2 > r1)
898 with self.assertRaises(TypeError):
899 f1 > l3
900 with self.assertRaises(TypeError):
901 f1 > l1
902 with self.assertRaises(TypeError):
903 f1 > l2
904
905 # any superset
906 self.assertTrue(f3 >= f1)
907 self.assertTrue(f1 >= f1)
908 self.assertFalse(f2 >= f1)
909 self.assertTrue(r3 >= r1)
910 self.assertTrue(f1 >= r1)
911 self.assertFalse(f2 >= r1)
912 self.assertTrue(r3 >= r1)
913 self.assertTrue(r1 >= r1)
914 self.assertFalse(r2 >= r1)
915 with self.assertRaises(TypeError):
916 f1 >= l3
917 with self.assertRaises(TypeError):
918 f1 >=l1
919 with self.assertRaises(TypeError):
920 f1 >= l2
921
922 # equality
923 self.assertTrue(f1 == f1)
924 self.assertTrue(r1 == f1)
925 self.assertTrue(f1 == r1)
926 self.assertFalse(f1 == f3)
927 self.assertFalse(r1 == f3)
928 self.assertFalse(f1 == r3)
929 self.assertFalse(f1 == l3)
930 self.assertFalse(f1 == l1)
931 self.assertFalse(f1 == l2)
932
933 # inequality
934 self.assertFalse(f1 != f1)
935 self.assertFalse(r1 != f1)
936 self.assertFalse(f1 != r1)
937 self.assertTrue(f1 != f3)
938 self.assertTrue(r1 != f3)
939 self.assertTrue(f1 != r3)
940 self.assertTrue(f1 != l3)
941 self.assertTrue(f1 != l1)
942 self.assertTrue(f1 != l2)
Andrew Svetlovbcac6ad2012-11-01 13:28:54 +0200943
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000944 def test_Mapping(self):
945 for sample in [dict]:
Ezio Melottie9615932010-01-24 19:26:24 +0000946 self.assertIsInstance(sample(), Mapping)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000947 self.assertTrue(issubclass(sample, Mapping))
Raymond Hettingerae650182009-01-28 23:33:59 +0000948 self.validate_abstract_methods(Mapping, '__contains__', '__iter__', '__len__',
949 '__getitem__')
Raymond Hettinger57d1a882011-02-23 00:46:28 +0000950 class MyMapping(Mapping):
Benjamin Peterson4ad6bd52010-05-21 20:55:22 +0000951 def __len__(self):
952 return 0
953 def __getitem__(self, i):
954 raise IndexError
955 def __iter__(self):
956 return iter(())
957 self.validate_comparison(MyMapping())
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000958
959 def test_MutableMapping(self):
960 for sample in [dict]:
Ezio Melottie9615932010-01-24 19:26:24 +0000961 self.assertIsInstance(sample(), MutableMapping)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000962 self.assertTrue(issubclass(sample, MutableMapping))
Raymond Hettingerae650182009-01-28 23:33:59 +0000963 self.validate_abstract_methods(MutableMapping, '__contains__', '__iter__', '__len__',
964 '__getitem__', '__setitem__', '__delitem__')
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000965
Raymond Hettinger9117c752010-08-22 07:44:24 +0000966 def test_MutableMapping_subclass(self):
967 # Test issue 9214
968 mymap = UserDict()
969 mymap['red'] = 5
970 self.assertIsInstance(mymap.keys(), Set)
971 self.assertIsInstance(mymap.keys(), KeysView)
972 self.assertIsInstance(mymap.items(), Set)
973 self.assertIsInstance(mymap.items(), ItemsView)
974
975 mymap = UserDict()
976 mymap['red'] = 5
977 z = mymap.keys() | {'orange'}
978 self.assertIsInstance(z, set)
979 list(z)
980 mymap['blue'] = 7 # Shouldn't affect 'z'
981 self.assertEqual(sorted(z), ['orange', 'red'])
982
983 mymap = UserDict()
984 mymap['red'] = 5
985 z = mymap.items() | {('orange', 3)}
986 self.assertIsInstance(z, set)
987 list(z)
988 mymap['blue'] = 7 # Shouldn't affect 'z'
989 self.assertEqual(sorted(z), [('orange', 3), ('red', 5)])
990
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000991 def test_Sequence(self):
992 for sample in [tuple, list, bytes, str]:
Ezio Melottie9615932010-01-24 19:26:24 +0000993 self.assertIsInstance(sample(), Sequence)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000994 self.assertTrue(issubclass(sample, Sequence))
Ezio Melottie9615932010-01-24 19:26:24 +0000995 self.assertIsInstance(range(10), Sequence)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000996 self.assertTrue(issubclass(range, Sequence))
Nick Coghlan45163cc2013-10-02 22:31:47 +1000997 self.assertIsInstance(memoryview(b""), Sequence)
998 self.assertTrue(issubclass(memoryview, Sequence))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000999 self.assertTrue(issubclass(str, Sequence))
Raymond Hettingerae650182009-01-28 23:33:59 +00001000 self.validate_abstract_methods(Sequence, '__contains__', '__iter__', '__len__',
1001 '__getitem__')
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001002
Guido van Rossumd05eb002007-11-21 22:26:24 +00001003 def test_ByteString(self):
1004 for sample in [bytes, bytearray]:
Ezio Melottie9615932010-01-24 19:26:24 +00001005 self.assertIsInstance(sample(), ByteString)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001006 self.assertTrue(issubclass(sample, ByteString))
Guido van Rossumd05eb002007-11-21 22:26:24 +00001007 for sample in [str, list, tuple]:
Ezio Melottie9615932010-01-24 19:26:24 +00001008 self.assertNotIsInstance(sample(), ByteString)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001009 self.assertFalse(issubclass(sample, ByteString))
Ezio Melottie9615932010-01-24 19:26:24 +00001010 self.assertNotIsInstance(memoryview(b""), ByteString)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001011 self.assertFalse(issubclass(memoryview, ByteString))
Guido van Rossumd05eb002007-11-21 22:26:24 +00001012
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001013 def test_MutableSequence(self):
Guido van Rossumd05eb002007-11-21 22:26:24 +00001014 for sample in [tuple, str, bytes]:
Ezio Melottie9615932010-01-24 19:26:24 +00001015 self.assertNotIsInstance(sample(), MutableSequence)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001016 self.assertFalse(issubclass(sample, MutableSequence))
Guido van Rossumd05eb002007-11-21 22:26:24 +00001017 for sample in [list, bytearray]:
Ezio Melottie9615932010-01-24 19:26:24 +00001018 self.assertIsInstance(sample(), MutableSequence)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001019 self.assertTrue(issubclass(sample, MutableSequence))
1020 self.assertFalse(issubclass(str, MutableSequence))
Raymond Hettingerae650182009-01-28 23:33:59 +00001021 self.validate_abstract_methods(MutableSequence, '__contains__', '__iter__',
1022 '__len__', '__getitem__', '__setitem__', '__delitem__', 'insert')
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001023
Eli Bendersky0716a572011-03-04 10:38:14 +00001024 def test_MutableSequence_mixins(self):
1025 # Test the mixins of MutableSequence by creating a miminal concrete
1026 # class inherited from it.
1027 class MutableSequenceSubclass(MutableSequence):
1028 def __init__(self):
1029 self.lst = []
1030
1031 def __setitem__(self, index, value):
1032 self.lst[index] = value
1033
1034 def __getitem__(self, index):
1035 return self.lst[index]
1036
1037 def __len__(self):
1038 return len(self.lst)
1039
1040 def __delitem__(self, index):
1041 del self.lst[index]
1042
1043 def insert(self, index, value):
1044 self.lst.insert(index, value)
1045
1046 mss = MutableSequenceSubclass()
1047 mss.append(0)
1048 mss.extend((1, 2, 3, 4))
1049 self.assertEqual(len(mss), 5)
1050 self.assertEqual(mss[3], 3)
1051 mss.reverse()
1052 self.assertEqual(mss[3], 1)
1053 mss.pop()
1054 self.assertEqual(len(mss), 4)
1055 mss.remove(3)
1056 self.assertEqual(len(mss), 3)
1057 mss += (10, 20, 30)
1058 self.assertEqual(len(mss), 6)
1059 self.assertEqual(mss[-1], 30)
1060 mss.clear()
1061 self.assertEqual(len(mss), 0)
Raymond Hettinger499e1932011-02-23 07:56:53 +00001062
1063################################################################################
1064### Counter
1065################################################################################
1066
Raymond Hettingercb1d96f2013-10-04 16:51:02 -07001067class CounterSubclassWithSetItem(Counter):
1068 # Test a counter subclass that overrides __setitem__
1069 def __init__(self, *args, **kwds):
1070 self.called = False
1071 Counter.__init__(self, *args, **kwds)
1072 def __setitem__(self, key, value):
1073 self.called = True
1074 Counter.__setitem__(self, key, value)
1075
1076class CounterSubclassWithGet(Counter):
1077 # Test a counter subclass that overrides get()
1078 def __init__(self, *args, **kwds):
1079 self.called = False
1080 Counter.__init__(self, *args, **kwds)
1081 def get(self, key, default):
1082 self.called = True
1083 return Counter.get(self, key, default)
1084
Raymond Hettingerb8baf632009-01-14 02:20:07 +00001085class TestCounter(unittest.TestCase):
1086
1087 def test_basics(self):
1088 c = Counter('abcaba')
Raymond Hettinger4d2073a2009-01-20 03:41:22 +00001089 self.assertEqual(c, Counter({'a':3 , 'b': 2, 'c': 1}))
1090 self.assertEqual(c, Counter(a=3, b=2, c=1))
Ezio Melottie9615932010-01-24 19:26:24 +00001091 self.assertIsInstance(c, dict)
1092 self.assertIsInstance(c, Mapping)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001093 self.assertTrue(issubclass(Counter, dict))
1094 self.assertTrue(issubclass(Counter, Mapping))
Raymond Hettingerb8baf632009-01-14 02:20:07 +00001095 self.assertEqual(len(c), 3)
1096 self.assertEqual(sum(c.values()), 6)
1097 self.assertEqual(sorted(c.values()), [1, 2, 3])
1098 self.assertEqual(sorted(c.keys()), ['a', 'b', 'c'])
1099 self.assertEqual(sorted(c), ['a', 'b', 'c'])
1100 self.assertEqual(sorted(c.items()),
1101 [('a', 3), ('b', 2), ('c', 1)])
1102 self.assertEqual(c['b'], 2)
1103 self.assertEqual(c['z'], 0)
1104 self.assertEqual(c.__contains__('c'), True)
1105 self.assertEqual(c.__contains__('z'), False)
1106 self.assertEqual(c.get('b', 10), 2)
1107 self.assertEqual(c.get('z', 10), 10)
1108 self.assertEqual(c, dict(a=3, b=2, c=1))
1109 self.assertEqual(repr(c), "Counter({'a': 3, 'b': 2, 'c': 1})")
1110 self.assertEqual(c.most_common(), [('a', 3), ('b', 2), ('c', 1)])
1111 for i in range(5):
1112 self.assertEqual(c.most_common(i),
1113 [('a', 3), ('b', 2), ('c', 1)][:i])
1114 self.assertEqual(''.join(sorted(c.elements())), 'aaabbc')
1115 c['a'] += 1 # increment an existing value
1116 c['b'] -= 2 # sub existing value to zero
1117 del c['c'] # remove an entry
Raymond Hettinger4d2073a2009-01-20 03:41:22 +00001118 del c['c'] # make sure that del doesn't raise KeyError
Raymond Hettingerb8baf632009-01-14 02:20:07 +00001119 c['d'] -= 2 # sub from a missing value
1120 c['e'] = -5 # directly assign a missing value
1121 c['f'] += 4 # add to a missing value
1122 self.assertEqual(c, dict(a=4, b=0, d=-2, e=-5, f=4))
1123 self.assertEqual(''.join(sorted(c.elements())), 'aaaaffff')
1124 self.assertEqual(c.pop('f'), 4)
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001125 self.assertNotIn('f', c)
Raymond Hettingerb8baf632009-01-14 02:20:07 +00001126 for i in range(3):
1127 elem, cnt = c.popitem()
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001128 self.assertNotIn(elem, c)
Raymond Hettingerb8baf632009-01-14 02:20:07 +00001129 c.clear()
1130 self.assertEqual(c, {})
1131 self.assertEqual(repr(c), 'Counter()')
1132 self.assertRaises(NotImplementedError, Counter.fromkeys, 'abc')
1133 self.assertRaises(TypeError, hash, c)
Raymond Hettinger4d2073a2009-01-20 03:41:22 +00001134 c.update(dict(a=5, b=3))
1135 c.update(c=1)
Raymond Hettingerb8baf632009-01-14 02:20:07 +00001136 c.update(Counter('a' * 50 + 'b' * 30))
1137 c.update() # test case with no args
1138 c.__init__('a' * 500 + 'b' * 300)
1139 c.__init__('cdc')
1140 c.__init__()
1141 self.assertEqual(c, dict(a=555, b=333, c=3, d=1))
1142 self.assertEqual(c.setdefault('d', 5), 1)
1143 self.assertEqual(c['d'], 1)
1144 self.assertEqual(c.setdefault('e', 5), 5)
1145 self.assertEqual(c['e'], 5)
1146
Serhiy Storchakaae5cb212014-11-27 16:25:51 +02001147 def test_init(self):
1148 self.assertEqual(list(Counter(self=42).items()), [('self', 42)])
1149 self.assertEqual(list(Counter(iterable=42).items()), [('iterable', 42)])
1150 self.assertEqual(list(Counter(iterable=None).items()), [('iterable', None)])
1151 self.assertRaises(TypeError, Counter, 42)
1152 self.assertRaises(TypeError, Counter, (), ())
1153 self.assertRaises(TypeError, Counter.__init__)
1154
1155 def test_update(self):
1156 c = Counter()
1157 c.update(self=42)
1158 self.assertEqual(list(c.items()), [('self', 42)])
1159 c = Counter()
1160 c.update(iterable=42)
1161 self.assertEqual(list(c.items()), [('iterable', 42)])
1162 c = Counter()
1163 c.update(iterable=None)
1164 self.assertEqual(list(c.items()), [('iterable', None)])
1165 self.assertRaises(TypeError, Counter().update, 42)
1166 self.assertRaises(TypeError, Counter().update, {}, {})
1167 self.assertRaises(TypeError, Counter.update)
1168
Raymond Hettingerb8baf632009-01-14 02:20:07 +00001169 def test_copying(self):
1170 # Check that counters are copyable, deepcopyable, picklable, and
1171 #have a repr/eval round-trip
1172 words = Counter('which witch had which witches wrist watch'.split())
Serhiy Storchakabad12572014-12-15 14:03:42 +02001173 def check(dup):
1174 msg = "\ncopy: %s\nwords: %s" % (dup, words)
1175 self.assertIsNot(dup, words, msg)
1176 self.assertEqual(dup, words)
1177 check(words.copy())
1178 check(copy.copy(words))
1179 check(copy.deepcopy(words))
1180 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1181 with self.subTest(proto=proto):
1182 check(pickle.loads(pickle.dumps(words, proto)))
1183 check(eval(repr(words)))
Raymond Hettingerb8baf632009-01-14 02:20:07 +00001184 update_test = Counter()
1185 update_test.update(words)
Serhiy Storchakabad12572014-12-15 14:03:42 +02001186 check(update_test)
1187 check(Counter(words))
Raymond Hettingerb8baf632009-01-14 02:20:07 +00001188
Raymond Hettinger1c746c22011-04-15 13:16:46 -07001189 def test_copy_subclass(self):
1190 class MyCounter(Counter):
1191 pass
1192 c = MyCounter('slartibartfast')
1193 d = c.copy()
1194 self.assertEqual(d, c)
1195 self.assertEqual(len(d), len(c))
1196 self.assertEqual(type(d), type(c))
1197
Raymond Hettingerb8baf632009-01-14 02:20:07 +00001198 def test_conversions(self):
1199 # Convert to: set, list, dict
1200 s = 'she sells sea shells by the sea shore'
1201 self.assertEqual(sorted(Counter(s).elements()), sorted(s))
1202 self.assertEqual(sorted(Counter(s)), sorted(set(s)))
1203 self.assertEqual(dict(Counter(s)), dict(Counter(s).items()))
1204 self.assertEqual(set(Counter(s)), set(s))
1205
Raymond Hettinger670eaec2009-01-21 23:14:07 +00001206 def test_invariant_for_the_in_operator(self):
1207 c = Counter(a=10, b=-2, c=0)
1208 for elem in c:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001209 self.assertTrue(elem in c)
Benjamin Peterson577473f2010-01-19 00:09:57 +00001210 self.assertIn(elem, c)
Raymond Hettinger670eaec2009-01-21 23:14:07 +00001211
Raymond Hettinger4d2073a2009-01-20 03:41:22 +00001212 def test_multiset_operations(self):
1213 # Verify that adding a zero counter will strip zeros and negatives
1214 c = Counter(a=10, b=-2, c=0) + Counter()
1215 self.assertEqual(dict(c), dict(a=10))
Raymond Hettingerb8baf632009-01-14 02:20:07 +00001216
Raymond Hettinger4d2073a2009-01-20 03:41:22 +00001217 elements = 'abcd'
1218 for i in range(1000):
1219 # test random pairs of multisets
1220 p = Counter(dict((elem, randrange(-2,4)) for elem in elements))
Raymond Hettingere0d1b9f2009-01-21 20:36:27 +00001221 p.update(e=1, f=-1, g=0)
Raymond Hettinger4d2073a2009-01-20 03:41:22 +00001222 q = Counter(dict((elem, randrange(-2,4)) for elem in elements))
Raymond Hettingere0d1b9f2009-01-21 20:36:27 +00001223 q.update(h=1, i=-1, j=0)
1224 for counterop, numberop in [
1225 (Counter.__add__, lambda x, y: max(0, x+y)),
1226 (Counter.__sub__, lambda x, y: max(0, x-y)),
1227 (Counter.__or__, lambda x, y: max(0,x,y)),
1228 (Counter.__and__, lambda x, y: max(0, min(x,y))),
Raymond Hettinger4d2073a2009-01-20 03:41:22 +00001229 ]:
1230 result = counterop(p, q)
1231 for x in elements:
Raymond Hettingere0d1b9f2009-01-21 20:36:27 +00001232 self.assertEqual(numberop(p[x], q[x]), result[x],
1233 (counterop, x, p, q))
Raymond Hettinger4d2073a2009-01-20 03:41:22 +00001234 # verify that results exclude non-positive counts
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001235 self.assertTrue(x>0 for x in result.values())
Raymond Hettinger4d2073a2009-01-20 03:41:22 +00001236
1237 elements = 'abcdef'
1238 for i in range(100):
1239 # verify that random multisets with no repeats are exactly like sets
1240 p = Counter(dict((elem, randrange(0, 2)) for elem in elements))
1241 q = Counter(dict((elem, randrange(0, 2)) for elem in elements))
1242 for counterop, setop in [
1243 (Counter.__sub__, set.__sub__),
1244 (Counter.__or__, set.__or__),
1245 (Counter.__and__, set.__and__),
1246 ]:
1247 counter_result = counterop(p, q)
1248 set_result = setop(set(p.elements()), set(q.elements()))
1249 self.assertEqual(counter_result, dict.fromkeys(set_result, 1))
Raymond Hettingerb8baf632009-01-14 02:20:07 +00001250
Raymond Hettingerbecd5682011-10-19 13:40:37 -07001251 def test_inplace_operations(self):
1252 elements = 'abcd'
1253 for i in range(1000):
1254 # test random pairs of multisets
1255 p = Counter(dict((elem, randrange(-2,4)) for elem in elements))
1256 p.update(e=1, f=-1, g=0)
1257 q = Counter(dict((elem, randrange(-2,4)) for elem in elements))
1258 q.update(h=1, i=-1, j=0)
1259 for inplace_op, regular_op in [
1260 (Counter.__iadd__, Counter.__add__),
1261 (Counter.__isub__, Counter.__sub__),
1262 (Counter.__ior__, Counter.__or__),
1263 (Counter.__iand__, Counter.__and__),
1264 ]:
1265 c = p.copy()
1266 c_id = id(c)
1267 regular_result = regular_op(c, q)
1268 inplace_result = inplace_op(c, q)
1269 self.assertEqual(inplace_result, regular_result)
1270 self.assertEqual(id(inplace_result), c_id)
1271
Raymond Hettinger9c01e442010-04-03 10:32:58 +00001272 def test_subtract(self):
1273 c = Counter(a=-5, b=0, c=5, d=10, e=15,g=40)
1274 c.subtract(a=1, b=2, c=-3, d=10, e=20, f=30, h=-50)
1275 self.assertEqual(c, Counter(a=-6, b=-2, c=8, d=0, e=-5, f=-30, g=40, h=50))
1276 c = Counter(a=-5, b=0, c=5, d=10, e=15,g=40)
1277 c.subtract(Counter(a=1, b=2, c=-3, d=10, e=20, f=30, h=-50))
1278 self.assertEqual(c, Counter(a=-6, b=-2, c=8, d=0, e=-5, f=-30, g=40, h=50))
1279 c = Counter('aaabbcd')
1280 c.subtract('aaaabbcce')
1281 self.assertEqual(c, Counter(a=-1, b=0, c=-1, d=1, e=-1))
Raymond Hettinger2d32f632009-03-02 21:24:57 +00001282
Serhiy Storchakaae5cb212014-11-27 16:25:51 +02001283 c = Counter()
1284 c.subtract(self=42)
1285 self.assertEqual(list(c.items()), [('self', -42)])
1286 c = Counter()
1287 c.subtract(iterable=42)
1288 self.assertEqual(list(c.items()), [('iterable', -42)])
1289 self.assertRaises(TypeError, Counter().subtract, 42)
1290 self.assertRaises(TypeError, Counter().subtract, {}, {})
1291 self.assertRaises(TypeError, Counter.subtract)
1292
Raymond Hettingerfcb393c2011-08-09 13:00:40 -07001293 def test_unary(self):
1294 c = Counter(a=-5, b=0, c=5, d=10, e=15,g=40)
1295 self.assertEqual(dict(+c), dict(c=5, d=10, e=15, g=40))
1296 self.assertEqual(dict(-c), dict(a=5))
1297
Raymond Hettinger4e6bf412011-11-05 13:35:26 -07001298 def test_repr_nonsortable(self):
1299 c = Counter(a=2, b=None)
1300 r = repr(c)
1301 self.assertIn("'a': 2", r)
1302 self.assertIn("'b': None", r)
Raymond Hettinger68fb89f2011-11-05 13:43:01 -07001303
Raymond Hettinger426e0522011-01-03 02:12:02 +00001304 def test_helper_function(self):
1305 # two paths, one for real dicts and one for other mappings
1306 elems = list('abracadabra')
1307
1308 d = dict()
1309 _count_elements(d, elems)
1310 self.assertEqual(d, {'a': 5, 'r': 2, 'b': 2, 'c': 1, 'd': 1})
1311
1312 m = OrderedDict()
1313 _count_elements(m, elems)
1314 self.assertEqual(m,
1315 OrderedDict([('a', 5), ('b', 2), ('r', 2), ('c', 1), ('d', 1)]))
1316
Raymond Hettingercb1d96f2013-10-04 16:51:02 -07001317 # test fidelity to the pure python version
1318 c = CounterSubclassWithSetItem('abracadabra')
1319 self.assertTrue(c.called)
Raymond Hettingerfacd0a32013-10-05 17:14:51 -07001320 self.assertEqual(dict(c), {'a': 5, 'b': 2, 'c': 1, 'd': 1, 'r':2 })
Raymond Hettingercb1d96f2013-10-04 16:51:02 -07001321 c = CounterSubclassWithGet('abracadabra')
1322 self.assertTrue(c.called)
Raymond Hettingerfacd0a32013-10-05 17:14:51 -07001323 self.assertEqual(dict(c), {'a': 5, 'b': 2, 'c': 1, 'd': 1, 'r':2 })
Raymond Hettingercb1d96f2013-10-04 16:51:02 -07001324
Raymond Hettinger499e1932011-02-23 07:56:53 +00001325
1326################################################################################
1327### OrderedDict
1328################################################################################
1329
Raymond Hettinger2d32f632009-03-02 21:24:57 +00001330class TestOrderedDict(unittest.TestCase):
1331
1332 def test_init(self):
1333 with self.assertRaises(TypeError):
1334 OrderedDict([('a', 1), ('b', 2)], None) # too many args
1335 pairs = [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)]
1336 self.assertEqual(sorted(OrderedDict(dict(pairs)).items()), pairs) # dict input
1337 self.assertEqual(sorted(OrderedDict(**dict(pairs)).items()), pairs) # kwds input
1338 self.assertEqual(list(OrderedDict(pairs).items()), pairs) # pairs input
1339 self.assertEqual(list(OrderedDict([('a', 1), ('b', 2), ('c', 9), ('d', 4)],
1340 c=3, e=5).items()), pairs) # mixed input
1341
1342 # make sure no positional args conflict with possible kwdargs
Serhiy Storchakaae5cb212014-11-27 16:25:51 +02001343 self.assertEqual(list(OrderedDict(self=42).items()), [('self', 42)])
1344 self.assertEqual(list(OrderedDict(other=42).items()), [('other', 42)])
1345 self.assertRaises(TypeError, OrderedDict, 42)
1346 self.assertRaises(TypeError, OrderedDict, (), ())
1347 self.assertRaises(TypeError, OrderedDict.__init__)
Raymond Hettinger2d32f632009-03-02 21:24:57 +00001348
1349 # Make sure that direct calls to __init__ do not clear previous contents
1350 d = OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 44), ('e', 55)])
1351 d.__init__([('e', 5), ('f', 6)], g=7, d=4)
1352 self.assertEqual(list(d.items()),
1353 [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5), ('f', 6), ('g', 7)])
1354
1355 def test_update(self):
1356 with self.assertRaises(TypeError):
1357 OrderedDict().update([('a', 1), ('b', 2)], None) # too many args
1358 pairs = [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)]
1359 od = OrderedDict()
1360 od.update(dict(pairs))
1361 self.assertEqual(sorted(od.items()), pairs) # dict input
1362 od = OrderedDict()
1363 od.update(**dict(pairs))
1364 self.assertEqual(sorted(od.items()), pairs) # kwds input
1365 od = OrderedDict()
1366 od.update(pairs)
1367 self.assertEqual(list(od.items()), pairs) # pairs input
1368 od = OrderedDict()
1369 od.update([('a', 1), ('b', 2), ('c', 9), ('d', 4)], c=3, e=5)
1370 self.assertEqual(list(od.items()), pairs) # mixed input
1371
Mark Dickinsonb214e902010-07-11 18:53:06 +00001372 # Issue 9137: Named argument called 'other' or 'self'
1373 # shouldn't be treated specially.
1374 od = OrderedDict()
1375 od.update(self=23)
1376 self.assertEqual(list(od.items()), [('self', 23)])
1377 od = OrderedDict()
1378 od.update(other={})
1379 self.assertEqual(list(od.items()), [('other', {})])
1380 od = OrderedDict()
1381 od.update(red=5, blue=6, other=7, self=8)
1382 self.assertEqual(sorted(list(od.items())),
1383 [('blue', 6), ('other', 7), ('red', 5), ('self', 8)])
1384
Raymond Hettinger2d32f632009-03-02 21:24:57 +00001385 # Make sure that direct calls to update do not clear previous contents
1386 # add that updates items are not moved to the end
1387 d = OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 44), ('e', 55)])
1388 d.update([('e', 5), ('f', 6)], g=7, d=4)
1389 self.assertEqual(list(d.items()),
1390 [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5), ('f', 6), ('g', 7)])
1391
Serhiy Storchakaae5cb212014-11-27 16:25:51 +02001392 self.assertRaises(TypeError, OrderedDict().update, 42)
1393 self.assertRaises(TypeError, OrderedDict().update, (), ())
1394 self.assertRaises(TypeError, OrderedDict.update)
1395
Raymond Hettinger345c49b2011-01-01 23:51:55 +00001396 def test_abc(self):
1397 self.assertIsInstance(OrderedDict(), MutableMapping)
1398 self.assertTrue(issubclass(OrderedDict, MutableMapping))
1399
Raymond Hettinger2d32f632009-03-02 21:24:57 +00001400 def test_clear(self):
1401 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
1402 shuffle(pairs)
1403 od = OrderedDict(pairs)
1404 self.assertEqual(len(od), len(pairs))
1405 od.clear()
1406 self.assertEqual(len(od), 0)
1407
1408 def test_delitem(self):
1409 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
1410 od = OrderedDict(pairs)
1411 del od['a']
Benjamin Peterson577473f2010-01-19 00:09:57 +00001412 self.assertNotIn('a', od)
Raymond Hettinger2d32f632009-03-02 21:24:57 +00001413 with self.assertRaises(KeyError):
1414 del od['a']
1415 self.assertEqual(list(od.items()), pairs[:2] + pairs[3:])
1416
1417 def test_setitem(self):
1418 od = OrderedDict([('d', 1), ('b', 2), ('c', 3), ('a', 4), ('e', 5)])
1419 od['c'] = 10 # existing element
1420 od['f'] = 20 # new element
1421 self.assertEqual(list(od.items()),
1422 [('d', 1), ('b', 2), ('c', 10), ('a', 4), ('e', 5), ('f', 20)])
1423
1424 def test_iterators(self):
1425 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
1426 shuffle(pairs)
1427 od = OrderedDict(pairs)
1428 self.assertEqual(list(od), [t[0] for t in pairs])
1429 self.assertEqual(list(od.keys()), [t[0] for t in pairs])
1430 self.assertEqual(list(od.values()), [t[1] for t in pairs])
1431 self.assertEqual(list(od.items()), pairs)
1432 self.assertEqual(list(reversed(od)),
1433 [t[0] for t in reversed(pairs)])
Serhiy Storchaka578c9212014-04-04 15:19:36 +03001434 self.assertEqual(list(reversed(od.keys())),
1435 [t[0] for t in reversed(pairs)])
1436 self.assertEqual(list(reversed(od.values())),
1437 [t[1] for t in reversed(pairs)])
1438 self.assertEqual(list(reversed(od.items())), list(reversed(pairs)))
Raymond Hettinger2d32f632009-03-02 21:24:57 +00001439
Raymond Hettinger53d2c412014-05-03 21:58:45 -07001440 def test_detect_deletion_during_iteration(self):
1441 od = OrderedDict.fromkeys('abc')
1442 it = iter(od)
1443 key = next(it)
1444 del od[key]
1445 with self.assertRaises(Exception):
1446 # Note, the exact exception raised is not guaranteed
1447 # The only guarantee that the next() will not succeed
1448 next(it)
1449
Raymond Hettinger2d32f632009-03-02 21:24:57 +00001450 def test_popitem(self):
1451 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
1452 shuffle(pairs)
1453 od = OrderedDict(pairs)
1454 while pairs:
1455 self.assertEqual(od.popitem(), pairs.pop())
1456 with self.assertRaises(KeyError):
1457 od.popitem()
1458 self.assertEqual(len(od), 0)
1459
1460 def test_pop(self):
1461 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
1462 shuffle(pairs)
1463 od = OrderedDict(pairs)
1464 shuffle(pairs)
1465 while pairs:
1466 k, v = pairs.pop()
1467 self.assertEqual(od.pop(k), v)
1468 with self.assertRaises(KeyError):
1469 od.pop('xyz')
1470 self.assertEqual(len(od), 0)
1471 self.assertEqual(od.pop(k, 12345), 12345)
1472
Raymond Hettinger345c49b2011-01-01 23:51:55 +00001473 # make sure pop still works when __missing__ is defined
1474 class Missing(OrderedDict):
1475 def __missing__(self, key):
1476 return 0
1477 m = Missing(a=1)
1478 self.assertEqual(m.pop('b', 5), 5)
1479 self.assertEqual(m.pop('a', 6), 1)
1480 self.assertEqual(m.pop('a', 6), 6)
1481 with self.assertRaises(KeyError):
1482 m.pop('a')
1483
Raymond Hettinger2d32f632009-03-02 21:24:57 +00001484 def test_equality(self):
1485 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
1486 shuffle(pairs)
1487 od1 = OrderedDict(pairs)
1488 od2 = OrderedDict(pairs)
1489 self.assertEqual(od1, od2) # same order implies equality
1490 pairs = pairs[2:] + pairs[:2]
1491 od2 = OrderedDict(pairs)
1492 self.assertNotEqual(od1, od2) # different order implies inequality
1493 # comparison to regular dict is not order sensitive
1494 self.assertEqual(od1, dict(od2))
1495 self.assertEqual(dict(od2), od1)
1496 # different length implied inequality
1497 self.assertNotEqual(od1, OrderedDict(pairs[:-1]))
1498
1499 def test_copying(self):
1500 # Check that ordered dicts are copyable, deepcopyable, picklable,
1501 # and have a repr/eval round-trip
1502 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
1503 od = OrderedDict(pairs)
Serhiy Storchakabad12572014-12-15 14:03:42 +02001504 def check(dup):
1505 msg = "\ncopy: %s\nod: %s" % (dup, od)
1506 self.assertIsNot(dup, od, msg)
1507 self.assertEqual(dup, od)
1508 check(od.copy())
1509 check(copy.copy(od))
1510 check(copy.deepcopy(od))
1511 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1512 with self.subTest(proto=proto):
1513 check(pickle.loads(pickle.dumps(od, proto)))
1514 check(eval(repr(od)))
Raymond Hettinger2d32f632009-03-02 21:24:57 +00001515 update_test = OrderedDict()
1516 update_test.update(od)
Serhiy Storchakabad12572014-12-15 14:03:42 +02001517 check(update_test)
1518 check(OrderedDict(od))
Raymond Hettinger2d32f632009-03-02 21:24:57 +00001519
Raymond Hettinger5b26fb52009-03-03 22:38:22 +00001520 def test_yaml_linkage(self):
1521 # Verify that __reduce__ is setup in a way that supports PyYAML's dump() feature.
1522 # In yaml, lists are native but tuples are not.
1523 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
1524 od = OrderedDict(pairs)
1525 # yaml.dump(od) -->
1526 # '!!python/object/apply:__main__.OrderedDict\n- - [a, 1]\n - [b, 2]\n'
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001527 self.assertTrue(all(type(pair)==list for pair in od.__reduce__()[1]))
Raymond Hettinger5b26fb52009-03-03 22:38:22 +00001528
Raymond Hettingerb2121572009-03-03 22:50:04 +00001529 def test_reduce_not_too_fat(self):
1530 # do not save instance dictionary if not needed
1531 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
1532 od = OrderedDict(pairs)
Serhiy Storchaka3ee6dab2013-05-21 12:47:57 +03001533 self.assertIsNone(od.__reduce__()[2])
Raymond Hettingerb2121572009-03-03 22:50:04 +00001534 od.x = 10
Serhiy Storchaka3ee6dab2013-05-21 12:47:57 +03001535 self.assertIsNotNone(od.__reduce__()[2])
1536
1537 def test_pickle_recursive(self):
1538 od = OrderedDict()
1539 od[1] = od
1540 for proto in range(-1, pickle.HIGHEST_PROTOCOL + 1):
1541 dup = pickle.loads(pickle.dumps(od, proto))
1542 self.assertIsNot(dup, od)
1543 self.assertEqual(list(dup.keys()), [1])
1544 self.assertIs(dup[1], dup)
Raymond Hettingerb2121572009-03-03 22:50:04 +00001545
Raymond Hettinger2d32f632009-03-02 21:24:57 +00001546 def test_repr(self):
1547 od = OrderedDict([('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)])
1548 self.assertEqual(repr(od),
1549 "OrderedDict([('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)])")
1550 self.assertEqual(eval(repr(od)), od)
1551 self.assertEqual(repr(OrderedDict()), "OrderedDict()")
1552
Raymond Hettingerdc08a142010-09-12 05:15:22 +00001553 def test_repr_recursive(self):
1554 # See issue #9826
1555 od = OrderedDict.fromkeys('abc')
1556 od['x'] = od
1557 self.assertEqual(repr(od),
1558 "OrderedDict([('a', None), ('b', None), ('c', None), ('x', ...)])")
1559
Raymond Hettinger2d32f632009-03-02 21:24:57 +00001560 def test_setdefault(self):
1561 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
1562 shuffle(pairs)
1563 od = OrderedDict(pairs)
1564 pair_order = list(od.items())
1565 self.assertEqual(od.setdefault('a', 10), 3)
1566 # make sure order didn't change
1567 self.assertEqual(list(od.items()), pair_order)
1568 self.assertEqual(od.setdefault('x', 10), 10)
1569 # make sure 'x' is added to the end
1570 self.assertEqual(list(od.items())[-1], ('x', 10))
1571
Raymond Hettingera673b1f2010-12-31 23:16:17 +00001572 # make sure setdefault still works when __missing__ is defined
1573 class Missing(OrderedDict):
1574 def __missing__(self, key):
1575 return 0
1576 self.assertEqual(Missing().setdefault(5, 9), 9)
1577
Raymond Hettinger2d32f632009-03-02 21:24:57 +00001578 def test_reinsert(self):
1579 # Given insert a, insert b, delete a, re-insert a,
1580 # verify that a is now later than b.
1581 od = OrderedDict()
1582 od['a'] = 1
1583 od['b'] = 2
1584 del od['a']
1585 od['a'] = 1
1586 self.assertEqual(list(od.items()), [('b', 2), ('a', 1)])
1587
Raymond Hettingerf45abc92010-09-06 21:26:09 +00001588 def test_move_to_end(self):
1589 od = OrderedDict.fromkeys('abcde')
1590 self.assertEqual(list(od), list('abcde'))
1591 od.move_to_end('c')
1592 self.assertEqual(list(od), list('abdec'))
1593 od.move_to_end('c', 0)
1594 self.assertEqual(list(od), list('cabde'))
1595 od.move_to_end('c', 0)
1596 self.assertEqual(list(od), list('cabde'))
1597 od.move_to_end('e')
1598 self.assertEqual(list(od), list('cabde'))
1599 with self.assertRaises(KeyError):
1600 od.move_to_end('x')
Raymond Hettinger2d32f632009-03-02 21:24:57 +00001601
Raymond Hettinger35c87f22010-09-16 19:10:17 +00001602 def test_sizeof(self):
1603 # Wimpy test: Just verify the reported size is larger than a regular dict
1604 d = dict(a=1)
1605 od = OrderedDict(**d)
1606 self.assertGreater(sys.getsizeof(od), sys.getsizeof(d))
1607
Raymond Hettinger32062e92011-01-01 22:38:00 +00001608 def test_override_update(self):
1609 # Verify that subclasses can override update() without breaking __init__()
1610 class MyOD(OrderedDict):
1611 def update(self, *args, **kwds):
1612 raise Exception()
1613 items = [('a', 1), ('c', 3), ('b', 2)]
1614 self.assertEqual(list(MyOD(items).items()), items)
1615
Raymond Hettinger2d32f632009-03-02 21:24:57 +00001616class GeneralMappingTests(mapping_tests.BasicTestMappingProtocol):
1617 type2test = OrderedDict
1618
Raymond Hettingerdc879f02009-03-19 20:30:56 +00001619 def test_popitem(self):
1620 d = self._empty_mapping()
1621 self.assertRaises(KeyError, d.popitem)
1622
Raymond Hettinger2d32f632009-03-02 21:24:57 +00001623class MyOrderedDict(OrderedDict):
1624 pass
1625
1626class SubclassMappingTests(mapping_tests.BasicTestMappingProtocol):
1627 type2test = MyOrderedDict
1628
Raymond Hettingerdc879f02009-03-19 20:30:56 +00001629 def test_popitem(self):
1630 d = self._empty_mapping()
1631 self.assertRaises(KeyError, d.popitem)
Raymond Hettinger2d32f632009-03-02 21:24:57 +00001632
1633
Raymond Hettinger499e1932011-02-23 07:56:53 +00001634################################################################################
1635### Run tests
1636################################################################################
1637
Christian Heimes25bb7832008-01-11 16:17:00 +00001638import doctest, collections
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001639
Guido van Rossumd8faa362007-04-27 19:54:29 +00001640def test_main(verbose=None):
Benjamin Petersonad9d48d2008-04-02 21:49:44 +00001641 NamedTupleDocs = doctest.DocTestSuite(module=collections)
Raymond Hettingerb8baf632009-01-14 02:20:07 +00001642 test_classes = [TestNamedTuple, NamedTupleDocs, TestOneTrickPonyABCs,
Raymond Hettingerd0321312011-02-26 06:53:58 +00001643 TestCollectionABCs, TestCounter, TestChainMap,
Serhiy Storchakaa86700a2014-11-27 17:45:44 +02001644 TestOrderedDict, GeneralMappingTests, SubclassMappingTests]
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001645 support.run_unittest(*test_classes)
1646 support.run_doctest(collections, verbose)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001647
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001648
Guido van Rossumd8faa362007-04-27 19:54:29 +00001649if __name__ == "__main__":
1650 test_main(verbose=True)