1 import unittest
2 import operator
3 import sys
4 import pickle
5 import gc
6
7 from test import support
8
9 class ESC[4;38;5;81mG:
10 'Sequence using __getitem__'
11 def __init__(self, seqn):
12 self.seqn = seqn
13 def __getitem__(self, i):
14 return self.seqn[i]
15
16 class ESC[4;38;5;81mI:
17 'Sequence using iterator protocol'
18 def __init__(self, seqn):
19 self.seqn = seqn
20 self.i = 0
21 def __iter__(self):
22 return self
23 def __next__(self):
24 if self.i >= len(self.seqn): raise StopIteration
25 v = self.seqn[self.i]
26 self.i += 1
27 return v
28
29 class ESC[4;38;5;81mIg:
30 'Sequence using iterator protocol defined with a generator'
31 def __init__(self, seqn):
32 self.seqn = seqn
33 self.i = 0
34 def __iter__(self):
35 for val in self.seqn:
36 yield val
37
38 class ESC[4;38;5;81mX:
39 'Missing __getitem__ and __iter__'
40 def __init__(self, seqn):
41 self.seqn = seqn
42 self.i = 0
43 def __next__(self):
44 if self.i >= len(self.seqn): raise StopIteration
45 v = self.seqn[self.i]
46 self.i += 1
47 return v
48
49 class ESC[4;38;5;81mE:
50 'Test propagation of exceptions'
51 def __init__(self, seqn):
52 self.seqn = seqn
53 self.i = 0
54 def __iter__(self):
55 return self
56 def __next__(self):
57 3 // 0
58
59 class ESC[4;38;5;81mN:
60 'Iterator missing __next__()'
61 def __init__(self, seqn):
62 self.seqn = seqn
63 self.i = 0
64 def __iter__(self):
65 return self
66
67 class ESC[4;38;5;81mPickleTest:
68 # Helper to check picklability
69 def check_pickle(self, itorg, seq):
70 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
71 d = pickle.dumps(itorg, proto)
72 it = pickle.loads(d)
73 self.assertEqual(type(itorg), type(it))
74 self.assertEqual(list(it), seq)
75
76 it = pickle.loads(d)
77 try:
78 next(it)
79 except StopIteration:
80 self.assertFalse(seq[1:])
81 continue
82 d = pickle.dumps(it, proto)
83 it = pickle.loads(d)
84 self.assertEqual(list(it), seq[1:])
85
86 class ESC[4;38;5;81mEnumerateTestCase(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase, ESC[4;38;5;149mPickleTest):
87
88 enum = enumerate
89 seq, res = 'abc', [(0,'a'), (1,'b'), (2,'c')]
90
91 def test_basicfunction(self):
92 self.assertEqual(type(self.enum(self.seq)), self.enum)
93 e = self.enum(self.seq)
94 self.assertEqual(iter(e), e)
95 self.assertEqual(list(self.enum(self.seq)), self.res)
96 self.enum.__doc__
97
98 def test_pickle(self):
99 self.check_pickle(self.enum(self.seq), self.res)
100
101 def test_getitemseqn(self):
102 self.assertEqual(list(self.enum(G(self.seq))), self.res)
103 e = self.enum(G(''))
104 self.assertRaises(StopIteration, next, e)
105
106 def test_iteratorseqn(self):
107 self.assertEqual(list(self.enum(I(self.seq))), self.res)
108 e = self.enum(I(''))
109 self.assertRaises(StopIteration, next, e)
110
111 def test_iteratorgenerator(self):
112 self.assertEqual(list(self.enum(Ig(self.seq))), self.res)
113 e = self.enum(Ig(''))
114 self.assertRaises(StopIteration, next, e)
115
116 def test_noniterable(self):
117 self.assertRaises(TypeError, self.enum, X(self.seq))
118
119 def test_illformediterable(self):
120 self.assertRaises(TypeError, self.enum, N(self.seq))
121
122 def test_exception_propagation(self):
123 self.assertRaises(ZeroDivisionError, list, self.enum(E(self.seq)))
124
125 def test_argumentcheck(self):
126 self.assertRaises(TypeError, self.enum) # no arguments
127 self.assertRaises(TypeError, self.enum, 1) # wrong type (not iterable)
128 self.assertRaises(TypeError, self.enum, 'abc', 'a') # wrong type
129 self.assertRaises(TypeError, self.enum, 'abc', 2, 3) # too many arguments
130
131 def test_kwargs(self):
132 self.assertEqual(list(self.enum(iterable=Ig(self.seq))), self.res)
133 expected = list(self.enum(Ig(self.seq), 0))
134 self.assertEqual(list(self.enum(iterable=Ig(self.seq), start=0)),
135 expected)
136 self.assertEqual(list(self.enum(start=0, iterable=Ig(self.seq))),
137 expected)
138 self.assertRaises(TypeError, self.enum, iterable=[], x=3)
139 self.assertRaises(TypeError, self.enum, start=0, x=3)
140 self.assertRaises(TypeError, self.enum, x=0, y=3)
141 self.assertRaises(TypeError, self.enum, x=0)
142
143 @support.cpython_only
144 def test_tuple_reuse(self):
145 # Tests an implementation detail where tuple is reused
146 # whenever nothing else holds a reference to it
147 self.assertEqual(len(set(map(id, list(enumerate(self.seq))))), len(self.seq))
148 self.assertEqual(len(set(map(id, enumerate(self.seq)))), min(1,len(self.seq)))
149
150 @support.cpython_only
151 def test_enumerate_result_gc(self):
152 # bpo-42536: enumerate's tuple-reuse speed trick breaks the GC's
153 # assumptions about what can be untracked. Make sure we re-track result
154 # tuples whenever we reuse them.
155 it = self.enum([[]])
156 gc.collect()
157 # That GC collection probably untracked the recycled internal result
158 # tuple, which is initialized to (None, None). Make sure it's re-tracked
159 # when it's mutated and returned from __next__:
160 self.assertTrue(gc.is_tracked(next(it)))
161
162 class ESC[4;38;5;81mMyEnum(ESC[4;38;5;149menumerate):
163 pass
164
165 class ESC[4;38;5;81mSubclassTestCase(ESC[4;38;5;149mEnumerateTestCase):
166
167 enum = MyEnum
168
169 class ESC[4;38;5;81mTestEmpty(ESC[4;38;5;149mEnumerateTestCase):
170
171 seq, res = '', []
172
173 class ESC[4;38;5;81mTestBig(ESC[4;38;5;149mEnumerateTestCase):
174
175 seq = range(10,20000,2)
176 res = list(zip(range(20000), seq))
177
178 class ESC[4;38;5;81mTestReversed(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase, ESC[4;38;5;149mPickleTest):
179
180 def test_simple(self):
181 class ESC[4;38;5;81mA:
182 def __getitem__(self, i):
183 if i < 5:
184 return str(i)
185 raise StopIteration
186 def __len__(self):
187 return 5
188 for data in ('abc', range(5), tuple(enumerate('abc')), A(),
189 range(1,17,5), dict.fromkeys('abcde')):
190 self.assertEqual(list(data)[::-1], list(reversed(data)))
191 # don't allow keyword arguments
192 self.assertRaises(TypeError, reversed, [], a=1)
193
194 def test_range_optimization(self):
195 x = range(1)
196 self.assertEqual(type(reversed(x)), type(iter(x)))
197
198 def test_len(self):
199 for s in ('hello', tuple('hello'), list('hello'), range(5)):
200 self.assertEqual(operator.length_hint(reversed(s)), len(s))
201 r = reversed(s)
202 list(r)
203 self.assertEqual(operator.length_hint(r), 0)
204 class ESC[4;38;5;81mSeqWithWeirdLen:
205 called = False
206 def __len__(self):
207 if not self.called:
208 self.called = True
209 return 10
210 raise ZeroDivisionError
211 def __getitem__(self, index):
212 return index
213 r = reversed(SeqWithWeirdLen())
214 self.assertRaises(ZeroDivisionError, operator.length_hint, r)
215
216
217 def test_gc(self):
218 class ESC[4;38;5;81mSeq:
219 def __len__(self):
220 return 10
221 def __getitem__(self, index):
222 return index
223 s = Seq()
224 r = reversed(s)
225 s.r = r
226
227 def test_args(self):
228 self.assertRaises(TypeError, reversed)
229 self.assertRaises(TypeError, reversed, [], 'extra')
230
231 @unittest.skipUnless(hasattr(sys, 'getrefcount'), 'test needs sys.getrefcount()')
232 def test_bug1229429(self):
233 # this bug was never in reversed, it was in
234 # PyObject_CallMethod, and reversed_new calls that sometimes.
235 def f():
236 pass
237 r = f.__reversed__ = object()
238 rc = sys.getrefcount(r)
239 for i in range(10):
240 try:
241 reversed(f)
242 except TypeError:
243 pass
244 else:
245 self.fail("non-callable __reversed__ didn't raise!")
246 self.assertEqual(rc, sys.getrefcount(r))
247
248 def test_objmethods(self):
249 # Objects must have __len__() and __getitem__() implemented.
250 class ESC[4;38;5;81mNoLen(ESC[4;38;5;149mobject):
251 def __getitem__(self, i): return 1
252 nl = NoLen()
253 self.assertRaises(TypeError, reversed, nl)
254
255 class ESC[4;38;5;81mNoGetItem(ESC[4;38;5;149mobject):
256 def __len__(self): return 2
257 ngi = NoGetItem()
258 self.assertRaises(TypeError, reversed, ngi)
259
260 class ESC[4;38;5;81mBlocked(ESC[4;38;5;149mobject):
261 def __getitem__(self, i): return 1
262 def __len__(self): return 2
263 __reversed__ = None
264 b = Blocked()
265 self.assertRaises(TypeError, reversed, b)
266
267 def test_pickle(self):
268 for data in 'abc', range(5), tuple(enumerate('abc')), range(1,17,5):
269 self.check_pickle(reversed(data), list(data)[::-1])
270
271
272 class ESC[4;38;5;81mEnumerateStartTestCase(ESC[4;38;5;149mEnumerateTestCase):
273
274 def test_basicfunction(self):
275 e = self.enum(self.seq)
276 self.assertEqual(iter(e), e)
277 self.assertEqual(list(self.enum(self.seq)), self.res)
278
279
280 class ESC[4;38;5;81mTestStart(ESC[4;38;5;149mEnumerateStartTestCase):
281 def enum(self, iterable, start=11):
282 return enumerate(iterable, start=start)
283
284 seq, res = 'abc', [(11, 'a'), (12, 'b'), (13, 'c')]
285
286
287 class ESC[4;38;5;81mTestLongStart(ESC[4;38;5;149mEnumerateStartTestCase):
288 def enum(self, iterable, start=sys.maxsize + 1):
289 return enumerate(iterable, start=start)
290
291 seq, res = 'abc', [(sys.maxsize+1,'a'), (sys.maxsize+2,'b'),
292 (sys.maxsize+3,'c')]
293
294
295 if __name__ == "__main__":
296 unittest.main()