|
1 import unittest, doctest |
|
2 from test import test_support |
|
3 from collections import namedtuple |
|
4 import pickle, cPickle, copy |
|
5 from collections import Hashable, Iterable, Iterator |
|
6 from collections import Sized, Container, Callable |
|
7 from collections import Set, MutableSet |
|
8 from collections import Mapping, MutableMapping |
|
9 from collections import Sequence, MutableSequence |
|
10 |
|
11 TestNT = namedtuple('TestNT', 'x y z') # type used for pickle tests |
|
12 |
|
13 class TestNamedTuple(unittest.TestCase): |
|
14 |
|
15 def test_factory(self): |
|
16 Point = namedtuple('Point', 'x y') |
|
17 self.assertEqual(Point.__name__, 'Point') |
|
18 self.assertEqual(Point.__doc__, 'Point(x, y)') |
|
19 self.assertEqual(Point.__slots__, ()) |
|
20 self.assertEqual(Point.__module__, __name__) |
|
21 self.assertEqual(Point.__getitem__, tuple.__getitem__) |
|
22 self.assertEqual(Point._fields, ('x', 'y')) |
|
23 |
|
24 self.assertRaises(ValueError, namedtuple, 'abc%', 'efg ghi') # type has non-alpha char |
|
25 self.assertRaises(ValueError, namedtuple, 'class', 'efg ghi') # type has keyword |
|
26 self.assertRaises(ValueError, namedtuple, '9abc', 'efg ghi') # type starts with digit |
|
27 |
|
28 self.assertRaises(ValueError, namedtuple, 'abc', 'efg g%hi') # field with non-alpha char |
|
29 self.assertRaises(ValueError, namedtuple, 'abc', 'abc class') # field has keyword |
|
30 self.assertRaises(ValueError, namedtuple, 'abc', '8efg 9ghi') # field starts with digit |
|
31 self.assertRaises(ValueError, namedtuple, 'abc', '_efg ghi') # field with leading underscore |
|
32 self.assertRaises(ValueError, namedtuple, 'abc', 'efg efg ghi') # duplicate field |
|
33 |
|
34 namedtuple('Point0', 'x1 y2') # Verify that numbers are allowed in names |
|
35 namedtuple('_', 'a b c') # Test leading underscores in a typename |
|
36 |
|
37 nt = namedtuple('nt', u'the quick brown fox') # check unicode input |
|
38 self.assert_("u'" not in repr(nt._fields)) |
|
39 nt = namedtuple('nt', (u'the', u'quick')) # check unicode input |
|
40 self.assert_("u'" not in repr(nt._fields)) |
|
41 |
|
42 self.assertRaises(TypeError, Point._make, [11]) # catch too few args |
|
43 self.assertRaises(TypeError, Point._make, [11, 22, 33]) # catch too many args |
|
44 |
|
45 def test_instance(self): |
|
46 Point = namedtuple('Point', 'x y') |
|
47 p = Point(11, 22) |
|
48 self.assertEqual(p, Point(x=11, y=22)) |
|
49 self.assertEqual(p, Point(11, y=22)) |
|
50 self.assertEqual(p, Point(y=22, x=11)) |
|
51 self.assertEqual(p, Point(*(11, 22))) |
|
52 self.assertEqual(p, Point(**dict(x=11, y=22))) |
|
53 self.assertRaises(TypeError, Point, 1) # too few args |
|
54 self.assertRaises(TypeError, Point, 1, 2, 3) # too many args |
|
55 self.assertRaises(TypeError, eval, 'Point(XXX=1, y=2)', locals()) # wrong keyword argument |
|
56 self.assertRaises(TypeError, eval, 'Point(x=1)', locals()) # missing keyword argument |
|
57 self.assertEqual(repr(p), 'Point(x=11, y=22)') |
|
58 self.assert_('__dict__' not in dir(p)) # verify instance has no dict |
|
59 self.assert_('__weakref__' not in dir(p)) |
|
60 self.assertEqual(p, Point._make([11, 22])) # test _make classmethod |
|
61 self.assertEqual(p._fields, ('x', 'y')) # test _fields attribute |
|
62 self.assertEqual(p._replace(x=1), (1, 22)) # test _replace method |
|
63 self.assertEqual(p._asdict(), dict(x=11, y=22)) # test _asdict method |
|
64 |
|
65 try: |
|
66 p._replace(x=1, error=2) |
|
67 except ValueError: |
|
68 pass |
|
69 else: |
|
70 self._fail('Did not detect an incorrect fieldname') |
|
71 |
|
72 # verify that field string can have commas |
|
73 Point = namedtuple('Point', 'x, y') |
|
74 p = Point(x=11, y=22) |
|
75 self.assertEqual(repr(p), 'Point(x=11, y=22)') |
|
76 |
|
77 # verify that fieldspec can be a non-string sequence |
|
78 Point = namedtuple('Point', ('x', 'y')) |
|
79 p = Point(x=11, y=22) |
|
80 self.assertEqual(repr(p), 'Point(x=11, y=22)') |
|
81 |
|
82 def test_tupleness(self): |
|
83 Point = namedtuple('Point', 'x y') |
|
84 p = Point(11, 22) |
|
85 |
|
86 self.assert_(isinstance(p, tuple)) |
|
87 self.assertEqual(p, (11, 22)) # matches a real tuple |
|
88 self.assertEqual(tuple(p), (11, 22)) # coercable to a real tuple |
|
89 self.assertEqual(list(p), [11, 22]) # coercable to a list |
|
90 self.assertEqual(max(p), 22) # iterable |
|
91 self.assertEqual(max(*p), 22) # star-able |
|
92 x, y = p |
|
93 self.assertEqual(p, (x, y)) # unpacks like a tuple |
|
94 self.assertEqual((p[0], p[1]), (11, 22)) # indexable like a tuple |
|
95 self.assertRaises(IndexError, p.__getitem__, 3) |
|
96 |
|
97 self.assertEqual(p.x, x) |
|
98 self.assertEqual(p.y, y) |
|
99 self.assertRaises(AttributeError, eval, 'p.z', locals()) |
|
100 |
|
101 def test_odd_sizes(self): |
|
102 Zero = namedtuple('Zero', '') |
|
103 self.assertEqual(Zero(), ()) |
|
104 self.assertEqual(Zero._make([]), ()) |
|
105 self.assertEqual(repr(Zero()), 'Zero()') |
|
106 self.assertEqual(Zero()._asdict(), {}) |
|
107 self.assertEqual(Zero()._fields, ()) |
|
108 |
|
109 Dot = namedtuple('Dot', 'd') |
|
110 self.assertEqual(Dot(1), (1,)) |
|
111 self.assertEqual(Dot._make([1]), (1,)) |
|
112 self.assertEqual(Dot(1).d, 1) |
|
113 self.assertEqual(repr(Dot(1)), 'Dot(d=1)') |
|
114 self.assertEqual(Dot(1)._asdict(), {'d':1}) |
|
115 self.assertEqual(Dot(1)._replace(d=999), (999,)) |
|
116 self.assertEqual(Dot(1)._fields, ('d',)) |
|
117 |
|
118 n = 5000 |
|
119 import string, random |
|
120 names = list(set(''.join([random.choice(string.ascii_letters) |
|
121 for j in range(10)]) for i in range(n))) |
|
122 n = len(names) |
|
123 Big = namedtuple('Big', names) |
|
124 b = Big(*range(n)) |
|
125 self.assertEqual(b, tuple(range(n))) |
|
126 self.assertEqual(Big._make(range(n)), tuple(range(n))) |
|
127 for pos, name in enumerate(names): |
|
128 self.assertEqual(getattr(b, name), pos) |
|
129 repr(b) # make sure repr() doesn't blow-up |
|
130 d = b._asdict() |
|
131 d_expected = dict(zip(names, range(n))) |
|
132 self.assertEqual(d, d_expected) |
|
133 b2 = b._replace(**dict([(names[1], 999),(names[-5], 42)])) |
|
134 b2_expected = range(n) |
|
135 b2_expected[1] = 999 |
|
136 b2_expected[-5] = 42 |
|
137 self.assertEqual(b2, tuple(b2_expected)) |
|
138 self.assertEqual(b._fields, tuple(names)) |
|
139 |
|
140 def test_pickle(self): |
|
141 p = TestNT(x=10, y=20, z=30) |
|
142 for module in pickle, cPickle: |
|
143 loads = getattr(module, 'loads') |
|
144 dumps = getattr(module, 'dumps') |
|
145 for protocol in -1, 0, 1, 2: |
|
146 q = loads(dumps(p, protocol)) |
|
147 self.assertEqual(p, q) |
|
148 self.assertEqual(p._fields, q._fields) |
|
149 |
|
150 def test_copy(self): |
|
151 p = TestNT(x=10, y=20, z=30) |
|
152 for copier in copy.copy, copy.deepcopy: |
|
153 q = copier(p) |
|
154 self.assertEqual(p, q) |
|
155 self.assertEqual(p._fields, q._fields) |
|
156 |
|
157 class TestOneTrickPonyABCs(unittest.TestCase): |
|
158 |
|
159 def test_Hashable(self): |
|
160 # Check some non-hashables |
|
161 non_samples = [list(), set(), dict()] |
|
162 for x in non_samples: |
|
163 self.failIf(isinstance(x, Hashable), repr(x)) |
|
164 self.failIf(issubclass(type(x), Hashable), repr(type(x))) |
|
165 # Check some hashables |
|
166 samples = [None, |
|
167 int(), float(), complex(), |
|
168 str(), |
|
169 tuple(), frozenset(), |
|
170 int, list, object, type, |
|
171 ] |
|
172 for x in samples: |
|
173 self.failUnless(isinstance(x, Hashable), repr(x)) |
|
174 self.failUnless(issubclass(type(x), Hashable), repr(type(x))) |
|
175 self.assertRaises(TypeError, Hashable) |
|
176 # Check direct subclassing |
|
177 class H(Hashable): |
|
178 def __hash__(self): |
|
179 return super(H, self).__hash__() |
|
180 __eq__ = Hashable.__eq__ # Silence Py3k warning |
|
181 self.assertEqual(hash(H()), 0) |
|
182 self.failIf(issubclass(int, H)) |
|
183 |
|
184 def test_Iterable(self): |
|
185 # Check some non-iterables |
|
186 non_samples = [None, 42, 3.14, 1j] |
|
187 for x in non_samples: |
|
188 self.failIf(isinstance(x, Iterable), repr(x)) |
|
189 self.failIf(issubclass(type(x), Iterable), repr(type(x))) |
|
190 # Check some iterables |
|
191 samples = [str(), |
|
192 tuple(), list(), set(), frozenset(), dict(), |
|
193 dict().keys(), dict().items(), dict().values(), |
|
194 (lambda: (yield))(), |
|
195 (x for x in []), |
|
196 ] |
|
197 for x in samples: |
|
198 self.failUnless(isinstance(x, Iterable), repr(x)) |
|
199 self.failUnless(issubclass(type(x), Iterable), repr(type(x))) |
|
200 # Check direct subclassing |
|
201 class I(Iterable): |
|
202 def __iter__(self): |
|
203 return super(I, self).__iter__() |
|
204 self.assertEqual(list(I()), []) |
|
205 self.failIf(issubclass(str, I)) |
|
206 |
|
207 def test_Iterator(self): |
|
208 non_samples = [None, 42, 3.14, 1j, "".encode('ascii'), "", (), [], |
|
209 {}, set()] |
|
210 for x in non_samples: |
|
211 self.failIf(isinstance(x, Iterator), repr(x)) |
|
212 self.failIf(issubclass(type(x), Iterator), repr(type(x))) |
|
213 samples = [iter(str()), |
|
214 iter(tuple()), iter(list()), iter(dict()), |
|
215 iter(set()), iter(frozenset()), |
|
216 iter(dict().keys()), iter(dict().items()), |
|
217 iter(dict().values()), |
|
218 (lambda: (yield))(), |
|
219 (x for x in []), |
|
220 ] |
|
221 for x in samples: |
|
222 self.failUnless(isinstance(x, Iterator), repr(x)) |
|
223 self.failUnless(issubclass(type(x), Iterator), repr(type(x))) |
|
224 |
|
225 def test_Sized(self): |
|
226 non_samples = [None, 42, 3.14, 1j, |
|
227 (lambda: (yield))(), |
|
228 (x for x in []), |
|
229 ] |
|
230 for x in non_samples: |
|
231 self.failIf(isinstance(x, Sized), repr(x)) |
|
232 self.failIf(issubclass(type(x), Sized), repr(type(x))) |
|
233 samples = [str(), |
|
234 tuple(), list(), set(), frozenset(), dict(), |
|
235 dict().keys(), dict().items(), dict().values(), |
|
236 ] |
|
237 for x in samples: |
|
238 self.failUnless(isinstance(x, Sized), repr(x)) |
|
239 self.failUnless(issubclass(type(x), Sized), repr(type(x))) |
|
240 |
|
241 def test_Container(self): |
|
242 non_samples = [None, 42, 3.14, 1j, |
|
243 (lambda: (yield))(), |
|
244 (x for x in []), |
|
245 ] |
|
246 for x in non_samples: |
|
247 self.failIf(isinstance(x, Container), repr(x)) |
|
248 self.failIf(issubclass(type(x), Container), repr(type(x))) |
|
249 samples = [str(), |
|
250 tuple(), list(), set(), frozenset(), dict(), |
|
251 dict().keys(), dict().items(), |
|
252 ] |
|
253 for x in samples: |
|
254 self.failUnless(isinstance(x, Container), repr(x)) |
|
255 self.failUnless(issubclass(type(x), Container), repr(type(x))) |
|
256 |
|
257 def test_Callable(self): |
|
258 non_samples = [None, 42, 3.14, 1j, |
|
259 "", "".encode('ascii'), (), [], {}, set(), |
|
260 (lambda: (yield))(), |
|
261 (x for x in []), |
|
262 ] |
|
263 for x in non_samples: |
|
264 self.failIf(isinstance(x, Callable), repr(x)) |
|
265 self.failIf(issubclass(type(x), Callable), repr(type(x))) |
|
266 samples = [lambda: None, |
|
267 type, int, object, |
|
268 len, |
|
269 list.append, [].append, |
|
270 ] |
|
271 for x in samples: |
|
272 self.failUnless(isinstance(x, Callable), repr(x)) |
|
273 self.failUnless(issubclass(type(x), Callable), repr(type(x))) |
|
274 |
|
275 def test_direct_subclassing(self): |
|
276 for B in Hashable, Iterable, Iterator, Sized, Container, Callable: |
|
277 class C(B): |
|
278 pass |
|
279 self.failUnless(issubclass(C, B)) |
|
280 self.failIf(issubclass(int, C)) |
|
281 |
|
282 def test_registration(self): |
|
283 for B in Hashable, Iterable, Iterator, Sized, Container, Callable: |
|
284 class C: |
|
285 __metaclass__ = type |
|
286 __hash__ = None # Make sure it isn't hashable by default |
|
287 self.failIf(issubclass(C, B), B.__name__) |
|
288 B.register(C) |
|
289 self.failUnless(issubclass(C, B)) |
|
290 |
|
291 |
|
292 class TestCollectionABCs(unittest.TestCase): |
|
293 |
|
294 # XXX For now, we only test some virtual inheritance properties. |
|
295 # We should also test the proper behavior of the collection ABCs |
|
296 # as real base classes or mix-in classes. |
|
297 |
|
298 def test_Set(self): |
|
299 for sample in [set, frozenset]: |
|
300 self.failUnless(isinstance(sample(), Set)) |
|
301 self.failUnless(issubclass(sample, Set)) |
|
302 |
|
303 def test_hash_Set(self): |
|
304 class OneTwoThreeSet(Set): |
|
305 def __init__(self): |
|
306 self.contents = [1, 2, 3] |
|
307 def __contains__(self, x): |
|
308 return x in self.contents |
|
309 def __len__(self): |
|
310 return len(self.contents) |
|
311 def __iter__(self): |
|
312 return iter(self.contents) |
|
313 def __hash__(self): |
|
314 return self._hash() |
|
315 a, b = OneTwoThreeSet(), OneTwoThreeSet() |
|
316 self.failUnless(hash(a) == hash(b)) |
|
317 |
|
318 def test_MutableSet(self): |
|
319 self.failUnless(isinstance(set(), MutableSet)) |
|
320 self.failUnless(issubclass(set, MutableSet)) |
|
321 self.failIf(isinstance(frozenset(), MutableSet)) |
|
322 self.failIf(issubclass(frozenset, MutableSet)) |
|
323 |
|
324 def test_Mapping(self): |
|
325 for sample in [dict]: |
|
326 self.failUnless(isinstance(sample(), Mapping)) |
|
327 self.failUnless(issubclass(sample, Mapping)) |
|
328 |
|
329 def test_MutableMapping(self): |
|
330 for sample in [dict]: |
|
331 self.failUnless(isinstance(sample(), MutableMapping)) |
|
332 self.failUnless(issubclass(sample, MutableMapping)) |
|
333 |
|
334 def test_Sequence(self): |
|
335 for sample in [tuple, list, str]: |
|
336 self.failUnless(isinstance(sample(), Sequence)) |
|
337 self.failUnless(issubclass(sample, Sequence)) |
|
338 self.failUnless(issubclass(basestring, Sequence)) |
|
339 |
|
340 def test_MutableSequence(self): |
|
341 for sample in [tuple, str]: |
|
342 self.failIf(isinstance(sample(), MutableSequence)) |
|
343 self.failIf(issubclass(sample, MutableSequence)) |
|
344 for sample in [list]: |
|
345 self.failUnless(isinstance(sample(), MutableSequence)) |
|
346 self.failUnless(issubclass(sample, MutableSequence)) |
|
347 self.failIf(issubclass(basestring, MutableSequence)) |
|
348 |
|
349 import doctest, collections |
|
350 |
|
351 def test_main(verbose=None): |
|
352 NamedTupleDocs = doctest.DocTestSuite(module=collections) |
|
353 test_classes = [TestNamedTuple, NamedTupleDocs, TestOneTrickPonyABCs, TestCollectionABCs] |
|
354 test_support.run_unittest(*test_classes) |
|
355 test_support.run_doctest(collections, verbose) |
|
356 |
|
357 if __name__ == "__main__": |
|
358 test_main(verbose=True) |