1 |
|
---|
2 | import unittest, doctest, operator
|
---|
3 | import inspect
|
---|
4 | from test import test_support
|
---|
5 | from collections import namedtuple, Counter, OrderedDict
|
---|
6 | from test import mapping_tests
|
---|
7 | import pickle, cPickle, copy
|
---|
8 | from random import randrange, shuffle
|
---|
9 | import keyword
|
---|
10 | import re
|
---|
11 | import sys
|
---|
12 | from collections import Hashable, Iterable, Iterator
|
---|
13 | from collections import Sized, Container, Callable
|
---|
14 | from collections import Set, MutableSet
|
---|
15 | from collections import Mapping, MutableMapping
|
---|
16 | from collections import Sequence, MutableSequence
|
---|
17 |
|
---|
18 | TestNT = namedtuple('TestNT', 'x y z') # type used for pickle tests
|
---|
19 |
|
---|
20 | py273_named_tuple_pickle = '''\
|
---|
21 | ccopy_reg
|
---|
22 | _reconstructor
|
---|
23 | p0
|
---|
24 | (ctest.test_collections
|
---|
25 | TestNT
|
---|
26 | p1
|
---|
27 | c__builtin__
|
---|
28 | tuple
|
---|
29 | p2
|
---|
30 | (I10
|
---|
31 | I20
|
---|
32 | I30
|
---|
33 | tp3
|
---|
34 | tp4
|
---|
35 | Rp5
|
---|
36 | ccollections
|
---|
37 | OrderedDict
|
---|
38 | p6
|
---|
39 | ((lp7
|
---|
40 | (lp8
|
---|
41 | S'x'
|
---|
42 | p9
|
---|
43 | aI10
|
---|
44 | aa(lp10
|
---|
45 | S'y'
|
---|
46 | p11
|
---|
47 | aI20
|
---|
48 | aa(lp12
|
---|
49 | S'z'
|
---|
50 | p13
|
---|
51 | aI30
|
---|
52 | aatp14
|
---|
53 | Rp15
|
---|
54 | b.
|
---|
55 | '''
|
---|
56 |
|
---|
57 | class 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 |
|
---|
260 | class 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 |
|
---|
329 | class 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 |
|
---|
486 | class 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 |
|
---|
506 | class 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 |
|
---|
641 | class 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 |
|
---|
807 | class 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 |
|
---|
1056 | class 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 |
|
---|
1063 | class MyOrderedDict(OrderedDict):
|
---|
1064 | pass
|
---|
1065 |
|
---|
1066 | class 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 |
|
---|
1073 | import collections
|
---|
1074 |
|
---|
1075 | def 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 |
|
---|
1083 | if __name__ == "__main__":
|
---|
1084 | test_main(verbose=True)
|
---|