blob: 2b6da6476c97f7106a095a2897fb6e75b0b22e77 [file] [log] [blame]
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001import functools
R. David Murray378c0cf2010-02-24 01:46:21 +00002import sys
Raymond Hettinger9c323f82005-02-28 19:39:44 +00003import unittest
Benjamin Petersonee8712c2008-05-20 21:35:26 +00004from test import support
Raymond Hettingerc8b6d1b2005-03-08 06:14:50 +00005from weakref import proxy
Jack Diederiche0cbd692009-04-01 04:27:09 +00006import pickle
Georg Brandl2e7346a2010-07-31 18:09:23 +00007from random import choice
Raymond Hettinger9c323f82005-02-28 19:39:44 +00008
9@staticmethod
10def PythonPartial(func, *args, **keywords):
11 'Pure Python approximation of partial()'
12 def newfunc(*fargs, **fkeywords):
13 newkeywords = keywords.copy()
14 newkeywords.update(fkeywords)
15 return func(*(args + fargs), **newkeywords)
16 newfunc.func = func
17 newfunc.args = args
18 newfunc.keywords = keywords
19 return newfunc
20
21def capture(*args, **kw):
22 """capture all positional and keyword arguments"""
23 return args, kw
24
Jack Diederiche0cbd692009-04-01 04:27:09 +000025def signature(part):
26 """ return the signature of a partial object """
27 return (part.func, part.args, part.keywords, part.__dict__)
Guido van Rossumc1f779c2007-07-03 08:25:58 +000028
Raymond Hettinger9c323f82005-02-28 19:39:44 +000029class TestPartial(unittest.TestCase):
30
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000031 thetype = functools.partial
Raymond Hettinger9c323f82005-02-28 19:39:44 +000032
33 def test_basic_examples(self):
34 p = self.thetype(capture, 1, 2, a=10, b=20)
35 self.assertEqual(p(3, 4, b=30, c=40),
36 ((1, 2, 3, 4), dict(a=10, b=30, c=40)))
37 p = self.thetype(map, lambda x: x*10)
Guido van Rossumc1f779c2007-07-03 08:25:58 +000038 self.assertEqual(list(p([1,2,3,4])), [10, 20, 30, 40])
Raymond Hettinger9c323f82005-02-28 19:39:44 +000039
40 def test_attributes(self):
41 p = self.thetype(capture, 1, 2, a=10, b=20)
42 # attributes should be readable
43 self.assertEqual(p.func, capture)
44 self.assertEqual(p.args, (1, 2))
45 self.assertEqual(p.keywords, dict(a=10, b=20))
46 # attributes should not be writable
47 if not isinstance(self.thetype, type):
48 return
Georg Brandl89fad142010-03-14 10:23:39 +000049 self.assertRaises(AttributeError, setattr, p, 'func', map)
50 self.assertRaises(AttributeError, setattr, p, 'args', (1, 2))
51 self.assertRaises(AttributeError, setattr, p, 'keywords', dict(a=1, b=2))
52
53 p = self.thetype(hex)
54 try:
55 del p.__dict__
56 except TypeError:
57 pass
58 else:
59 self.fail('partial object allowed __dict__ to be deleted')
Raymond Hettinger9c323f82005-02-28 19:39:44 +000060
61 def test_argument_checking(self):
62 self.assertRaises(TypeError, self.thetype) # need at least a func arg
63 try:
64 self.thetype(2)()
65 except TypeError:
66 pass
67 else:
68 self.fail('First arg not checked for callability')
69
70 def test_protection_of_callers_dict_argument(self):
71 # a caller's dictionary should not be altered by partial
72 def func(a=10, b=20):
73 return a
74 d = {'a':3}
75 p = self.thetype(func, a=5)
76 self.assertEqual(p(**d), 3)
77 self.assertEqual(d, {'a':3})
78 p(b=7)
79 self.assertEqual(d, {'a':3})
80
81 def test_arg_combinations(self):
82 # exercise special code paths for zero args in either partial
83 # object or the caller
84 p = self.thetype(capture)
85 self.assertEqual(p(), ((), {}))
86 self.assertEqual(p(1,2), ((1,2), {}))
87 p = self.thetype(capture, 1, 2)
88 self.assertEqual(p(), ((1,2), {}))
89 self.assertEqual(p(3,4), ((1,2,3,4), {}))
90
91 def test_kw_combinations(self):
92 # exercise special code paths for no keyword args in
93 # either the partial object or the caller
94 p = self.thetype(capture)
95 self.assertEqual(p(), ((), {}))
96 self.assertEqual(p(a=1), ((), {'a':1}))
97 p = self.thetype(capture, a=1)
98 self.assertEqual(p(), ((), {'a':1}))
99 self.assertEqual(p(b=2), ((), {'a':1, 'b':2}))
100 # keyword args in the call override those in the partial object
101 self.assertEqual(p(a=3, b=2), ((), {'a':3, 'b':2}))
102
103 def test_positional(self):
104 # make sure positional arguments are captured correctly
105 for args in [(), (0,), (0,1), (0,1,2), (0,1,2,3)]:
106 p = self.thetype(capture, *args)
107 expected = args + ('x',)
108 got, empty = p('x')
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000109 self.assertTrue(expected == got and empty == {})
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000110
111 def test_keyword(self):
112 # make sure keyword arguments are captured correctly
113 for a in ['a', 0, None, 3.5]:
114 p = self.thetype(capture, a=a)
115 expected = {'a':a,'x':None}
116 empty, got = p(x=None)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000117 self.assertTrue(expected == got and empty == ())
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000118
119 def test_no_side_effects(self):
120 # make sure there are no side effects that affect subsequent calls
121 p = self.thetype(capture, 0, a=1)
122 args1, kw1 = p(1, b=2)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000123 self.assertTrue(args1 == (0,1) and kw1 == {'a':1,'b':2})
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000124 args2, kw2 = p()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000125 self.assertTrue(args2 == (0,) and kw2 == {'a':1})
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000126
127 def test_error_propagation(self):
128 def f(x, y):
129 x / y
130 self.assertRaises(ZeroDivisionError, self.thetype(f, 1, 0))
131 self.assertRaises(ZeroDivisionError, self.thetype(f, 1), 0)
132 self.assertRaises(ZeroDivisionError, self.thetype(f), 1, 0)
133 self.assertRaises(ZeroDivisionError, self.thetype(f, y=0), 1)
134
Raymond Hettingerc8b6d1b2005-03-08 06:14:50 +0000135 def test_weakref(self):
136 f = self.thetype(int, base=16)
137 p = proxy(f)
138 self.assertEqual(f.func, p.func)
139 f = None
140 self.assertRaises(ReferenceError, getattr, p, 'func')
141
Raymond Hettinger26e512a2005-03-11 06:48:49 +0000142 def test_with_bound_and_unbound_methods(self):
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000143 data = list(map(str, range(10)))
Raymond Hettinger26e512a2005-03-11 06:48:49 +0000144 join = self.thetype(str.join, '')
145 self.assertEqual(join(data), '0123456789')
146 join = self.thetype(''.join)
147 self.assertEqual(join(data), '0123456789')
Tim Peterseba28be2005-03-28 01:08:02 +0000148
Jack Diederiche0cbd692009-04-01 04:27:09 +0000149 def test_pickle(self):
150 f = self.thetype(signature, 'asdf', bar=True)
151 f.add_something_to__dict__ = True
152 f_copy = pickle.loads(pickle.dumps(f))
153 self.assertEqual(signature(f), signature(f_copy))
154
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000155class PartialSubclass(functools.partial):
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000156 pass
157
158class TestPartialSubclass(TestPartial):
159
160 thetype = PartialSubclass
161
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000162class TestPythonPartial(TestPartial):
163
164 thetype = PythonPartial
165
Jack Diederiche0cbd692009-04-01 04:27:09 +0000166 # the python version isn't picklable
167 def test_pickle(self): pass
168
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000169class TestUpdateWrapper(unittest.TestCase):
170
171 def check_wrapper(self, wrapper, wrapped,
172 assigned=functools.WRAPPER_ASSIGNMENTS,
173 updated=functools.WRAPPER_UPDATES):
174 # Check attributes were assigned
175 for name in assigned:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000176 self.assertTrue(getattr(wrapper, name) is getattr(wrapped, name))
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000177 # Check attributes were updated
178 for name in updated:
179 wrapper_attr = getattr(wrapper, name)
180 wrapped_attr = getattr(wrapped, name)
181 for key in wrapped_attr:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000182 self.assertTrue(wrapped_attr[key] is wrapper_attr[key])
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000183
R. David Murray378c0cf2010-02-24 01:46:21 +0000184 def _default_update(self):
Antoine Pitrou560f7642010-08-04 18:28:02 +0000185 def f(a:'This is a new annotation'):
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000186 """This is a test"""
187 pass
188 f.attr = 'This is also a test'
Antoine Pitrou560f7642010-08-04 18:28:02 +0000189 def wrapper(b:'This is the prior annotation'):
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000190 pass
191 functools.update_wrapper(wrapper, f)
R. David Murray378c0cf2010-02-24 01:46:21 +0000192 return wrapper, f
193
194 def test_default_update(self):
195 wrapper, f = self._default_update()
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000196 self.check_wrapper(wrapper, f)
197 self.assertEqual(wrapper.__name__, 'f')
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000198 self.assertEqual(wrapper.attr, 'This is also a test')
Antoine Pitrou560f7642010-08-04 18:28:02 +0000199 self.assertEqual(wrapper.__annotations__['a'], 'This is a new annotation')
200 self.assertNotIn('b', wrapper.__annotations__)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000201
R. David Murray378c0cf2010-02-24 01:46:21 +0000202 @unittest.skipIf(sys.flags.optimize >= 2,
203 "Docstrings are omitted with -O2 and above")
204 def test_default_update_doc(self):
205 wrapper, f = self._default_update()
206 self.assertEqual(wrapper.__doc__, 'This is a test')
207
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000208 def test_no_update(self):
209 def f():
210 """This is a test"""
211 pass
212 f.attr = 'This is also a test'
213 def wrapper():
214 pass
215 functools.update_wrapper(wrapper, f, (), ())
216 self.check_wrapper(wrapper, f, (), ())
217 self.assertEqual(wrapper.__name__, 'wrapper')
218 self.assertEqual(wrapper.__doc__, None)
Antoine Pitrou560f7642010-08-04 18:28:02 +0000219 self.assertEqual(wrapper.__annotations__, {})
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000220 self.assertFalse(hasattr(wrapper, 'attr'))
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000221
222 def test_selective_update(self):
223 def f():
224 pass
225 f.attr = 'This is a different test'
226 f.dict_attr = dict(a=1, b=2, c=3)
227 def wrapper():
228 pass
229 wrapper.dict_attr = {}
230 assign = ('attr',)
231 update = ('dict_attr',)
232 functools.update_wrapper(wrapper, f, assign, update)
233 self.check_wrapper(wrapper, f, assign, update)
234 self.assertEqual(wrapper.__name__, 'wrapper')
235 self.assertEqual(wrapper.__doc__, None)
236 self.assertEqual(wrapper.attr, 'This is a different test')
237 self.assertEqual(wrapper.dict_attr, f.dict_attr)
238
Thomas Wouters89f507f2006-12-13 04:49:30 +0000239 def test_builtin_update(self):
240 # Test for bug #1576241
241 def wrapper():
242 pass
243 functools.update_wrapper(wrapper, max)
244 self.assertEqual(wrapper.__name__, 'max')
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000245 self.assertTrue(wrapper.__doc__.startswith('max('))
Antoine Pitrou560f7642010-08-04 18:28:02 +0000246 self.assertEqual(wrapper.__annotations__, {})
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000247
248class TestWraps(TestUpdateWrapper):
249
R. David Murray378c0cf2010-02-24 01:46:21 +0000250 def _default_update(self):
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000251 def f():
252 """This is a test"""
253 pass
254 f.attr = 'This is also a test'
255 @functools.wraps(f)
256 def wrapper():
257 pass
258 self.check_wrapper(wrapper, f)
R. David Murray378c0cf2010-02-24 01:46:21 +0000259 return wrapper
260
261 def test_default_update(self):
262 wrapper = self._default_update()
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000263 self.assertEqual(wrapper.__name__, 'f')
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000264 self.assertEqual(wrapper.attr, 'This is also a test')
265
R. David Murray378c0cf2010-02-24 01:46:21 +0000266 @unittest.skipIf(not sys.flags.optimize <= 1,
267 "Docstrings are omitted with -O2 and above")
268 def test_default_update_doc(self):
269 wrapper = self._default_update()
270 self.assertEqual(wrapper.__doc__, 'This is a test')
271
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000272 def test_no_update(self):
273 def f():
274 """This is a test"""
275 pass
276 f.attr = 'This is also a test'
277 @functools.wraps(f, (), ())
278 def wrapper():
279 pass
280 self.check_wrapper(wrapper, f, (), ())
281 self.assertEqual(wrapper.__name__, 'wrapper')
282 self.assertEqual(wrapper.__doc__, None)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000283 self.assertFalse(hasattr(wrapper, 'attr'))
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000284
285 def test_selective_update(self):
286 def f():
287 pass
288 f.attr = 'This is a different test'
289 f.dict_attr = dict(a=1, b=2, c=3)
290 def add_dict_attr(f):
291 f.dict_attr = {}
292 return f
293 assign = ('attr',)
294 update = ('dict_attr',)
295 @functools.wraps(f, assign, update)
296 @add_dict_attr
297 def wrapper():
298 pass
299 self.check_wrapper(wrapper, f, assign, update)
300 self.assertEqual(wrapper.__name__, 'wrapper')
301 self.assertEqual(wrapper.__doc__, None)
302 self.assertEqual(wrapper.attr, 'This is a different test')
303 self.assertEqual(wrapper.dict_attr, f.dict_attr)
304
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000305class TestReduce(unittest.TestCase):
306 func = functools.reduce
307
308 def test_reduce(self):
309 class Squares:
310 def __init__(self, max):
311 self.max = max
312 self.sofar = []
313
314 def __len__(self):
315 return len(self.sofar)
316
317 def __getitem__(self, i):
318 if not 0 <= i < self.max: raise IndexError
319 n = len(self.sofar)
320 while n <= i:
321 self.sofar.append(n*n)
322 n += 1
323 return self.sofar[i]
Alexander Belopolskye29e6bf2010-08-16 18:55:46 +0000324 def add(x, y):
325 return x + y
326 self.assertEqual(self.func(add, ['a', 'b', 'c'], ''), 'abc')
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000327 self.assertEqual(
Alexander Belopolskye29e6bf2010-08-16 18:55:46 +0000328 self.func(add, [['a', 'c'], [], ['d', 'w']], []),
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000329 ['a','c','d','w']
330 )
331 self.assertEqual(self.func(lambda x, y: x*y, range(2,8), 1), 5040)
332 self.assertEqual(
Guido van Rossume2a383d2007-01-15 16:59:06 +0000333 self.func(lambda x, y: x*y, range(2,21), 1),
334 2432902008176640000
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000335 )
Alexander Belopolskye29e6bf2010-08-16 18:55:46 +0000336 self.assertEqual(self.func(add, Squares(10)), 285)
337 self.assertEqual(self.func(add, Squares(10), 0), 285)
338 self.assertEqual(self.func(add, Squares(0), 0), 0)
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000339 self.assertRaises(TypeError, self.func)
340 self.assertRaises(TypeError, self.func, 42, 42)
341 self.assertRaises(TypeError, self.func, 42, 42, 42)
342 self.assertEqual(self.func(42, "1"), "1") # func is never called with one item
343 self.assertEqual(self.func(42, "", "1"), "1") # func is never called with one item
344 self.assertRaises(TypeError, self.func, 42, (42, 42))
Alexander Belopolskye29e6bf2010-08-16 18:55:46 +0000345 self.assertRaises(TypeError, self.func, add, []) # arg 2 must not be empty sequence with no initial value
346 self.assertRaises(TypeError, self.func, add, "")
347 self.assertRaises(TypeError, self.func, add, ())
348 self.assertRaises(TypeError, self.func, add, object())
349
350 class TestFailingIter:
351 def __iter__(self):
352 raise RuntimeError
353 self.assertRaises(RuntimeError, self.func, add, TestFailingIter())
354
355 self.assertEqual(self.func(add, [], None), None)
356 self.assertEqual(self.func(add, [], 42), 42)
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000357
358 class BadSeq:
359 def __getitem__(self, index):
360 raise ValueError
361 self.assertRaises(ValueError, self.func, 42, BadSeq())
362
363 # Test reduce()'s use of iterators.
364 def test_iterator_usage(self):
365 class SequenceClass:
366 def __init__(self, n):
367 self.n = n
368 def __getitem__(self, i):
369 if 0 <= i < self.n:
370 return i
371 else:
372 raise IndexError
Guido van Rossumd8faa362007-04-27 19:54:29 +0000373
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000374 from operator import add
375 self.assertEqual(self.func(add, SequenceClass(5)), 10)
376 self.assertEqual(self.func(add, SequenceClass(5), 42), 52)
377 self.assertRaises(TypeError, self.func, add, SequenceClass(0))
378 self.assertEqual(self.func(add, SequenceClass(0), 42), 42)
379 self.assertEqual(self.func(add, SequenceClass(1)), 0)
380 self.assertEqual(self.func(add, SequenceClass(1), 42), 42)
381
382 d = {"one": 1, "two": 2, "three": 3}
383 self.assertEqual(self.func(add, d), "".join(d.keys()))
384
Raymond Hettingerc50846a2010-04-05 18:56:31 +0000385class TestCmpToKey(unittest.TestCase):
386 def test_cmp_to_key(self):
387 def mycmp(x, y):
388 return y - x
389 self.assertEqual(sorted(range(5), key=functools.cmp_to_key(mycmp)),
390 [4, 3, 2, 1, 0])
Guido van Rossumd8faa362007-04-27 19:54:29 +0000391
Raymond Hettingerc50846a2010-04-05 18:56:31 +0000392 def test_hash(self):
393 def mycmp(x, y):
394 return y - x
395 key = functools.cmp_to_key(mycmp)
396 k = key(10)
397 self.assertRaises(TypeError, hash(k))
398
399class TestTotalOrdering(unittest.TestCase):
400
401 def test_total_ordering_lt(self):
402 @functools.total_ordering
403 class A:
404 def __init__(self, value):
405 self.value = value
406 def __lt__(self, other):
407 return self.value < other.value
408 self.assert_(A(1) < A(2))
409 self.assert_(A(2) > A(1))
410 self.assert_(A(1) <= A(2))
411 self.assert_(A(2) >= A(1))
412 self.assert_(A(2) <= A(2))
413 self.assert_(A(2) >= A(2))
414
415 def test_total_ordering_le(self):
416 @functools.total_ordering
417 class A:
418 def __init__(self, value):
419 self.value = value
420 def __le__(self, other):
421 return self.value <= other.value
422 self.assert_(A(1) < A(2))
423 self.assert_(A(2) > A(1))
424 self.assert_(A(1) <= A(2))
425 self.assert_(A(2) >= A(1))
426 self.assert_(A(2) <= A(2))
427 self.assert_(A(2) >= A(2))
428
429 def test_total_ordering_gt(self):
430 @functools.total_ordering
431 class A:
432 def __init__(self, value):
433 self.value = value
434 def __gt__(self, other):
435 return self.value > other.value
436 self.assert_(A(1) < A(2))
437 self.assert_(A(2) > A(1))
438 self.assert_(A(1) <= A(2))
439 self.assert_(A(2) >= A(1))
440 self.assert_(A(2) <= A(2))
441 self.assert_(A(2) >= A(2))
442
443 def test_total_ordering_ge(self):
444 @functools.total_ordering
445 class A:
446 def __init__(self, value):
447 self.value = value
448 def __ge__(self, other):
449 return self.value >= other.value
450 self.assert_(A(1) < A(2))
451 self.assert_(A(2) > A(1))
452 self.assert_(A(1) <= A(2))
453 self.assert_(A(2) >= A(1))
454 self.assert_(A(2) <= A(2))
455 self.assert_(A(2) >= A(2))
456
457 def test_total_ordering_no_overwrite(self):
458 # new methods should not overwrite existing
459 @functools.total_ordering
460 class A(int):
461 raise Exception()
462 self.assert_(A(1) < A(2))
463 self.assert_(A(2) > A(1))
464 self.assert_(A(1) <= A(2))
465 self.assert_(A(2) >= A(1))
466 self.assert_(A(2) <= A(2))
467 self.assert_(A(2) >= A(2))
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000468
Benjamin Peterson42ebee32010-04-11 01:43:16 +0000469 def test_no_operations_defined(self):
470 with self.assertRaises(ValueError):
471 @functools.total_ordering
472 class A:
473 pass
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000474
Georg Brandl2e7346a2010-07-31 18:09:23 +0000475class TestLRU(unittest.TestCase):
476
477 def test_lru(self):
478 def orig(x, y):
479 return 3*x+y
480 f = functools.lru_cache(maxsize=20)(orig)
481
482 domain = range(5)
483 for i in range(1000):
484 x, y = choice(domain), choice(domain)
485 actual = f(x, y)
486 expected = orig(x, y)
487 self.assertEquals(actual, expected)
488 self.assert_(f.hits > f.misses)
489 self.assertEquals(f.hits + f.misses, 1000)
490
491 f.clear() # test clearing
492 self.assertEqual(f.hits, 0)
493 self.assertEqual(f.misses, 0)
494 f(x, y)
495 self.assertEqual(f.hits, 0)
496 self.assertEqual(f.misses, 1)
497
Raymond Hettinger0f56e902010-08-14 23:52:08 +0000498 # test size zero (which means "never-cache")
Raymond Hettinger0f56e902010-08-14 23:52:08 +0000499 @functools.lru_cache(0)
500 def f():
501 nonlocal f_cnt
502 f_cnt += 1
503 return 20
Raymond Hettingerf3098282010-08-15 03:30:45 +0000504 f_cnt = 0
505 for i in range(5):
506 self.assertEqual(f(), 20)
507 self.assertEqual(f_cnt, 5)
Raymond Hettinger0f56e902010-08-14 23:52:08 +0000508
509 # test size one
Raymond Hettinger0f56e902010-08-14 23:52:08 +0000510 @functools.lru_cache(1)
511 def f():
512 nonlocal f_cnt
513 f_cnt += 1
514 return 20
Raymond Hettingerf3098282010-08-15 03:30:45 +0000515 f_cnt = 0
516 for i in range(5):
517 self.assertEqual(f(), 20)
Raymond Hettinger0f56e902010-08-14 23:52:08 +0000518 self.assertEqual(f_cnt, 1)
519
Raymond Hettingerf3098282010-08-15 03:30:45 +0000520 # test size two
521 @functools.lru_cache(2)
522 def f(x):
Raymond Hettinger0f56e902010-08-14 23:52:08 +0000523 nonlocal f_cnt
524 f_cnt += 1
Raymond Hettingerf3098282010-08-15 03:30:45 +0000525 return x*10
Raymond Hettinger0f56e902010-08-14 23:52:08 +0000526 f_cnt = 0
Raymond Hettingerf3098282010-08-15 03:30:45 +0000527 for x in 7, 9, 7, 9, 7, 9, 8, 8, 8, 9, 9, 9, 8, 8, 8, 7:
528 # * * * *
529 self.assertEqual(f(x), x*10)
530 self.assertEqual(f_cnt, 4)
Raymond Hettinger0f56e902010-08-14 23:52:08 +0000531
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000532def test_main(verbose=None):
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000533 test_classes = (
534 TestPartial,
535 TestPartialSubclass,
536 TestPythonPartial,
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000537 TestUpdateWrapper,
Guido van Rossum0919a1a2006-08-26 20:49:04 +0000538 TestWraps,
Georg Brandl2e7346a2010-07-31 18:09:23 +0000539 TestReduce,
540 TestLRU,
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000541 )
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000542 support.run_unittest(*test_classes)
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000543
544 # verify reference counting
545 if verbose and hasattr(sys, "gettotalrefcount"):
546 import gc
547 counts = [None] * 5
Guido van Rossum805365e2007-05-07 22:24:25 +0000548 for i in range(len(counts)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000549 support.run_unittest(*test_classes)
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000550 gc.collect()
551 counts[i] = sys.gettotalrefcount()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000552 print(counts)
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000553
554if __name__ == '__main__':
555 test_main(verbose=True)