PageRenderTime 72ms CodeModel.GetById 13ms app.highlight 53ms RepoModel.GetById 1ms app.codeStats 0ms

/Lib/test/test_collections.py

http://unladen-swallow.googlecode.com/
Python | 493 lines | 442 code | 29 blank | 22 comment | 29 complexity | bdf7a1560460581f4257f298e42e0ddb MD5 | raw file
  1import unittest, doctest, sys
  2from test import test_support
  3from collections import namedtuple
  4import pickle, cPickle, copy
  5import keyword
  6import re
  7from collections import Hashable, Iterable, Iterator
  8from collections import Sized, Container, Callable
  9from collections import Set, MutableSet
 10from collections import Mapping, MutableMapping
 11from collections import Sequence, MutableSequence
 12
 13TestNT = namedtuple('TestNT', 'x y z')    # type used for pickle tests
 14
 15class TestNamedTuple(unittest.TestCase):
 16
 17    def test_factory(self):
 18        Point = namedtuple('Point', 'x y')
 19        self.assertEqual(Point.__name__, 'Point')
 20        # Docstrings are omitted with -O2 and above, so this test doesn't make
 21        # any sense.
 22        if sys.flags.optimize <= 1:
 23            self.assertEqual(Point.__doc__, 'Point(x, y)')
 24        self.assertEqual(Point.__slots__, ())
 25        self.assertEqual(Point.__module__, __name__)
 26        self.assertEqual(Point.__getitem__, tuple.__getitem__)
 27        self.assertEqual(Point._fields, ('x', 'y'))
 28
 29        self.assertRaises(ValueError, namedtuple, 'abc%', 'efg ghi')       # type has non-alpha char
 30        self.assertRaises(ValueError, namedtuple, 'class', 'efg ghi')      # type has keyword
 31        self.assertRaises(ValueError, namedtuple, '9abc', 'efg ghi')       # type starts with digit
 32
 33        self.assertRaises(ValueError, namedtuple, 'abc', 'efg g%hi')       # field with non-alpha char
 34        self.assertRaises(ValueError, namedtuple, 'abc', 'abc class')      # field has keyword
 35        self.assertRaises(ValueError, namedtuple, 'abc', '8efg 9ghi')      # field starts with digit
 36        self.assertRaises(ValueError, namedtuple, 'abc', '_efg ghi')       # field with leading underscore
 37        self.assertRaises(ValueError, namedtuple, 'abc', 'efg efg ghi')    # duplicate field
 38
 39        namedtuple('Point0', 'x1 y2')   # Verify that numbers are allowed in names
 40        namedtuple('_', 'a b c')        # Test leading underscores in a typename
 41
 42        nt = namedtuple('nt', u'the quick brown fox')                       # check unicode input
 43        self.assert_("u'" not in repr(nt._fields))
 44        nt = namedtuple('nt', (u'the', u'quick'))                           # check unicode input
 45        self.assert_("u'" not in repr(nt._fields))
 46
 47        self.assertRaises(TypeError, Point._make, [11])                     # catch too few args
 48        self.assertRaises(TypeError, Point._make, [11, 22, 33])             # catch too many args
 49
 50    def test_instance(self):
 51        Point = namedtuple('Point', 'x y')
 52        p = Point(11, 22)
 53        self.assertEqual(p, Point(x=11, y=22))
 54        self.assertEqual(p, Point(11, y=22))
 55        self.assertEqual(p, Point(y=22, x=11))
 56        self.assertEqual(p, Point(*(11, 22)))
 57        self.assertEqual(p, Point(**dict(x=11, y=22)))
 58        self.assertRaises(TypeError, Point, 1)                              # too few args
 59        self.assertRaises(TypeError, Point, 1, 2, 3)                        # too many args
 60        self.assertRaises(TypeError, eval, 'Point(XXX=1, y=2)', locals())   # wrong keyword argument
 61        self.assertRaises(TypeError, eval, 'Point(x=1)', locals())          # missing keyword argument
 62        self.assertEqual(repr(p), 'Point(x=11, y=22)')
 63        self.assert_('__dict__' not in dir(p))                              # verify instance has no dict
 64        self.assert_('__weakref__' not in dir(p))
 65        self.assertEqual(p, Point._make([11, 22]))                          # test _make classmethod
 66        self.assertEqual(p._fields, ('x', 'y'))                             # test _fields attribute
 67        self.assertEqual(p._replace(x=1), (1, 22))                          # test _replace method
 68        self.assertEqual(p._asdict(), dict(x=11, y=22))                     # test _asdict method
 69
 70        try:
 71            p._replace(x=1, error=2)
 72        except ValueError:
 73            pass
 74        else:
 75            self._fail('Did not detect an incorrect fieldname')
 76
 77        # verify that field string can have commas
 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        # verify that fieldspec can be a non-string sequence
 83        Point = namedtuple('Point', ('x', 'y'))
 84        p = Point(x=11, y=22)
 85        self.assertEqual(repr(p), 'Point(x=11, y=22)')
 86
 87    def test_tupleness(self):
 88        Point = namedtuple('Point', 'x y')
 89        p = Point(11, 22)
 90
 91        self.assert_(isinstance(p, tuple))
 92        self.assertEqual(p, (11, 22))                                       # matches a real tuple
 93        self.assertEqual(tuple(p), (11, 22))                                # coercable to a real tuple
 94        self.assertEqual(list(p), [11, 22])                                 # coercable to a list
 95        self.assertEqual(max(p), 22)                                        # iterable
 96        self.assertEqual(max(*p), 22)                                       # star-able
 97        x, y = p
 98        self.assertEqual(p, (x, y))                                         # unpacks like a tuple
 99        self.assertEqual((p[0], p[1]), (11, 22))                            # indexable like a tuple
100        self.assertRaises(IndexError, p.__getitem__, 3)
101
102        self.assertEqual(p.x, x)
103        self.assertEqual(p.y, y)
104        self.assertRaises(AttributeError, eval, 'p.z', locals())
105
106    def test_odd_sizes(self):
107        Zero = namedtuple('Zero', '')
108        self.assertEqual(Zero(), ())
109        self.assertEqual(Zero._make([]), ())
110        self.assertEqual(repr(Zero()), 'Zero()')
111        self.assertEqual(Zero()._asdict(), {})
112        self.assertEqual(Zero()._fields, ())
113
114        Dot = namedtuple('Dot', 'd')
115        self.assertEqual(Dot(1), (1,))
116        self.assertEqual(Dot._make([1]), (1,))
117        self.assertEqual(Dot(1).d, 1)
118        self.assertEqual(repr(Dot(1)), 'Dot(d=1)')
119        self.assertEqual(Dot(1)._asdict(), {'d':1})
120        self.assertEqual(Dot(1)._replace(d=999), (999,))
121        self.assertEqual(Dot(1)._fields, ('d',))
122
123        n = 5000
124        import string, random
125        names = list(set(''.join([random.choice(string.ascii_letters)
126                                  for j in range(10)]) for i in range(n)))
127        n = len(names)
128        Big = namedtuple('Big', names)
129        b = Big(*range(n))
130        self.assertEqual(b, tuple(range(n)))
131        self.assertEqual(Big._make(range(n)), tuple(range(n)))
132        for pos, name in enumerate(names):
133            self.assertEqual(getattr(b, name), pos)
134        repr(b)                                 # make sure repr() doesn't blow-up
135        d = b._asdict()
136        d_expected = dict(zip(names, range(n)))
137        self.assertEqual(d, d_expected)
138        b2 = b._replace(**dict([(names[1], 999),(names[-5], 42)]))
139        b2_expected = range(n)
140        b2_expected[1] = 999
141        b2_expected[-5] = 42
142        self.assertEqual(b2, tuple(b2_expected))
143        self.assertEqual(b._fields, tuple(names))
144
145    def test_pickle(self):
146        p = TestNT(x=10, y=20, z=30)
147        for module in pickle, cPickle:
148            loads = getattr(module, 'loads')
149            dumps = getattr(module, 'dumps')
150            for protocol in -1, 0, 1, 2:
151                q = loads(dumps(p, protocol))
152                self.assertEqual(p, q)
153                self.assertEqual(p._fields, q._fields)
154
155    def test_copy(self):
156        p = TestNT(x=10, y=20, z=30)
157        for copier in copy.copy, copy.deepcopy:
158            q = copier(p)
159            self.assertEqual(p, q)
160            self.assertEqual(p._fields, q._fields)
161
162    def test_name_conflicts(self):
163        # Some names like "self", "cls", "tuple", "itemgetter", and "property"
164        # failed when used as field names.  Test to make sure these now work.
165        T = namedtuple('T', 'itemgetter property self cls tuple')
166        t = T(1, 2, 3, 4, 5)
167        self.assertEqual(t, (1,2,3,4,5))
168        newt = t._replace(itemgetter=10, property=20, self=30, cls=40, tuple=50)
169        self.assertEqual(newt, (10,20,30,40,50))
170
171        # Broader test of all interesting names in a template
172        with test_support.captured_stdout() as template:
173            T = namedtuple('T', 'x', verbose=True)
174        words = set(re.findall('[A-Za-z]+', template.getvalue()))
175        words -= set(keyword.kwlist)
176        T = namedtuple('T', words)
177        # test __new__
178        values = tuple(range(len(words)))
179        t = T(*values)
180        self.assertEqual(t, values)
181        t = T(**dict(zip(T._fields, values)))
182        self.assertEqual(t, values)
183        # test _make
184        t = T._make(values)
185        self.assertEqual(t, values)
186        # exercise __repr__
187        repr(t)
188        # test _asdict
189        self.assertEqual(t._asdict(), dict(zip(T._fields, values)))
190        # test _replace
191        t = T._make(values)
192        newvalues = tuple(v*10 for v in values)
193        newt = t._replace(**dict(zip(T._fields, newvalues)))
194        self.assertEqual(newt, newvalues)
195        # test _fields
196        self.assertEqual(T._fields, tuple(words))
197        # test __getnewargs__
198        self.assertEqual(t.__getnewargs__(), values)
199
200class ABCTestCase(unittest.TestCase):
201
202    def validate_abstract_methods(self, abc, *names):
203        methodstubs = dict.fromkeys(names, lambda s, *args: 0)
204
205        # everything should work will all required methods are present
206        C = type('C', (abc,), methodstubs)
207        C()
208
209        # instantiation should fail if a required method is missing
210        for name in names:
211            stubs = methodstubs.copy()
212            del stubs[name]
213            C = type('C', (abc,), stubs)
214            self.assertRaises(TypeError, C, name)
215
216
217class TestOneTrickPonyABCs(ABCTestCase):
218
219    def test_Hashable(self):
220        # Check some non-hashables
221        non_samples = [list(), set(), dict()]
222        for x in non_samples:
223            self.failIf(isinstance(x, Hashable), repr(x))
224            self.failIf(issubclass(type(x), Hashable), repr(type(x)))
225        # Check some hashables
226        samples = [None,
227                   int(), float(), complex(),
228                   str(),
229                   tuple(), frozenset(),
230                   int, list, object, type,
231                   ]
232        for x in samples:
233            self.failUnless(isinstance(x, Hashable), repr(x))
234            self.failUnless(issubclass(type(x), Hashable), repr(type(x)))
235        self.assertRaises(TypeError, Hashable)
236        # Check direct subclassing
237        class H(Hashable):
238            def __hash__(self):
239                return super(H, self).__hash__()
240            __eq__ = Hashable.__eq__ # Silence Py3k warning
241        self.assertEqual(hash(H()), 0)
242        self.failIf(issubclass(int, H))
243        self.validate_abstract_methods(Hashable, '__hash__')
244
245    def test_Iterable(self):
246        # Check some non-iterables
247        non_samples = [None, 42, 3.14, 1j]
248        for x in non_samples:
249            self.failIf(isinstance(x, Iterable), repr(x))
250            self.failIf(issubclass(type(x), Iterable), repr(type(x)))
251        # Check some iterables
252        samples = [str(),
253                   tuple(), list(), set(), frozenset(), dict(),
254                   dict().keys(), dict().items(), dict().values(),
255                   (lambda: (yield))(),
256                   (x for x in []),
257                   ]
258        for x in samples:
259            self.failUnless(isinstance(x, Iterable), repr(x))
260            self.failUnless(issubclass(type(x), Iterable), repr(type(x)))
261        # Check direct subclassing
262        class I(Iterable):
263            def __iter__(self):
264                return super(I, self).__iter__()
265        self.assertEqual(list(I()), [])
266        self.failIf(issubclass(str, I))
267        self.validate_abstract_methods(Iterable, '__iter__')
268
269    def test_Iterator(self):
270        non_samples = [None, 42, 3.14, 1j, "".encode('ascii'), "", (), [],
271            {}, set()]
272        for x in non_samples:
273            self.failIf(isinstance(x, Iterator), repr(x))
274            self.failIf(issubclass(type(x), Iterator), repr(type(x)))
275        samples = [iter(str()),
276                   iter(tuple()), iter(list()), iter(dict()),
277                   iter(set()), iter(frozenset()),
278                   iter(dict().keys()), iter(dict().items()),
279                   iter(dict().values()),
280                   (lambda: (yield))(),
281                   (x for x in []),
282                   ]
283        for x in samples:
284            self.failUnless(isinstance(x, Iterator), repr(x))
285            self.failUnless(issubclass(type(x), Iterator), repr(type(x)))
286        self.validate_abstract_methods(Iterator, 'next')
287
288    def test_Sized(self):
289        non_samples = [None, 42, 3.14, 1j,
290                       (lambda: (yield))(),
291                       (x for x in []),
292                       ]
293        for x in non_samples:
294            self.failIf(isinstance(x, Sized), repr(x))
295            self.failIf(issubclass(type(x), Sized), repr(type(x)))
296        samples = [str(),
297                   tuple(), list(), set(), frozenset(), dict(),
298                   dict().keys(), dict().items(), dict().values(),
299                   ]
300        for x in samples:
301            self.failUnless(isinstance(x, Sized), repr(x))
302            self.failUnless(issubclass(type(x), Sized), repr(type(x)))
303        self.validate_abstract_methods(Sized, '__len__')
304
305    def test_Container(self):
306        non_samples = [None, 42, 3.14, 1j,
307                       (lambda: (yield))(),
308                       (x for x in []),
309                       ]
310        for x in non_samples:
311            self.failIf(isinstance(x, Container), repr(x))
312            self.failIf(issubclass(type(x), Container), repr(type(x)))
313        samples = [str(),
314                   tuple(), list(), set(), frozenset(), dict(),
315                   dict().keys(), dict().items(),
316                   ]
317        for x in samples:
318            self.failUnless(isinstance(x, Container), repr(x))
319            self.failUnless(issubclass(type(x), Container), repr(type(x)))
320        self.validate_abstract_methods(Container, '__contains__')
321
322    def test_Callable(self):
323        non_samples = [None, 42, 3.14, 1j,
324                       "", "".encode('ascii'), (), [], {}, set(),
325                       (lambda: (yield))(),
326                       (x for x in []),
327                       ]
328        for x in non_samples:
329            self.failIf(isinstance(x, Callable), repr(x))
330            self.failIf(issubclass(type(x), Callable), repr(type(x)))
331        samples = [lambda: None,
332                   type, int, object,
333                   len,
334                   list.append, [].append,
335                   ]
336        for x in samples:
337            self.failUnless(isinstance(x, Callable), repr(x))
338            self.failUnless(issubclass(type(x), Callable), repr(type(x)))
339        self.validate_abstract_methods(Callable, '__call__')
340
341    def test_direct_subclassing(self):
342        for B in Hashable, Iterable, Iterator, Sized, Container, Callable:
343            class C(B):
344                pass
345            self.failUnless(issubclass(C, B))
346            self.failIf(issubclass(int, C))
347
348    def test_registration(self):
349        for B in Hashable, Iterable, Iterator, Sized, Container, Callable:
350            class C:
351                __metaclass__ = type
352                __hash__ = None  # Make sure it isn't hashable by default
353            self.failIf(issubclass(C, B), B.__name__)
354            B.register(C)
355            self.failUnless(issubclass(C, B))
356
357class WithSet(MutableSet):
358
359    def __init__(self, it=()):
360        self.data = set(it)
361
362    def __len__(self):
363        return len(self.data)
364
365    def __iter__(self):
366        return iter(self.data)
367
368    def __contains__(self, item):
369        return item in self.data
370
371    def add(self, item):
372        self.data.add(item)
373
374    def discard(self, item):
375        self.data.discard(item)
376
377class TestCollectionABCs(ABCTestCase):
378
379    # XXX For now, we only test some virtual inheritance properties.
380    # We should also test the proper behavior of the collection ABCs
381    # as real base classes or mix-in classes.
382
383    def test_Set(self):
384        for sample in [set, frozenset]:
385            self.failUnless(isinstance(sample(), Set))
386            self.failUnless(issubclass(sample, Set))
387        self.validate_abstract_methods(Set, '__contains__', '__iter__', '__len__')
388
389    def test_hash_Set(self):
390        class OneTwoThreeSet(Set):
391            def __init__(self):
392                self.contents = [1, 2, 3]
393            def __contains__(self, x):
394                return x in self.contents
395            def __len__(self):
396                return len(self.contents)
397            def __iter__(self):
398                return iter(self.contents)
399            def __hash__(self):
400                return self._hash()
401        a, b = OneTwoThreeSet(), OneTwoThreeSet()
402        self.failUnless(hash(a) == hash(b))
403
404    def test_MutableSet(self):
405        self.failUnless(isinstance(set(), MutableSet))
406        self.failUnless(issubclass(set, MutableSet))
407        self.failIf(isinstance(frozenset(), MutableSet))
408        self.failIf(issubclass(frozenset, MutableSet))
409        self.validate_abstract_methods(MutableSet, '__contains__', '__iter__', '__len__',
410            'add', 'discard')
411
412    def test_issue_5647(self):
413        # MutableSet.__iand__ mutated the set during iteration
414        s = WithSet('abcd')
415        s &= WithSet('cdef')            # This used to fail
416        self.assertEqual(set(s), set('cd'))
417
418    def test_issue_4920(self):
419        # MutableSet.pop() method did not work
420        class MySet(collections.MutableSet):
421            __slots__=['__s']
422            def __init__(self,items=None):
423                if items is None:
424                    items=[]
425                self.__s=set(items)
426            def __contains__(self,v):
427                return v in self.__s
428            def __iter__(self):
429                return iter(self.__s)
430            def __len__(self):
431                return len(self.__s)
432            def add(self,v):
433                result=v not in self.__s
434                self.__s.add(v)
435                return result
436            def discard(self,v):
437                result=v in self.__s
438                self.__s.discard(v)
439                return result
440            def __repr__(self):
441                return "MySet(%s)" % repr(list(self))
442        s = MySet([5,43,2,1])
443        self.assertEqual(s.pop(), 1)
444
445    def test_Mapping(self):
446        for sample in [dict]:
447            self.failUnless(isinstance(sample(), Mapping))
448            self.failUnless(issubclass(sample, Mapping))
449        self.validate_abstract_methods(Mapping, '__contains__', '__iter__', '__len__',
450            '__getitem__')
451
452    def test_MutableMapping(self):
453        for sample in [dict]:
454            self.failUnless(isinstance(sample(), MutableMapping))
455            self.failUnless(issubclass(sample, MutableMapping))
456        self.validate_abstract_methods(MutableMapping, '__contains__', '__iter__', '__len__',
457            '__getitem__', '__setitem__', '__delitem__')
458
459    def test_Sequence(self):
460        for sample in [tuple, list, str]:
461            self.failUnless(isinstance(sample(), Sequence))
462            self.failUnless(issubclass(sample, Sequence))
463        self.failUnless(issubclass(basestring, Sequence))
464        self.failUnless(isinstance(range(10), Sequence))
465        self.failUnless(issubclass(xrange, Sequence))
466        self.failUnless(issubclass(str, Sequence))
467        self.validate_abstract_methods(Sequence, '__contains__', '__iter__', '__len__',
468            '__getitem__')
469
470    def test_MutableSequence(self):
471        for sample in [tuple, str]:
472            self.failIf(isinstance(sample(), MutableSequence))
473            self.failIf(issubclass(sample, MutableSequence))
474        for sample in [list]:
475            self.failUnless(isinstance(sample(), MutableSequence))
476            self.failUnless(issubclass(sample, MutableSequence))
477        self.failIf(issubclass(basestring, MutableSequence))
478        self.validate_abstract_methods(MutableSequence, '__contains__', '__iter__',
479            '__len__', '__getitem__', '__setitem__', '__delitem__', 'insert')
480
481import doctest, collections
482
483def test_main(verbose=None):
484    if sys.flags.optimize >= 2:
485        print >>sys.stderr, "test_collections -- skipping some tests due to -O flag."
486        sys.stderr.flush()
487    NamedTupleDocs = doctest.DocTestSuite(module=collections)
488    test_classes = [TestNamedTuple, NamedTupleDocs, TestOneTrickPonyABCs, TestCollectionABCs]
489    test_support.run_unittest(*test_classes)
490    test_support.run_doctest(collections, verbose)
491
492if __name__ == "__main__":
493    test_main(verbose=True)