1# Test iterators.
2
3import unittest
4from test.test_support import run_unittest, TESTFN, unlink, have_unicode, \
5                              check_py3k_warnings, cpython_only
6
7# Test result of triple loop (too big to inline)
8TRIPLETS = [(0, 0, 0), (0, 0, 1), (0, 0, 2),
9            (0, 1, 0), (0, 1, 1), (0, 1, 2),
10            (0, 2, 0), (0, 2, 1), (0, 2, 2),
11
12            (1, 0, 0), (1, 0, 1), (1, 0, 2),
13            (1, 1, 0), (1, 1, 1), (1, 1, 2),
14            (1, 2, 0), (1, 2, 1), (1, 2, 2),
15
16            (2, 0, 0), (2, 0, 1), (2, 0, 2),
17            (2, 1, 0), (2, 1, 1), (2, 1, 2),
18            (2, 2, 0), (2, 2, 1), (2, 2, 2)]
19
20# Helper classes
21
22class BasicIterClass:
23    def __init__(self, n):
24        self.n = n
25        self.i = 0
26    def next(self):
27        res = self.i
28        if res >= self.n:
29            raise StopIteration
30        self.i = res + 1
31        return res
32
33class IteratingSequenceClass:
34    def __init__(self, n):
35        self.n = n
36    def __iter__(self):
37        return BasicIterClass(self.n)
38
39class SequenceClass:
40    def __init__(self, n):
41        self.n = n
42    def __getitem__(self, i):
43        if 0 <= i < self.n:
44            return i
45        else:
46            raise IndexError
47
48# Main test suite
49
50class TestCase(unittest.TestCase):
51
52    # Helper to check that an iterator returns a given sequence
53    def check_iterator(self, it, seq):
54        res = []
55        while 1:
56            try:
57                val = it.next()
58            except StopIteration:
59                break
60            res.append(val)
61        self.assertEqual(res, seq)
62
63    # Helper to check that a for loop generates a given sequence
64    def check_for_loop(self, expr, seq):
65        res = []
66        for val in expr:
67            res.append(val)
68        self.assertEqual(res, seq)
69
70    # Test basic use of iter() function
71    def test_iter_basic(self):
72        self.check_iterator(iter(range(10)), range(10))
73
74    # Test that iter(iter(x)) is the same as iter(x)
75    def test_iter_idempotency(self):
76        seq = range(10)
77        it = iter(seq)
78        it2 = iter(it)
79        self.assertTrue(it is it2)
80
81    # Test that for loops over iterators work
82    def test_iter_for_loop(self):
83        self.check_for_loop(iter(range(10)), range(10))
84
85    # Test several independent iterators over the same list
86    def test_iter_independence(self):
87        seq = range(3)
88        res = []
89        for i in iter(seq):
90            for j in iter(seq):
91                for k in iter(seq):
92                    res.append((i, j, k))
93        self.assertEqual(res, TRIPLETS)
94
95    # Test triple list comprehension using iterators
96    def test_nested_comprehensions_iter(self):
97        seq = range(3)
98        res = [(i, j, k)
99               for i in iter(seq) for j in iter(seq) for k in iter(seq)]
100        self.assertEqual(res, TRIPLETS)
101
102    # Test triple list comprehension without iterators
103    def test_nested_comprehensions_for(self):
104        seq = range(3)
105        res = [(i, j, k) for i in seq for j in seq for k in seq]
106        self.assertEqual(res, TRIPLETS)
107
108    # Test a class with __iter__ in a for loop
109    def test_iter_class_for(self):
110        self.check_for_loop(IteratingSequenceClass(10), range(10))
111
112    # Test a class with __iter__ with explicit iter()
113    def test_iter_class_iter(self):
114        self.check_iterator(iter(IteratingSequenceClass(10)), range(10))
115
116    # Test for loop on a sequence class without __iter__
117    def test_seq_class_for(self):
118        self.check_for_loop(SequenceClass(10), range(10))
119
120    # Test iter() on a sequence class without __iter__
121    def test_seq_class_iter(self):
122        self.check_iterator(iter(SequenceClass(10)), range(10))
123
124    # Test a new_style class with __iter__ but no next() method
125    def test_new_style_iter_class(self):
126        class IterClass(object):
127            def __iter__(self):
128                return self
129        self.assertRaises(TypeError, iter, IterClass())
130
131    # Test two-argument iter() with callable instance
132    def test_iter_callable(self):
133        class C:
134            def __init__(self):
135                self.i = 0
136            def __call__(self):
137                i = self.i
138                self.i = i + 1
139                if i > 100:
140                    raise IndexError # Emergency stop
141                return i
142        self.check_iterator(iter(C(), 10), range(10))
143
144    # Test two-argument iter() with function
145    def test_iter_function(self):
146        def spam(state=[0]):
147            i = state[0]
148            state[0] = i+1
149            return i
150        self.check_iterator(iter(spam, 10), range(10))
151
152    # Test two-argument iter() with function that raises StopIteration
153    def test_iter_function_stop(self):
154        def spam(state=[0]):
155            i = state[0]
156            if i == 10:
157                raise StopIteration
158            state[0] = i+1
159            return i
160        self.check_iterator(iter(spam, 20), range(10))
161
162    # Test exception propagation through function iterator
163    def test_exception_function(self):
164        def spam(state=[0]):
165            i = state[0]
166            state[0] = i+1
167            if i == 10:
168                raise RuntimeError
169            return i
170        res = []
171        try:
172            for x in iter(spam, 20):
173                res.append(x)
174        except RuntimeError:
175            self.assertEqual(res, range(10))
176        else:
177            self.fail("should have raised RuntimeError")
178
179    # Test exception propagation through sequence iterator
180    def test_exception_sequence(self):
181        class MySequenceClass(SequenceClass):
182            def __getitem__(self, i):
183                if i == 10:
184                    raise RuntimeError
185                return SequenceClass.__getitem__(self, i)
186        res = []
187        try:
188            for x in MySequenceClass(20):
189                res.append(x)
190        except RuntimeError:
191            self.assertEqual(res, range(10))
192        else:
193            self.fail("should have raised RuntimeError")
194
195    # Test for StopIteration from __getitem__
196    def test_stop_sequence(self):
197        class MySequenceClass(SequenceClass):
198            def __getitem__(self, i):
199                if i == 10:
200                    raise StopIteration
201                return SequenceClass.__getitem__(self, i)
202        self.check_for_loop(MySequenceClass(20), range(10))
203
204    # Test a big range
205    def test_iter_big_range(self):
206        self.check_for_loop(iter(range(10000)), range(10000))
207
208    # Test an empty list
209    def test_iter_empty(self):
210        self.check_for_loop(iter([]), [])
211
212    # Test a tuple
213    def test_iter_tuple(self):
214        self.check_for_loop(iter((0,1,2,3,4,5,6,7,8,9)), range(10))
215
216    # Test an xrange
217    def test_iter_xrange(self):
218        self.check_for_loop(iter(xrange(10)), range(10))
219
220    # Test a string
221    def test_iter_string(self):
222        self.check_for_loop(iter("abcde"), ["a", "b", "c", "d", "e"])
223
224    # Test a Unicode string
225    if have_unicode:
226        def test_iter_unicode(self):
227            self.check_for_loop(iter(unicode("abcde")),
228                                [unicode("a"), unicode("b"), unicode("c"),
229                                 unicode("d"), unicode("e")])
230
231    # Test a directory
232    def test_iter_dict(self):
233        dict = {}
234        for i in range(10):
235            dict[i] = None
236        self.check_for_loop(dict, dict.keys())
237
238    # Test a file
239    def test_iter_file(self):
240        f = open(TESTFN, "w")
241        try:
242            for i in range(5):
243                f.write("%d\n" % i)
244        finally:
245            f.close()
246        f = open(TESTFN, "r")
247        try:
248            self.check_for_loop(f, ["0\n", "1\n", "2\n", "3\n", "4\n"])
249            self.check_for_loop(f, [])
250        finally:
251            f.close()
252            try:
253                unlink(TESTFN)
254            except OSError:
255                pass
256
257    # Test list()'s use of iterators.
258    def test_builtin_list(self):
259        self.assertEqual(list(SequenceClass(5)), range(5))
260        self.assertEqual(list(SequenceClass(0)), [])
261        self.assertEqual(list(()), [])
262        self.assertEqual(list(range(10, -1, -1)), range(10, -1, -1))
263
264        d = {"one": 1, "two": 2, "three": 3}
265        self.assertEqual(list(d), d.keys())
266
267        self.assertRaises(TypeError, list, list)
268        self.assertRaises(TypeError, list, 42)
269
270        f = open(TESTFN, "w")
271        try:
272            for i in range(5):
273                f.write("%d\n" % i)
274        finally:
275            f.close()
276        f = open(TESTFN, "r")
277        try:
278            self.assertEqual(list(f), ["0\n", "1\n", "2\n", "3\n", "4\n"])
279            f.seek(0, 0)
280            self.assertEqual(list(f),
281                             ["0\n", "1\n", "2\n", "3\n", "4\n"])
282        finally:
283            f.close()
284            try:
285                unlink(TESTFN)
286            except OSError:
287                pass
288
289    # Test tuples()'s use of iterators.
290    def test_builtin_tuple(self):
291        self.assertEqual(tuple(SequenceClass(5)), (0, 1, 2, 3, 4))
292        self.assertEqual(tuple(SequenceClass(0)), ())
293        self.assertEqual(tuple([]), ())
294        self.assertEqual(tuple(()), ())
295        self.assertEqual(tuple("abc"), ("a", "b", "c"))
296
297        d = {"one": 1, "two": 2, "three": 3}
298        self.assertEqual(tuple(d), tuple(d.keys()))
299
300        self.assertRaises(TypeError, tuple, list)
301        self.assertRaises(TypeError, tuple, 42)
302
303        f = open(TESTFN, "w")
304        try:
305            for i in range(5):
306                f.write("%d\n" % i)
307        finally:
308            f.close()
309        f = open(TESTFN, "r")
310        try:
311            self.assertEqual(tuple(f), ("0\n", "1\n", "2\n", "3\n", "4\n"))
312            f.seek(0, 0)
313            self.assertEqual(tuple(f),
314                             ("0\n", "1\n", "2\n", "3\n", "4\n"))
315        finally:
316            f.close()
317            try:
318                unlink(TESTFN)
319            except OSError:
320                pass
321
322    # Test filter()'s use of iterators.
323    def test_builtin_filter(self):
324        self.assertEqual(filter(None, SequenceClass(5)), range(1, 5))
325        self.assertEqual(filter(None, SequenceClass(0)), [])
326        self.assertEqual(filter(None, ()), ())
327        self.assertEqual(filter(None, "abc"), "abc")
328
329        d = {"one": 1, "two": 2, "three": 3}
330        self.assertEqual(filter(None, d), d.keys())
331
332        self.assertRaises(TypeError, filter, None, list)
333        self.assertRaises(TypeError, filter, None, 42)
334
335        class Boolean:
336            def __init__(self, truth):
337                self.truth = truth
338            def __nonzero__(self):
339                return self.truth
340        bTrue = Boolean(1)
341        bFalse = Boolean(0)
342
343        class Seq:
344            def __init__(self, *args):
345                self.vals = args
346            def __iter__(self):
347                class SeqIter:
348                    def __init__(self, vals):
349                        self.vals = vals
350                        self.i = 0
351                    def __iter__(self):
352                        return self
353                    def next(self):
354                        i = self.i
355                        self.i = i + 1
356                        if i < len(self.vals):
357                            return self.vals[i]
358                        else:
359                            raise StopIteration
360                return SeqIter(self.vals)
361
362        seq = Seq(*([bTrue, bFalse] * 25))
363        self.assertEqual(filter(lambda x: not x, seq), [bFalse]*25)
364        self.assertEqual(filter(lambda x: not x, iter(seq)), [bFalse]*25)
365
366    # Test max() and min()'s use of iterators.
367    def test_builtin_max_min(self):
368        self.assertEqual(max(SequenceClass(5)), 4)
369        self.assertEqual(min(SequenceClass(5)), 0)
370        self.assertEqual(max(8, -1), 8)
371        self.assertEqual(min(8, -1), -1)
372
373        d = {"one": 1, "two": 2, "three": 3}
374        self.assertEqual(max(d), "two")
375        self.assertEqual(min(d), "one")
376        self.assertEqual(max(d.itervalues()), 3)
377        self.assertEqual(min(iter(d.itervalues())), 1)
378
379        f = open(TESTFN, "w")
380        try:
381            f.write("medium line\n")
382            f.write("xtra large line\n")
383            f.write("itty-bitty line\n")
384        finally:
385            f.close()
386        f = open(TESTFN, "r")
387        try:
388            self.assertEqual(min(f), "itty-bitty line\n")
389            f.seek(0, 0)
390            self.assertEqual(max(f), "xtra large line\n")
391        finally:
392            f.close()
393            try:
394                unlink(TESTFN)
395            except OSError:
396                pass
397
398    # Test map()'s use of iterators.
399    def test_builtin_map(self):
400        self.assertEqual(map(lambda x: x+1, SequenceClass(5)), range(1, 6))
401
402        d = {"one": 1, "two": 2, "three": 3}
403        self.assertEqual(map(lambda k, d=d: (k, d[k]), d), d.items())
404        dkeys = d.keys()
405        expected = [(i < len(d) and dkeys[i] or None,
406                     i,
407                     i < len(d) and dkeys[i] or None)
408                    for i in range(5)]
409
410        # Deprecated map(None, ...)
411        with check_py3k_warnings():
412            self.assertEqual(map(None, SequenceClass(5)), range(5))
413            self.assertEqual(map(None, d), d.keys())
414            self.assertEqual(map(None, d,
415                                       SequenceClass(5),
416                                       iter(d.iterkeys())),
417                             expected)
418
419        f = open(TESTFN, "w")
420        try:
421            for i in range(10):
422                f.write("xy" * i + "\n") # line i has len 2*i+1
423        finally:
424            f.close()
425        f = open(TESTFN, "r")
426        try:
427            self.assertEqual(map(len, f), range(1, 21, 2))
428        finally:
429            f.close()
430            try:
431                unlink(TESTFN)
432            except OSError:
433                pass
434
435    # Test zip()'s use of iterators.
436    def test_builtin_zip(self):
437        self.assertEqual(zip(), [])
438        self.assertEqual(zip(*[]), [])
439        self.assertEqual(zip(*[(1, 2), 'ab']), [(1, 'a'), (2, 'b')])
440
441        self.assertRaises(TypeError, zip, None)
442        self.assertRaises(TypeError, zip, range(10), 42)
443        self.assertRaises(TypeError, zip, range(10), zip)
444
445        self.assertEqual(zip(IteratingSequenceClass(3)),
446                         [(0,), (1,), (2,)])
447        self.assertEqual(zip(SequenceClass(3)),
448                         [(0,), (1,), (2,)])
449
450        d = {"one": 1, "two": 2, "three": 3}
451        self.assertEqual(d.items(), zip(d, d.itervalues()))
452
453        # Generate all ints starting at constructor arg.
454        class IntsFrom:
455            def __init__(self, start):
456                self.i = start
457
458            def __iter__(self):
459                return self
460
461            def next(self):
462                i = self.i
463                self.i = i+1
464                return i
465
466        f = open(TESTFN, "w")
467        try:
468            f.write("a\n" "bbb\n" "cc\n")
469        finally:
470            f.close()
471        f = open(TESTFN, "r")
472        try:
473            self.assertEqual(zip(IntsFrom(0), f, IntsFrom(-100)),
474                             [(0, "a\n", -100),
475                              (1, "bbb\n", -99),
476                              (2, "cc\n", -98)])
477        finally:
478            f.close()
479            try:
480                unlink(TESTFN)
481            except OSError:
482                pass
483
484        self.assertEqual(zip(xrange(5)), [(i,) for i in range(5)])
485
486        # Classes that lie about their lengths.
487        class NoGuessLen5:
488            def __getitem__(self, i):
489                if i >= 5:
490                    raise IndexError
491                return i
492
493        class Guess3Len5(NoGuessLen5):
494            def __len__(self):
495                return 3
496
497        class Guess30Len5(NoGuessLen5):
498            def __len__(self):
499                return 30
500
501        self.assertEqual(len(Guess3Len5()), 3)
502        self.assertEqual(len(Guess30Len5()), 30)
503        self.assertEqual(zip(NoGuessLen5()), zip(range(5)))
504        self.assertEqual(zip(Guess3Len5()), zip(range(5)))
505        self.assertEqual(zip(Guess30Len5()), zip(range(5)))
506
507        expected = [(i, i) for i in range(5)]
508        for x in NoGuessLen5(), Guess3Len5(), Guess30Len5():
509            for y in NoGuessLen5(), Guess3Len5(), Guess30Len5():
510                self.assertEqual(zip(x, y), expected)
511
512    # Test reduces()'s use of iterators.
513    def test_deprecated_builtin_reduce(self):
514        with check_py3k_warnings():
515            self._test_builtin_reduce()
516
517    def _test_builtin_reduce(self):
518        from operator import add
519        self.assertEqual(reduce(add, SequenceClass(5)), 10)
520        self.assertEqual(reduce(add, SequenceClass(5), 42), 52)
521        self.assertRaises(TypeError, reduce, add, SequenceClass(0))
522        self.assertEqual(reduce(add, SequenceClass(0), 42), 42)
523        self.assertEqual(reduce(add, SequenceClass(1)), 0)
524        self.assertEqual(reduce(add, SequenceClass(1), 42), 42)
525
526        d = {"one": 1, "two": 2, "three": 3}
527        self.assertEqual(reduce(add, d), "".join(d.keys()))
528
529    # This test case will be removed if we don't have Unicode
530    def test_unicode_join_endcase(self):
531
532        # This class inserts a Unicode object into its argument's natural
533        # iteration, in the 3rd position.
534        class OhPhooey:
535            def __init__(self, seq):
536                self.it = iter(seq)
537                self.i = 0
538
539            def __iter__(self):
540                return self
541
542            def next(self):
543                i = self.i
544                self.i = i+1
545                if i == 2:
546                    return unicode("fooled you!")
547                return self.it.next()
548
549        f = open(TESTFN, "w")
550        try:
551            f.write("a\n" + "b\n" + "c\n")
552        finally:
553            f.close()
554
555        f = open(TESTFN, "r")
556        # Nasty:  string.join(s) can't know whether unicode.join() is needed
557        # until it's seen all of s's elements.  But in this case, f's
558        # iterator cannot be restarted.  So what we're testing here is
559        # whether string.join() can manage to remember everything it's seen
560        # and pass that on to unicode.join().
561        try:
562            got = " - ".join(OhPhooey(f))
563            self.assertEqual(got, unicode("a\n - b\n - fooled you! - c\n"))
564        finally:
565            f.close()
566            try:
567                unlink(TESTFN)
568            except OSError:
569                pass
570    if not have_unicode:
571        def test_unicode_join_endcase(self): pass
572
573    # Test iterators with 'x in y' and 'x not in y'.
574    def test_in_and_not_in(self):
575        for sc5 in IteratingSequenceClass(5), SequenceClass(5):
576            for i in range(5):
577                self.assertIn(i, sc5)
578            for i in "abc", -1, 5, 42.42, (3, 4), [], {1: 1}, 3-12j, sc5:
579                self.assertNotIn(i, sc5)
580
581        self.assertRaises(TypeError, lambda: 3 in 12)
582        self.assertRaises(TypeError, lambda: 3 not in map)
583
584        d = {"one": 1, "two": 2, "three": 3, 1j: 2j}
585        for k in d:
586            self.assertIn(k, d)
587            self.assertNotIn(k, d.itervalues())
588        for v in d.values():
589            self.assertIn(v, d.itervalues())
590            self.assertNotIn(v, d)
591        for k, v in d.iteritems():
592            self.assertIn((k, v), d.iteritems())
593            self.assertNotIn((v, k), d.iteritems())
594
595        f = open(TESTFN, "w")
596        try:
597            f.write("a\n" "b\n" "c\n")
598        finally:
599            f.close()
600        f = open(TESTFN, "r")
601        try:
602            for chunk in "abc":
603                f.seek(0, 0)
604                self.assertNotIn(chunk, f)
605                f.seek(0, 0)
606                self.assertIn((chunk + "\n"), f)
607        finally:
608            f.close()
609            try:
610                unlink(TESTFN)
611            except OSError:
612                pass
613
614    # Test iterators with operator.countOf (PySequence_Count).
615    def test_countOf(self):
616        from operator import countOf
617        self.assertEqual(countOf([1,2,2,3,2,5], 2), 3)
618        self.assertEqual(countOf((1,2,2,3,2,5), 2), 3)
619        self.assertEqual(countOf("122325", "2"), 3)
620        self.assertEqual(countOf("122325", "6"), 0)
621
622        self.assertRaises(TypeError, countOf, 42, 1)
623        self.assertRaises(TypeError, countOf, countOf, countOf)
624
625        d = {"one": 3, "two": 3, "three": 3, 1j: 2j}
626        for k in d:
627            self.assertEqual(countOf(d, k), 1)
628        self.assertEqual(countOf(d.itervalues(), 3), 3)
629        self.assertEqual(countOf(d.itervalues(), 2j), 1)
630        self.assertEqual(countOf(d.itervalues(), 1j), 0)
631
632        f = open(TESTFN, "w")
633        try:
634            f.write("a\n" "b\n" "c\n" "b\n")
635        finally:
636            f.close()
637        f = open(TESTFN, "r")
638        try:
639            for letter, count in ("a", 1), ("b", 2), ("c", 1), ("d", 0):
640                f.seek(0, 0)
641                self.assertEqual(countOf(f, letter + "\n"), count)
642        finally:
643            f.close()
644            try:
645                unlink(TESTFN)
646            except OSError:
647                pass
648
649    # Test iterators with operator.indexOf (PySequence_Index).
650    def test_indexOf(self):
651        from operator import indexOf
652        self.assertEqual(indexOf([1,2,2,3,2,5], 1), 0)
653        self.assertEqual(indexOf((1,2,2,3,2,5), 2), 1)
654        self.assertEqual(indexOf((1,2,2,3,2,5), 3), 3)
655        self.assertEqual(indexOf((1,2,2,3,2,5), 5), 5)
656        self.assertRaises(ValueError, indexOf, (1,2,2,3,2,5), 0)
657        self.assertRaises(ValueError, indexOf, (1,2,2,3,2,5), 6)
658
659        self.assertEqual(indexOf("122325", "2"), 1)
660        self.assertEqual(indexOf("122325", "5"), 5)
661        self.assertRaises(ValueError, indexOf, "122325", "6")
662
663        self.assertRaises(TypeError, indexOf, 42, 1)
664        self.assertRaises(TypeError, indexOf, indexOf, indexOf)
665
666        f = open(TESTFN, "w")
667        try:
668            f.write("a\n" "b\n" "c\n" "d\n" "e\n")
669        finally:
670            f.close()
671        f = open(TESTFN, "r")
672        try:
673            fiter = iter(f)
674            self.assertEqual(indexOf(fiter, "b\n"), 1)
675            self.assertEqual(indexOf(fiter, "d\n"), 1)
676            self.assertEqual(indexOf(fiter, "e\n"), 0)
677            self.assertRaises(ValueError, indexOf, fiter, "a\n")
678        finally:
679            f.close()
680            try:
681                unlink(TESTFN)
682            except OSError:
683                pass
684
685        iclass = IteratingSequenceClass(3)
686        for i in range(3):
687            self.assertEqual(indexOf(iclass, i), i)
688        self.assertRaises(ValueError, indexOf, iclass, -1)
689
690    # Test iterators with file.writelines().
691    def test_writelines(self):
692        f = file(TESTFN, "w")
693
694        try:
695            self.assertRaises(TypeError, f.writelines, None)
696            self.assertRaises(TypeError, f.writelines, 42)
697
698            f.writelines(["1\n", "2\n"])
699            f.writelines(("3\n", "4\n"))
700            f.writelines({'5\n': None})
701            f.writelines({})
702
703            # Try a big chunk too.
704            class Iterator:
705                def __init__(self, start, finish):
706                    self.start = start
707                    self.finish = finish
708                    self.i = self.start
709
710                def next(self):
711                    if self.i >= self.finish:
712                        raise StopIteration
713                    result = str(self.i) + '\n'
714                    self.i += 1
715                    return result
716
717                def __iter__(self):
718                    return self
719
720            class Whatever:
721                def __init__(self, start, finish):
722                    self.start = start
723                    self.finish = finish
724
725                def __iter__(self):
726                    return Iterator(self.start, self.finish)
727
728            f.writelines(Whatever(6, 6+2000))
729            f.close()
730
731            f = file(TESTFN)
732            expected = [str(i) + "\n" for i in range(1, 2006)]
733            self.assertEqual(list(f), expected)
734
735        finally:
736            f.close()
737            try:
738                unlink(TESTFN)
739            except OSError:
740                pass
741
742
743    # Test iterators on RHS of unpacking assignments.
744    def test_unpack_iter(self):
745        a, b = 1, 2
746        self.assertEqual((a, b), (1, 2))
747
748        a, b, c = IteratingSequenceClass(3)
749        self.assertEqual((a, b, c), (0, 1, 2))
750
751        try:    # too many values
752            a, b = IteratingSequenceClass(3)
753        except ValueError:
754            pass
755        else:
756            self.fail("should have raised ValueError")
757
758        try:    # not enough values
759            a, b, c = IteratingSequenceClass(2)
760        except ValueError:
761            pass
762        else:
763            self.fail("should have raised ValueError")
764
765        try:    # not iterable
766            a, b, c = len
767        except TypeError:
768            pass
769        else:
770            self.fail("should have raised TypeError")
771
772        a, b, c = {1: 42, 2: 42, 3: 42}.itervalues()
773        self.assertEqual((a, b, c), (42, 42, 42))
774
775        f = open(TESTFN, "w")
776        lines = ("a\n", "bb\n", "ccc\n")
777        try:
778            for line in lines:
779                f.write(line)
780        finally:
781            f.close()
782        f = open(TESTFN, "r")
783        try:
784            a, b, c = f
785            self.assertEqual((a, b, c), lines)
786        finally:
787            f.close()
788            try:
789                unlink(TESTFN)
790            except OSError:
791                pass
792
793        (a, b), (c,) = IteratingSequenceClass(2), {42: 24}
794        self.assertEqual((a, b, c), (0, 1, 42))
795
796
797    @cpython_only
798    def test_ref_counting_behavior(self):
799        class C(object):
800            count = 0
801            def __new__(cls):
802                cls.count += 1
803                return object.__new__(cls)
804            def __del__(self):
805                cls = self.__class__
806                assert cls.count > 0
807                cls.count -= 1
808        x = C()
809        self.assertEqual(C.count, 1)
810        del x
811        self.assertEqual(C.count, 0)
812        l = [C(), C(), C()]
813        self.assertEqual(C.count, 3)
814        try:
815            a, b = iter(l)
816        except ValueError:
817            pass
818        del l
819        self.assertEqual(C.count, 0)
820
821
822    # Make sure StopIteration is a "sink state".
823    # This tests various things that weren't sink states in Python 2.2.1,
824    # plus various things that always were fine.
825
826    def test_sinkstate_list(self):
827        # This used to fail
828        a = range(5)
829        b = iter(a)
830        self.assertEqual(list(b), range(5))
831        a.extend(range(5, 10))
832        self.assertEqual(list(b), [])
833
834    def test_sinkstate_tuple(self):
835        a = (0, 1, 2, 3, 4)
836        b = iter(a)
837        self.assertEqual(list(b), range(5))
838        self.assertEqual(list(b), [])
839
840    def test_sinkstate_string(self):
841        a = "abcde"
842        b = iter(a)
843        self.assertEqual(list(b), ['a', 'b', 'c', 'd', 'e'])
844        self.assertEqual(list(b), [])
845
846    def test_sinkstate_sequence(self):
847        # This used to fail
848        a = SequenceClass(5)
849        b = iter(a)
850        self.assertEqual(list(b), range(5))
851        a.n = 10
852        self.assertEqual(list(b), [])
853
854    def test_sinkstate_callable(self):
855        # This used to fail
856        def spam(state=[0]):
857            i = state[0]
858            state[0] = i+1
859            if i == 10:
860                raise AssertionError, "shouldn't have gotten this far"
861            return i
862        b = iter(spam, 5)
863        self.assertEqual(list(b), range(5))
864        self.assertEqual(list(b), [])
865
866    def test_sinkstate_dict(self):
867        # XXX For a more thorough test, see towards the end of:
868        # http://mail.python.org/pipermail/python-dev/2002-July/026512.html
869        a = {1:1, 2:2, 0:0, 4:4, 3:3}
870        for b in iter(a), a.iterkeys(), a.iteritems(), a.itervalues():
871            b = iter(a)
872            self.assertEqual(len(list(b)), 5)
873            self.assertEqual(list(b), [])
874
875    def test_sinkstate_yield(self):
876        def gen():
877            for i in range(5):
878                yield i
879        b = gen()
880        self.assertEqual(list(b), range(5))
881        self.assertEqual(list(b), [])
882
883    def test_sinkstate_range(self):
884        a = xrange(5)
885        b = iter(a)
886        self.assertEqual(list(b), range(5))
887        self.assertEqual(list(b), [])
888
889    def test_sinkstate_enumerate(self):
890        a = range(5)
891        e = enumerate(a)
892        b = iter(e)
893        self.assertEqual(list(b), zip(range(5), range(5)))
894        self.assertEqual(list(b), [])
895
896    def test_3720(self):
897        # Avoid a crash, when an iterator deletes its next() method.
898        class BadIterator(object):
899            def __iter__(self):
900                return self
901            def next(self):
902                del BadIterator.next
903                return 1
904
905        try:
906            for i in BadIterator() :
907                pass
908        except TypeError:
909            pass
910
911    def test_extending_list_with_iterator_does_not_segfault(self):
912        # The code to extend a list with an iterator has a fair
913        # amount of nontrivial logic in terms of guessing how
914        # much memory to allocate in advance, "stealing" refs,
915        # and then shrinking at the end.  This is a basic smoke
916        # test for that scenario.
917        def gen():
918            for i in range(500):
919                yield i
920        lst = [0] * 500
921        for i in range(240):
922            lst.pop(0)
923        lst.extend(gen())
924        self.assertEqual(len(lst), 760)
925
926
927def test_main():
928    run_unittest(TestCase)
929
930
931if __name__ == "__main__":
932    test_main()
933