blob: 5e71399004d5bef1a1ce04956a01fd26c0b7d6e8 [file] [log] [blame]
Raymond Hettingerc37e5e02007-03-01 06:16:43 +00001import unittest
2from test import test_support
Raymond Hettinger01a09572007-10-23 20:37:41 +00003from collections import namedtuple
Guido van Rossum64c06e32007-11-22 00:55:51 +00004from collections import Hashable, Iterable, Iterator
5from collections import Sized, Container, Callable
6from collections import Set, MutableSet
7from collections import Mapping, MutableMapping
8from collections import Sequence, MutableSequence
9
Raymond Hettingerc37e5e02007-03-01 06:16:43 +000010
11class TestNamedTuple(unittest.TestCase):
12
13 def test_factory(self):
Raymond Hettinger01a09572007-10-23 20:37:41 +000014 Point = namedtuple('Point', 'x y')
Raymond Hettingerc37e5e02007-03-01 06:16:43 +000015 self.assertEqual(Point.__name__, 'Point')
16 self.assertEqual(Point.__doc__, 'Point(x, y)')
17 self.assertEqual(Point.__slots__, ())
18 self.assertEqual(Point.__module__, __name__)
19 self.assertEqual(Point.__getitem__, tuple.__getitem__)
Raymond Hettingere0734e72008-01-04 03:22:53 +000020 self.assertEqual(Point._fields, ('x', 'y'))
Raymond Hettingerabfd8df2007-10-16 21:28:32 +000021
Raymond Hettinger01a09572007-10-23 20:37:41 +000022 self.assertRaises(ValueError, namedtuple, 'abc%', 'efg ghi') # type has non-alpha char
23 self.assertRaises(ValueError, namedtuple, 'class', 'efg ghi') # type has keyword
24 self.assertRaises(ValueError, namedtuple, '9abc', 'efg ghi') # type starts with digit
Raymond Hettingerabfd8df2007-10-16 21:28:32 +000025
Raymond Hettinger01a09572007-10-23 20:37:41 +000026 self.assertRaises(ValueError, namedtuple, 'abc', 'efg g%hi') # field with non-alpha char
27 self.assertRaises(ValueError, namedtuple, 'abc', 'abc class') # field has keyword
28 self.assertRaises(ValueError, namedtuple, 'abc', '8efg 9ghi') # field starts with digit
Raymond Hettinger42da8742007-12-14 02:49:47 +000029 self.assertRaises(ValueError, namedtuple, 'abc', '_efg ghi') # field with leading underscore
Raymond Hettinger01a09572007-10-23 20:37:41 +000030 self.assertRaises(ValueError, namedtuple, 'abc', 'efg efg ghi') # duplicate field
Raymond Hettingerabfd8df2007-10-16 21:28:32 +000031
Raymond Hettinger01a09572007-10-23 20:37:41 +000032 namedtuple('Point0', 'x1 y2') # Verify that numbers are allowed in names
Raymond Hettinger42da8742007-12-14 02:49:47 +000033 namedtuple('_', 'a b c') # Test leading underscores in a typename
Raymond Hettingerc37e5e02007-03-01 06:16:43 +000034
35 def test_instance(self):
Raymond Hettinger01a09572007-10-23 20:37:41 +000036 Point = namedtuple('Point', 'x y')
Raymond Hettingerc37e5e02007-03-01 06:16:43 +000037 p = Point(11, 22)
38 self.assertEqual(p, Point(x=11, y=22))
39 self.assertEqual(p, Point(11, y=22))
40 self.assertEqual(p, Point(y=22, x=11))
41 self.assertEqual(p, Point(*(11, 22)))
42 self.assertEqual(p, Point(**dict(x=11, y=22)))
43 self.assertRaises(TypeError, Point, 1) # too few args
44 self.assertRaises(TypeError, Point, 1, 2, 3) # too many args
45 self.assertRaises(TypeError, eval, 'Point(XXX=1, y=2)', locals()) # wrong keyword argument
46 self.assertRaises(TypeError, eval, 'Point(x=1)', locals()) # missing keyword argument
47 self.assertEqual(repr(p), 'Point(x=11, y=22)')
48 self.assert_('__dict__' not in dir(p)) # verify instance has no dict
49 self.assert_('__weakref__' not in dir(p))
Raymond Hettinger85dfcf32007-12-18 23:51:15 +000050 self.assertEqual(p, Point._cast([11, 22])) # test _cast classmethod
Raymond Hettinger42da8742007-12-14 02:49:47 +000051 self.assertEqual(p._fields, ('x', 'y')) # test _fields attribute
52 self.assertEqual(p._replace(x=1), (1, 22)) # test _replace method
53 self.assertEqual(p._asdict(), dict(x=11, y=22)) # test _asdict method
Raymond Hettingerd36a60e2007-09-17 00:55:00 +000054
55 # verify that field string can have commas
Raymond Hettinger01a09572007-10-23 20:37:41 +000056 Point = namedtuple('Point', 'x, y')
Raymond Hettingerd36a60e2007-09-17 00:55:00 +000057 p = Point(x=11, y=22)
58 self.assertEqual(repr(p), 'Point(x=11, y=22)')
Raymond Hettingerc37e5e02007-03-01 06:16:43 +000059
Raymond Hettinger2115bbc2007-10-08 09:14:28 +000060 # verify that fieldspec can be a non-string sequence
Raymond Hettinger01a09572007-10-23 20:37:41 +000061 Point = namedtuple('Point', ('x', 'y'))
Raymond Hettinger2115bbc2007-10-08 09:14:28 +000062 p = Point(x=11, y=22)
63 self.assertEqual(repr(p), 'Point(x=11, y=22)')
64
Raymond Hettingerc37e5e02007-03-01 06:16:43 +000065 def test_tupleness(self):
Raymond Hettinger01a09572007-10-23 20:37:41 +000066 Point = namedtuple('Point', 'x y')
Raymond Hettingerc37e5e02007-03-01 06:16:43 +000067 p = Point(11, 22)
68
69 self.assert_(isinstance(p, tuple))
70 self.assertEqual(p, (11, 22)) # matches a real tuple
71 self.assertEqual(tuple(p), (11, 22)) # coercable to a real tuple
72 self.assertEqual(list(p), [11, 22]) # coercable to a list
73 self.assertEqual(max(p), 22) # iterable
74 self.assertEqual(max(*p), 22) # star-able
75 x, y = p
76 self.assertEqual(p, (x, y)) # unpacks like a tuple
77 self.assertEqual((p[0], p[1]), (11, 22)) # indexable like a tuple
78 self.assertRaises(IndexError, p.__getitem__, 3)
79
80 self.assertEqual(p.x, x)
81 self.assertEqual(p.y, y)
82 self.assertRaises(AttributeError, eval, 'p.z', locals())
83
Raymond Hettinger2b03d452007-09-18 03:33:19 +000084 def test_odd_sizes(self):
Raymond Hettinger01a09572007-10-23 20:37:41 +000085 Zero = namedtuple('Zero', '')
Raymond Hettinger2b03d452007-09-18 03:33:19 +000086 self.assertEqual(Zero(), ())
Raymond Hettinger85dfcf32007-12-18 23:51:15 +000087 self.assertEqual(Zero._cast([]), ())
Raymond Hettinger88880b22007-12-18 00:13:45 +000088 self.assertEqual(repr(Zero()), 'Zero()')
89 self.assertEqual(Zero()._asdict(), {})
90 self.assertEqual(Zero()._fields, ())
91
Raymond Hettinger01a09572007-10-23 20:37:41 +000092 Dot = namedtuple('Dot', 'd')
Raymond Hettinger2b03d452007-09-18 03:33:19 +000093 self.assertEqual(Dot(1), (1,))
Raymond Hettinger85dfcf32007-12-18 23:51:15 +000094 self.assertEqual(Dot._cast([1]), (1,))
Raymond Hettinger88880b22007-12-18 00:13:45 +000095 self.assertEqual(Dot(1).d, 1)
96 self.assertEqual(repr(Dot(1)), 'Dot(d=1)')
97 self.assertEqual(Dot(1)._asdict(), {'d':1})
98 self.assertEqual(Dot(1)._replace(d=999), (999,))
99 self.assertEqual(Dot(1)._fields, ('d',))
Raymond Hettinger2b03d452007-09-18 03:33:19 +0000100
Raymond Hettinger88880b22007-12-18 00:13:45 +0000101 n = 10000
102 import string, random
103 names = [''.join([random.choice(string.letters) for j in range(10)]) for i in range(n)]
104 Big = namedtuple('Big', names)
105 b = Big(*range(n))
106 self.assertEqual(b, tuple(range(n)))
Raymond Hettinger85dfcf32007-12-18 23:51:15 +0000107 self.assertEqual(Big._cast(range(n)), tuple(range(n)))
Raymond Hettinger88880b22007-12-18 00:13:45 +0000108 for pos, name in enumerate(names):
109 self.assertEqual(getattr(b, name), pos)
110 repr(b) # make sure repr() doesn't blow-up
111 d = b._asdict()
112 d_expected = dict(zip(names, range(n)))
113 self.assertEqual(d, d_expected)
114 b2 = b._replace(**dict([(names[1], 999),(names[-5], 42)]))
115 b2_expected = range(n)
116 b2_expected[1] = 999
117 b2_expected[-5] = 42
118 self.assertEqual(b2, tuple(b2_expected))
119 self.assertEqual(b._fields, tuple(names))
Guido van Rossum64c06e32007-11-22 00:55:51 +0000120
121class TestOneTrickPonyABCs(unittest.TestCase):
122
123 def test_Hashable(self):
124 # Check some non-hashables
125 non_samples = [list(), set(), dict()]
126 for x in non_samples:
127 self.failIf(isinstance(x, Hashable), repr(x))
128 self.failIf(issubclass(type(x), Hashable), repr(type(x)))
129 # Check some hashables
130 samples = [None,
131 int(), float(), complex(),
132 str(),
133 tuple(), frozenset(),
134 int, list, object, type,
135 ]
136 for x in samples:
137 self.failUnless(isinstance(x, Hashable), repr(x))
138 self.failUnless(issubclass(type(x), Hashable), repr(type(x)))
139 self.assertRaises(TypeError, Hashable)
140 # Check direct subclassing
141 class H(Hashable):
142 def __hash__(self):
143 return super(H, self).__hash__()
144 self.assertEqual(hash(H()), 0)
145 self.failIf(issubclass(int, H))
146
147 def test_Iterable(self):
148 # Check some non-iterables
149 non_samples = [None, 42, 3.14, 1j]
150 for x in non_samples:
151 self.failIf(isinstance(x, Iterable), repr(x))
152 self.failIf(issubclass(type(x), Iterable), repr(type(x)))
153 # Check some iterables
154 samples = [str(),
155 tuple(), list(), set(), frozenset(), dict(),
156 dict().keys(), dict().items(), dict().values(),
157 (lambda: (yield))(),
158 (x for x in []),
159 ]
160 for x in samples:
161 self.failUnless(isinstance(x, Iterable), repr(x))
162 self.failUnless(issubclass(type(x), Iterable), repr(type(x)))
163 # Check direct subclassing
164 class I(Iterable):
165 def __iter__(self):
166 return super(I, self).__iter__()
167 self.assertEqual(list(I()), [])
168 self.failIf(issubclass(str, I))
169
170 def test_Iterator(self):
171 non_samples = [None, 42, 3.14, 1j, "".encode('ascii'), "", (), [],
172 {}, set()]
173 for x in non_samples:
174 self.failIf(isinstance(x, Iterator), repr(x))
175 self.failIf(issubclass(type(x), Iterator), repr(type(x)))
176 samples = [iter(str()),
177 iter(tuple()), iter(list()), iter(dict()),
178 iter(set()), iter(frozenset()),
179 iter(dict().keys()), iter(dict().items()),
180 iter(dict().values()),
181 (lambda: (yield))(),
182 (x for x in []),
183 ]
184 for x in samples:
185 self.failUnless(isinstance(x, Iterator), repr(x))
186 self.failUnless(issubclass(type(x), Iterator), repr(type(x)))
187
188 def test_Sized(self):
189 non_samples = [None, 42, 3.14, 1j,
190 (lambda: (yield))(),
191 (x for x in []),
192 ]
193 for x in non_samples:
194 self.failIf(isinstance(x, Sized), repr(x))
195 self.failIf(issubclass(type(x), Sized), repr(type(x)))
196 samples = [str(),
197 tuple(), list(), set(), frozenset(), dict(),
198 dict().keys(), dict().items(), dict().values(),
199 ]
200 for x in samples:
201 self.failUnless(isinstance(x, Sized), repr(x))
202 self.failUnless(issubclass(type(x), Sized), repr(type(x)))
203
204 def test_Container(self):
205 non_samples = [None, 42, 3.14, 1j,
206 (lambda: (yield))(),
207 (x for x in []),
208 ]
209 for x in non_samples:
210 self.failIf(isinstance(x, Container), repr(x))
211 self.failIf(issubclass(type(x), Container), repr(type(x)))
212 samples = [str(),
213 tuple(), list(), set(), frozenset(), dict(),
214 dict().keys(), dict().items(),
215 ]
216 for x in samples:
217 self.failUnless(isinstance(x, Container), repr(x))
218 self.failUnless(issubclass(type(x), Container), repr(type(x)))
219
220 def test_Callable(self):
221 non_samples = [None, 42, 3.14, 1j,
222 "", "".encode('ascii'), (), [], {}, set(),
223 (lambda: (yield))(),
224 (x for x in []),
225 ]
226 for x in non_samples:
227 self.failIf(isinstance(x, Callable), repr(x))
228 self.failIf(issubclass(type(x), Callable), repr(type(x)))
229 samples = [lambda: None,
230 type, int, object,
231 len,
232 list.append, [].append,
233 ]
234 for x in samples:
235 self.failUnless(isinstance(x, Callable), repr(x))
236 self.failUnless(issubclass(type(x), Callable), repr(type(x)))
237
238 def test_direct_subclassing(self):
239 for B in Hashable, Iterable, Iterator, Sized, Container, Callable:
240 class C(B):
241 pass
242 self.failUnless(issubclass(C, B))
243 self.failIf(issubclass(int, C))
244
245 def test_registration(self):
246 for B in Hashable, Iterable, Iterator, Sized, Container, Callable:
247 class C:
248 __metaclass__ = type
249 __hash__ = None # Make sure it isn't hashable by default
250 self.failIf(issubclass(C, B), B.__name__)
251 B.register(C)
252 self.failUnless(issubclass(C, B))
253
254
255class TestCollectionABCs(unittest.TestCase):
256
257 # XXX For now, we only test some virtual inheritance properties.
258 # We should also test the proper behavior of the collection ABCs
259 # as real base classes or mix-in classes.
260
261 def test_Set(self):
262 for sample in [set, frozenset]:
263 self.failUnless(isinstance(sample(), Set))
264 self.failUnless(issubclass(sample, Set))
265
266 def test_MutableSet(self):
267 self.failUnless(isinstance(set(), MutableSet))
268 self.failUnless(issubclass(set, MutableSet))
269 self.failIf(isinstance(frozenset(), MutableSet))
270 self.failIf(issubclass(frozenset, MutableSet))
271
272 def test_Mapping(self):
273 for sample in [dict]:
274 self.failUnless(isinstance(sample(), Mapping))
275 self.failUnless(issubclass(sample, Mapping))
276
277 def test_MutableMapping(self):
278 for sample in [dict]:
279 self.failUnless(isinstance(sample(), MutableMapping))
280 self.failUnless(issubclass(sample, MutableMapping))
281
282 def test_Sequence(self):
283 for sample in [tuple, list, str]:
284 self.failUnless(isinstance(sample(), Sequence))
285 self.failUnless(issubclass(sample, Sequence))
286 self.failUnless(issubclass(basestring, Sequence))
287
288 def test_MutableSequence(self):
289 for sample in [tuple, str]:
290 self.failIf(isinstance(sample(), MutableSequence))
291 self.failIf(issubclass(sample, MutableSequence))
292 for sample in [list]:
293 self.failUnless(isinstance(sample(), MutableSequence))
294 self.failUnless(issubclass(sample, MutableSequence))
295 self.failIf(issubclass(basestring, MutableSequence))
296
297
Raymond Hettingerc37e5e02007-03-01 06:16:43 +0000298def test_main(verbose=None):
Raymond Hettinger5a41daf2007-05-19 01:11:16 +0000299 import collections as CollectionsModule
Guido van Rossum64c06e32007-11-22 00:55:51 +0000300 test_classes = [TestNamedTuple, TestOneTrickPonyABCs, TestCollectionABCs]
Raymond Hettingerc37e5e02007-03-01 06:16:43 +0000301 test_support.run_unittest(*test_classes)
Raymond Hettinger5a41daf2007-05-19 01:11:16 +0000302 test_support.run_doctest(CollectionsModule, verbose)
Raymond Hettingerc37e5e02007-03-01 06:16:43 +0000303
304if __name__ == "__main__":
305 test_main(verbose=True)