blob: 99eb8cf9addb623fe33140d665f6167f0d8cd3d0 [file] [log] [blame]
Raymond Hettingerd1ef8542008-01-11 00:23:13 +00001import unittest, doctest
Raymond Hettingerc37e5e02007-03-01 06:16:43 +00002from test import test_support
Raymond Hettinger01a09572007-10-23 20:37:41 +00003from collections import namedtuple
Raymond Hettingere98839a2008-06-09 01:28:30 +00004import pickle, cPickle, copy
Guido van Rossum64c06e32007-11-22 00:55:51 +00005from collections import Hashable, Iterable, Iterator
6from collections import Sized, Container, Callable
7from collections import Set, MutableSet
8from collections import Mapping, MutableMapping
9from collections import Sequence, MutableSequence
10
Raymond Hettingere98839a2008-06-09 01:28:30 +000011TestNT = namedtuple('TestNT', 'x y z') # type used for pickle tests
Raymond Hettingerc37e5e02007-03-01 06:16:43 +000012
13class TestNamedTuple(unittest.TestCase):
14
15 def test_factory(self):
Raymond Hettinger01a09572007-10-23 20:37:41 +000016 Point = namedtuple('Point', 'x y')
Raymond Hettingerc37e5e02007-03-01 06:16:43 +000017 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__)
Raymond Hettingere0734e72008-01-04 03:22:53 +000022 self.assertEqual(Point._fields, ('x', 'y'))
Raymond Hettingerabfd8df2007-10-16 21:28:32 +000023
Raymond Hettinger01a09572007-10-23 20:37:41 +000024 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
Raymond Hettingerabfd8df2007-10-16 21:28:32 +000027
Raymond Hettinger01a09572007-10-23 20:37:41 +000028 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
Raymond Hettinger42da8742007-12-14 02:49:47 +000031 self.assertRaises(ValueError, namedtuple, 'abc', '_efg ghi') # field with leading underscore
Raymond Hettinger01a09572007-10-23 20:37:41 +000032 self.assertRaises(ValueError, namedtuple, 'abc', 'efg efg ghi') # duplicate field
Raymond Hettingerabfd8df2007-10-16 21:28:32 +000033
Raymond Hettinger01a09572007-10-23 20:37:41 +000034 namedtuple('Point0', 'x1 y2') # Verify that numbers are allowed in names
Raymond Hettinger42da8742007-12-14 02:49:47 +000035 namedtuple('_', 'a b c') # Test leading underscores in a typename
Raymond Hettingerc37e5e02007-03-01 06:16:43 +000036
Raymond Hettinger02740f72008-01-05 01:35:43 +000037 self.assertRaises(TypeError, Point._make, [11]) # catch too few args
38 self.assertRaises(TypeError, Point._make, [11, 22, 33]) # catch too many args
39
Raymond Hettingerc37e5e02007-03-01 06:16:43 +000040 def test_instance(self):
Raymond Hettinger01a09572007-10-23 20:37:41 +000041 Point = namedtuple('Point', 'x y')
Raymond Hettingerc37e5e02007-03-01 06:16:43 +000042 p = Point(11, 22)
43 self.assertEqual(p, Point(x=11, y=22))
44 self.assertEqual(p, Point(11, y=22))
45 self.assertEqual(p, Point(y=22, x=11))
46 self.assertEqual(p, Point(*(11, 22)))
47 self.assertEqual(p, Point(**dict(x=11, y=22)))
48 self.assertRaises(TypeError, Point, 1) # too few args
49 self.assertRaises(TypeError, Point, 1, 2, 3) # too many args
50 self.assertRaises(TypeError, eval, 'Point(XXX=1, y=2)', locals()) # wrong keyword argument
51 self.assertRaises(TypeError, eval, 'Point(x=1)', locals()) # missing keyword argument
52 self.assertEqual(repr(p), 'Point(x=11, y=22)')
53 self.assert_('__dict__' not in dir(p)) # verify instance has no dict
54 self.assert_('__weakref__' not in dir(p))
Raymond Hettinger02740f72008-01-05 01:35:43 +000055 self.assertEqual(p, Point._make([11, 22])) # test _make classmethod
Raymond Hettinger42da8742007-12-14 02:49:47 +000056 self.assertEqual(p._fields, ('x', 'y')) # test _fields attribute
57 self.assertEqual(p._replace(x=1), (1, 22)) # test _replace method
58 self.assertEqual(p._asdict(), dict(x=11, y=22)) # test _asdict method
Raymond Hettingerd36a60e2007-09-17 00:55:00 +000059
Raymond Hettinger1b50fd72008-01-05 02:17:24 +000060 try:
61 p._replace(x=1, error=2)
62 except ValueError:
63 pass
64 else:
65 self._fail('Did not detect an incorrect fieldname')
66
Raymond Hettingerd36a60e2007-09-17 00:55:00 +000067 # verify that field string can have commas
Raymond Hettinger01a09572007-10-23 20:37:41 +000068 Point = namedtuple('Point', 'x, y')
Raymond Hettingerd36a60e2007-09-17 00:55:00 +000069 p = Point(x=11, y=22)
70 self.assertEqual(repr(p), 'Point(x=11, y=22)')
Raymond Hettingerc37e5e02007-03-01 06:16:43 +000071
Raymond Hettinger2115bbc2007-10-08 09:14:28 +000072 # verify that fieldspec can be a non-string sequence
Raymond Hettinger01a09572007-10-23 20:37:41 +000073 Point = namedtuple('Point', ('x', 'y'))
Raymond Hettinger2115bbc2007-10-08 09:14:28 +000074 p = Point(x=11, y=22)
75 self.assertEqual(repr(p), 'Point(x=11, y=22)')
76
Raymond Hettingerc37e5e02007-03-01 06:16:43 +000077 def test_tupleness(self):
Raymond Hettinger01a09572007-10-23 20:37:41 +000078 Point = namedtuple('Point', 'x y')
Raymond Hettingerc37e5e02007-03-01 06:16:43 +000079 p = Point(11, 22)
80
81 self.assert_(isinstance(p, tuple))
82 self.assertEqual(p, (11, 22)) # matches a real tuple
83 self.assertEqual(tuple(p), (11, 22)) # coercable to a real tuple
84 self.assertEqual(list(p), [11, 22]) # coercable to a list
85 self.assertEqual(max(p), 22) # iterable
86 self.assertEqual(max(*p), 22) # star-able
87 x, y = p
88 self.assertEqual(p, (x, y)) # unpacks like a tuple
89 self.assertEqual((p[0], p[1]), (11, 22)) # indexable like a tuple
90 self.assertRaises(IndexError, p.__getitem__, 3)
91
92 self.assertEqual(p.x, x)
93 self.assertEqual(p.y, y)
94 self.assertRaises(AttributeError, eval, 'p.z', locals())
95
Raymond Hettinger2b03d452007-09-18 03:33:19 +000096 def test_odd_sizes(self):
Raymond Hettinger01a09572007-10-23 20:37:41 +000097 Zero = namedtuple('Zero', '')
Raymond Hettinger2b03d452007-09-18 03:33:19 +000098 self.assertEqual(Zero(), ())
Raymond Hettinger02740f72008-01-05 01:35:43 +000099 self.assertEqual(Zero._make([]), ())
Raymond Hettinger88880b22007-12-18 00:13:45 +0000100 self.assertEqual(repr(Zero()), 'Zero()')
101 self.assertEqual(Zero()._asdict(), {})
102 self.assertEqual(Zero()._fields, ())
103
Raymond Hettinger01a09572007-10-23 20:37:41 +0000104 Dot = namedtuple('Dot', 'd')
Raymond Hettinger2b03d452007-09-18 03:33:19 +0000105 self.assertEqual(Dot(1), (1,))
Raymond Hettinger02740f72008-01-05 01:35:43 +0000106 self.assertEqual(Dot._make([1]), (1,))
Raymond Hettinger88880b22007-12-18 00:13:45 +0000107 self.assertEqual(Dot(1).d, 1)
108 self.assertEqual(repr(Dot(1)), 'Dot(d=1)')
109 self.assertEqual(Dot(1)._asdict(), {'d':1})
110 self.assertEqual(Dot(1)._replace(d=999), (999,))
111 self.assertEqual(Dot(1)._fields, ('d',))
Raymond Hettinger2b03d452007-09-18 03:33:19 +0000112
Raymond Hettingere98839a2008-06-09 01:28:30 +0000113 n = 5000
Raymond Hettinger88880b22007-12-18 00:13:45 +0000114 import string, random
Georg Brandl0bb02992008-05-18 10:39:26 +0000115 names = list(set(''.join([random.choice(string.ascii_letters)
116 for j in range(10)]) for i in range(n)))
117 n = len(names)
Raymond Hettinger88880b22007-12-18 00:13:45 +0000118 Big = namedtuple('Big', names)
119 b = Big(*range(n))
120 self.assertEqual(b, tuple(range(n)))
Raymond Hettinger02740f72008-01-05 01:35:43 +0000121 self.assertEqual(Big._make(range(n)), tuple(range(n)))
Raymond Hettinger88880b22007-12-18 00:13:45 +0000122 for pos, name in enumerate(names):
123 self.assertEqual(getattr(b, name), pos)
124 repr(b) # make sure repr() doesn't blow-up
125 d = b._asdict()
126 d_expected = dict(zip(names, range(n)))
127 self.assertEqual(d, d_expected)
128 b2 = b._replace(**dict([(names[1], 999),(names[-5], 42)]))
129 b2_expected = range(n)
130 b2_expected[1] = 999
131 b2_expected[-5] = 42
132 self.assertEqual(b2, tuple(b2_expected))
133 self.assertEqual(b._fields, tuple(names))
Guido van Rossum64c06e32007-11-22 00:55:51 +0000134
Raymond Hettingere98839a2008-06-09 01:28:30 +0000135 def test_pickle(self):
136 p = TestNT(x=10, y=20, z=30)
137 for module in pickle, cPickle:
138 loads = getattr(module, 'loads')
139 dumps = getattr(module, 'dumps')
140 for protocol in -1, 0, 1, 2:
141 q = loads(dumps(p, protocol))
142 self.assertEqual(p, q)
143 self.assertEqual(p._fields, q._fields)
144
145 def test_copy(self):
146 p = TestNT(x=10, y=20, z=30)
147 for copier in copy.copy, copy.deepcopy:
148 q = copier(p)
149 self.assertEqual(p, q)
150 self.assertEqual(p._fields, q._fields)
151
Guido van Rossum64c06e32007-11-22 00:55:51 +0000152class TestOneTrickPonyABCs(unittest.TestCase):
153
154 def test_Hashable(self):
155 # Check some non-hashables
156 non_samples = [list(), set(), dict()]
157 for x in non_samples:
158 self.failIf(isinstance(x, Hashable), repr(x))
159 self.failIf(issubclass(type(x), Hashable), repr(type(x)))
160 # Check some hashables
161 samples = [None,
162 int(), float(), complex(),
163 str(),
164 tuple(), frozenset(),
165 int, list, object, type,
166 ]
167 for x in samples:
168 self.failUnless(isinstance(x, Hashable), repr(x))
169 self.failUnless(issubclass(type(x), Hashable), repr(type(x)))
170 self.assertRaises(TypeError, Hashable)
171 # Check direct subclassing
172 class H(Hashable):
173 def __hash__(self):
174 return super(H, self).__hash__()
175 self.assertEqual(hash(H()), 0)
176 self.failIf(issubclass(int, H))
177
178 def test_Iterable(self):
179 # Check some non-iterables
180 non_samples = [None, 42, 3.14, 1j]
181 for x in non_samples:
182 self.failIf(isinstance(x, Iterable), repr(x))
183 self.failIf(issubclass(type(x), Iterable), repr(type(x)))
184 # Check some iterables
185 samples = [str(),
186 tuple(), list(), set(), frozenset(), dict(),
187 dict().keys(), dict().items(), dict().values(),
188 (lambda: (yield))(),
189 (x for x in []),
190 ]
191 for x in samples:
192 self.failUnless(isinstance(x, Iterable), repr(x))
193 self.failUnless(issubclass(type(x), Iterable), repr(type(x)))
194 # Check direct subclassing
195 class I(Iterable):
196 def __iter__(self):
197 return super(I, self).__iter__()
198 self.assertEqual(list(I()), [])
199 self.failIf(issubclass(str, I))
200
201 def test_Iterator(self):
202 non_samples = [None, 42, 3.14, 1j, "".encode('ascii'), "", (), [],
203 {}, set()]
204 for x in non_samples:
205 self.failIf(isinstance(x, Iterator), repr(x))
206 self.failIf(issubclass(type(x), Iterator), repr(type(x)))
207 samples = [iter(str()),
208 iter(tuple()), iter(list()), iter(dict()),
209 iter(set()), iter(frozenset()),
210 iter(dict().keys()), iter(dict().items()),
211 iter(dict().values()),
212 (lambda: (yield))(),
213 (x for x in []),
214 ]
215 for x in samples:
216 self.failUnless(isinstance(x, Iterator), repr(x))
217 self.failUnless(issubclass(type(x), Iterator), repr(type(x)))
218
219 def test_Sized(self):
220 non_samples = [None, 42, 3.14, 1j,
221 (lambda: (yield))(),
222 (x for x in []),
223 ]
224 for x in non_samples:
225 self.failIf(isinstance(x, Sized), repr(x))
226 self.failIf(issubclass(type(x), Sized), repr(type(x)))
227 samples = [str(),
228 tuple(), list(), set(), frozenset(), dict(),
229 dict().keys(), dict().items(), dict().values(),
230 ]
231 for x in samples:
232 self.failUnless(isinstance(x, Sized), repr(x))
233 self.failUnless(issubclass(type(x), Sized), repr(type(x)))
234
235 def test_Container(self):
236 non_samples = [None, 42, 3.14, 1j,
237 (lambda: (yield))(),
238 (x for x in []),
239 ]
240 for x in non_samples:
241 self.failIf(isinstance(x, Container), repr(x))
242 self.failIf(issubclass(type(x), Container), repr(type(x)))
243 samples = [str(),
244 tuple(), list(), set(), frozenset(), dict(),
245 dict().keys(), dict().items(),
246 ]
247 for x in samples:
248 self.failUnless(isinstance(x, Container), repr(x))
249 self.failUnless(issubclass(type(x), Container), repr(type(x)))
250
251 def test_Callable(self):
252 non_samples = [None, 42, 3.14, 1j,
253 "", "".encode('ascii'), (), [], {}, set(),
254 (lambda: (yield))(),
255 (x for x in []),
256 ]
257 for x in non_samples:
258 self.failIf(isinstance(x, Callable), repr(x))
259 self.failIf(issubclass(type(x), Callable), repr(type(x)))
260 samples = [lambda: None,
261 type, int, object,
262 len,
263 list.append, [].append,
264 ]
265 for x in samples:
266 self.failUnless(isinstance(x, Callable), repr(x))
267 self.failUnless(issubclass(type(x), Callable), repr(type(x)))
268
269 def test_direct_subclassing(self):
270 for B in Hashable, Iterable, Iterator, Sized, Container, Callable:
271 class C(B):
272 pass
273 self.failUnless(issubclass(C, B))
274 self.failIf(issubclass(int, C))
275
276 def test_registration(self):
277 for B in Hashable, Iterable, Iterator, Sized, Container, Callable:
278 class C:
279 __metaclass__ = type
280 __hash__ = None # Make sure it isn't hashable by default
281 self.failIf(issubclass(C, B), B.__name__)
282 B.register(C)
283 self.failUnless(issubclass(C, B))
284
285
286class TestCollectionABCs(unittest.TestCase):
287
288 # XXX For now, we only test some virtual inheritance properties.
289 # We should also test the proper behavior of the collection ABCs
290 # as real base classes or mix-in classes.
291
292 def test_Set(self):
293 for sample in [set, frozenset]:
294 self.failUnless(isinstance(sample(), Set))
295 self.failUnless(issubclass(sample, Set))
296
Raymond Hettinger4c52f522008-06-23 03:29:28 +0000297 def test_hash_Set(self):
298 class OneTwoThreeSet(Set):
299 def __init__(self):
300 self.contents = [1, 2, 3]
301 def __contains__(self, x):
302 return x in self.contents
303 def __len__(self):
304 return len(self.contents)
305 def __iter__(self):
306 return iter(self.contents)
307 def __hash__(self):
308 return self._hash()
309 a, b = OneTwoThreeSet(), OneTwoThreeSet()
310 self.failUnless(hash(a) == hash(b))
311
Guido van Rossum64c06e32007-11-22 00:55:51 +0000312 def test_MutableSet(self):
313 self.failUnless(isinstance(set(), MutableSet))
314 self.failUnless(issubclass(set, MutableSet))
315 self.failIf(isinstance(frozenset(), MutableSet))
316 self.failIf(issubclass(frozenset, MutableSet))
317
318 def test_Mapping(self):
319 for sample in [dict]:
320 self.failUnless(isinstance(sample(), Mapping))
321 self.failUnless(issubclass(sample, Mapping))
322
323 def test_MutableMapping(self):
324 for sample in [dict]:
325 self.failUnless(isinstance(sample(), MutableMapping))
326 self.failUnless(issubclass(sample, MutableMapping))
327
328 def test_Sequence(self):
329 for sample in [tuple, list, str]:
330 self.failUnless(isinstance(sample(), Sequence))
331 self.failUnless(issubclass(sample, Sequence))
332 self.failUnless(issubclass(basestring, Sequence))
333
334 def test_MutableSequence(self):
335 for sample in [tuple, str]:
336 self.failIf(isinstance(sample(), MutableSequence))
337 self.failIf(issubclass(sample, MutableSequence))
338 for sample in [list]:
339 self.failUnless(isinstance(sample(), MutableSequence))
340 self.failUnless(issubclass(sample, MutableSequence))
341 self.failIf(issubclass(basestring, MutableSequence))
342
Raymond Hettingerd1ef8542008-01-11 00:23:13 +0000343import doctest, collections
Guido van Rossum64c06e32007-11-22 00:55:51 +0000344
Raymond Hettingerc37e5e02007-03-01 06:16:43 +0000345def test_main(verbose=None):
Amaury Forgeot d'Arccb0f2ad2008-04-02 00:55:04 +0000346 NamedTupleDocs = doctest.DocTestSuite(module=collections)
Raymond Hettingerd1ef8542008-01-11 00:23:13 +0000347 test_classes = [TestNamedTuple, NamedTupleDocs, TestOneTrickPonyABCs, TestCollectionABCs]
Raymond Hettingerc37e5e02007-03-01 06:16:43 +0000348 test_support.run_unittest(*test_classes)
Amaury Forgeot d'Arccb0f2ad2008-04-02 00:55:04 +0000349 test_support.run_doctest(collections, verbose)
Raymond Hettingerc37e5e02007-03-01 06:16:43 +0000350
351if __name__ == "__main__":
352 test_main(verbose=True)