blob: 06a9da3f41a65d4b7d33bac4933dcc27ca9cae7d [file] [log] [blame]
Serhiy Storchaka71b71762016-02-02 18:45:59 +02001import copy
Nick Coghlanc649ec52006-05-29 12:43:05 +00002import functools
R. David Murrayf28fd242010-02-23 00:24:49 +00003import sys
Raymond Hettinger9c323f82005-02-28 19:39:44 +00004import unittest
5from test import test_support
Raymond Hettingerc8b6d1b2005-03-08 06:14:50 +00006from weakref import proxy
Jack Diederichd60c29e2009-03-31 23:46:48 +00007import pickle
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 Diederichd60c29e2009-03-31 23:46:48 +000025def signature(part):
26 """ return the signature of a partial object """
27 return (part.func, part.args, part.keywords, part.__dict__)
28
Serhiy Storchaka71b71762016-02-02 18:45:59 +020029class MyTuple(tuple):
30 pass
31
32class BadTuple(tuple):
33 def __add__(self, other):
34 return list(self) + list(other)
35
36class MyDict(dict):
37 pass
38
Raymond Hettinger9c323f82005-02-28 19:39:44 +000039class TestPartial(unittest.TestCase):
40
Nick Coghlanc649ec52006-05-29 12:43:05 +000041 thetype = functools.partial
Raymond Hettinger9c323f82005-02-28 19:39:44 +000042
43 def test_basic_examples(self):
44 p = self.thetype(capture, 1, 2, a=10, b=20)
45 self.assertEqual(p(3, 4, b=30, c=40),
46 ((1, 2, 3, 4), dict(a=10, b=30, c=40)))
47 p = self.thetype(map, lambda x: x*10)
48 self.assertEqual(p([1,2,3,4]), [10, 20, 30, 40])
49
50 def test_attributes(self):
51 p = self.thetype(capture, 1, 2, a=10, b=20)
52 # attributes should be readable
53 self.assertEqual(p.func, capture)
54 self.assertEqual(p.args, (1, 2))
55 self.assertEqual(p.keywords, dict(a=10, b=20))
56 # attributes should not be writable
Raymond Hettinger9c323f82005-02-28 19:39:44 +000057 self.assertRaises(TypeError, setattr, p, 'func', map)
58 self.assertRaises(TypeError, setattr, p, 'args', (1, 2))
59 self.assertRaises(TypeError, setattr, p, 'keywords', dict(a=1, b=2))
60
Georg Brandla34f87f2010-02-07 12:27:06 +000061 p = self.thetype(hex)
62 try:
63 del p.__dict__
64 except TypeError:
65 pass
66 else:
67 self.fail('partial object allowed __dict__ to be deleted')
68
Raymond Hettinger9c323f82005-02-28 19:39:44 +000069 def test_argument_checking(self):
70 self.assertRaises(TypeError, self.thetype) # need at least a func arg
71 try:
72 self.thetype(2)()
73 except TypeError:
74 pass
75 else:
76 self.fail('First arg not checked for callability')
77
78 def test_protection_of_callers_dict_argument(self):
79 # a caller's dictionary should not be altered by partial
80 def func(a=10, b=20):
81 return a
82 d = {'a':3}
83 p = self.thetype(func, a=5)
84 self.assertEqual(p(**d), 3)
85 self.assertEqual(d, {'a':3})
86 p(b=7)
87 self.assertEqual(d, {'a':3})
88
89 def test_arg_combinations(self):
90 # exercise special code paths for zero args in either partial
91 # object or the caller
92 p = self.thetype(capture)
93 self.assertEqual(p(), ((), {}))
94 self.assertEqual(p(1,2), ((1,2), {}))
95 p = self.thetype(capture, 1, 2)
96 self.assertEqual(p(), ((1,2), {}))
97 self.assertEqual(p(3,4), ((1,2,3,4), {}))
98
99 def test_kw_combinations(self):
100 # exercise special code paths for no keyword args in
101 # either the partial object or the caller
102 p = self.thetype(capture)
Benjamin Peterson72c01412015-05-09 00:23:41 -0400103 self.assertEqual(p.keywords, {})
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000104 self.assertEqual(p(), ((), {}))
105 self.assertEqual(p(a=1), ((), {'a':1}))
106 p = self.thetype(capture, a=1)
Benjamin Peterson72c01412015-05-09 00:23:41 -0400107 self.assertEqual(p.keywords, {'a':1})
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000108 self.assertEqual(p(), ((), {'a':1}))
109 self.assertEqual(p(b=2), ((), {'a':1, 'b':2}))
110 # keyword args in the call override those in the partial object
111 self.assertEqual(p(a=3, b=2), ((), {'a':3, 'b':2}))
112
113 def test_positional(self):
114 # make sure positional arguments are captured correctly
115 for args in [(), (0,), (0,1), (0,1,2), (0,1,2,3)]:
116 p = self.thetype(capture, *args)
117 expected = args + ('x',)
118 got, empty = p('x')
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000119 self.assertTrue(expected == got and empty == {})
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000120
121 def test_keyword(self):
122 # make sure keyword arguments are captured correctly
123 for a in ['a', 0, None, 3.5]:
124 p = self.thetype(capture, a=a)
125 expected = {'a':a,'x':None}
126 empty, got = p(x=None)
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000127 self.assertTrue(expected == got and empty == ())
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000128
129 def test_no_side_effects(self):
130 # make sure there are no side effects that affect subsequent calls
131 p = self.thetype(capture, 0, a=1)
132 args1, kw1 = p(1, b=2)
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000133 self.assertTrue(args1 == (0,1) and kw1 == {'a':1,'b':2})
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000134 args2, kw2 = p()
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000135 self.assertTrue(args2 == (0,) and kw2 == {'a':1})
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000136
137 def test_error_propagation(self):
138 def f(x, y):
Ezio Melottidde5b942010-02-03 05:37:26 +0000139 x // y
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000140 self.assertRaises(ZeroDivisionError, self.thetype(f, 1, 0))
141 self.assertRaises(ZeroDivisionError, self.thetype(f, 1), 0)
142 self.assertRaises(ZeroDivisionError, self.thetype(f), 1, 0)
143 self.assertRaises(ZeroDivisionError, self.thetype(f, y=0), 1)
144
Raymond Hettingerc8b6d1b2005-03-08 06:14:50 +0000145 def test_weakref(self):
146 f = self.thetype(int, base=16)
147 p = proxy(f)
148 self.assertEqual(f.func, p.func)
149 f = None
150 self.assertRaises(ReferenceError, getattr, p, 'func')
151
Raymond Hettinger26e512a2005-03-11 06:48:49 +0000152 def test_with_bound_and_unbound_methods(self):
153 data = map(str, range(10))
154 join = self.thetype(str.join, '')
155 self.assertEqual(join(data), '0123456789')
156 join = self.thetype(''.join)
157 self.assertEqual(join(data), '0123456789')
Tim Peterseba28be2005-03-28 01:08:02 +0000158
Jack Diederichd60c29e2009-03-31 23:46:48 +0000159 def test_pickle(self):
Serhiy Storchaka71b71762016-02-02 18:45:59 +0200160 f = self.thetype(signature, ['asdf'], bar=[True])
161 f.attr = []
Serhiy Storchaka655720e2014-12-15 14:02:43 +0200162 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
163 f_copy = pickle.loads(pickle.dumps(f, proto))
Serhiy Storchaka71b71762016-02-02 18:45:59 +0200164 self.assertEqual(signature(f_copy), signature(f))
165
166 def test_copy(self):
167 f = self.thetype(signature, ['asdf'], bar=[True])
168 f.attr = []
169 f_copy = copy.copy(f)
170 self.assertEqual(signature(f_copy), signature(f))
171 self.assertIs(f_copy.attr, f.attr)
172 self.assertIs(f_copy.args, f.args)
173 self.assertIs(f_copy.keywords, f.keywords)
174
175 def test_deepcopy(self):
176 f = self.thetype(signature, ['asdf'], bar=[True])
177 f.attr = []
178 f_copy = copy.deepcopy(f)
179 self.assertEqual(signature(f_copy), signature(f))
180 self.assertIsNot(f_copy.attr, f.attr)
181 self.assertIsNot(f_copy.args, f.args)
182 self.assertIsNot(f_copy.args[0], f.args[0])
183 self.assertIsNot(f_copy.keywords, f.keywords)
184 self.assertIsNot(f_copy.keywords['bar'], f.keywords['bar'])
185
186 def test_setstate(self):
187 f = self.thetype(signature)
188 f.__setstate__((capture, (1,), dict(a=10), dict(attr=[])))
189 self.assertEqual(signature(f),
190 (capture, (1,), dict(a=10), dict(attr=[])))
191 self.assertEqual(f(2, b=20), ((1, 2), {'a': 10, 'b': 20}))
192
193 f.__setstate__((capture, (1,), dict(a=10), None))
194 self.assertEqual(signature(f), (capture, (1,), dict(a=10), {}))
195 self.assertEqual(f(2, b=20), ((1, 2), {'a': 10, 'b': 20}))
196
197 f.__setstate__((capture, (1,), None, None))
198 #self.assertEqual(signature(f), (capture, (1,), {}, {}))
199 self.assertEqual(f(2, b=20), ((1, 2), {'b': 20}))
200 self.assertEqual(f(2), ((1, 2), {}))
201 self.assertEqual(f(), ((1,), {}))
202
203 f.__setstate__((capture, (), {}, None))
204 self.assertEqual(signature(f), (capture, (), {}, {}))
205 self.assertEqual(f(2, b=20), ((2,), {'b': 20}))
206 self.assertEqual(f(2), ((2,), {}))
207 self.assertEqual(f(), ((), {}))
208
209 def test_setstate_errors(self):
210 f = self.thetype(signature)
211 self.assertRaises(TypeError, f.__setstate__, (capture, (), {}))
212 self.assertRaises(TypeError, f.__setstate__, (capture, (), {}, {}, None))
213 self.assertRaises(TypeError, f.__setstate__, [capture, (), {}, None])
214 self.assertRaises(TypeError, f.__setstate__, (None, (), {}, None))
215 self.assertRaises(TypeError, f.__setstate__, (capture, None, {}, None))
216 self.assertRaises(TypeError, f.__setstate__, (capture, [], {}, None))
217 self.assertRaises(TypeError, f.__setstate__, (capture, (), [], None))
218
219 def test_setstate_subclasses(self):
220 f = self.thetype(signature)
221 f.__setstate__((capture, MyTuple((1,)), MyDict(a=10), None))
222 s = signature(f)
223 self.assertEqual(s, (capture, (1,), dict(a=10), {}))
224 self.assertIs(type(s[1]), tuple)
225 self.assertIs(type(s[2]), dict)
226 r = f()
227 self.assertEqual(r, ((1,), {'a': 10}))
228 self.assertIs(type(r[0]), tuple)
229 self.assertIs(type(r[1]), dict)
230
231 f.__setstate__((capture, BadTuple((1,)), {}, None))
232 s = signature(f)
233 self.assertEqual(s, (capture, (1,), {}, {}))
234 self.assertIs(type(s[1]), tuple)
235 r = f(2)
236 self.assertEqual(r, ((1, 2), {}))
237 self.assertIs(type(r[0]), tuple)
Jack Diederichd60c29e2009-03-31 23:46:48 +0000238
Serhiy Storchaka1e090062016-06-12 15:08:57 +0300239 def test_recursive_pickle(self):
240 f = self.thetype(capture)
241 f.__setstate__((f, (), {}, {}))
242 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
243 with self.assertRaises(RuntimeError):
244 pickle.dumps(f, proto)
245
246 f = self.thetype(capture)
247 f.__setstate__((capture, (f,), {}, {}))
248 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
249 f_copy = pickle.loads(pickle.dumps(f, proto))
250 self.assertIs(f_copy.args[0], f_copy)
251
252 f = self.thetype(capture)
253 f.__setstate__((capture, (), {'a': f}, {}))
254 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
255 f_copy = pickle.loads(pickle.dumps(f, proto))
256 self.assertIs(f_copy.keywords['a'], f_copy)
257
Serhiy Storchakaa07a8b42013-02-04 12:45:46 +0200258 # Issue 6083: Reference counting bug
259 def test_setstate_refcount(self):
260 class BadSequence:
261 def __len__(self):
262 return 4
263 def __getitem__(self, key):
264 if key == 0:
265 return max
266 elif key == 1:
267 return tuple(range(1000000))
268 elif key in (2, 3):
269 return {}
270 raise IndexError
271
272 f = self.thetype(object)
Serhiy Storchaka71b71762016-02-02 18:45:59 +0200273 self.assertRaises(TypeError, f.__setstate__, BadSequence())
Serhiy Storchakaa07a8b42013-02-04 12:45:46 +0200274
Nick Coghlanc649ec52006-05-29 12:43:05 +0000275class PartialSubclass(functools.partial):
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000276 pass
277
278class TestPartialSubclass(TestPartial):
279
280 thetype = PartialSubclass
281
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000282class TestPythonPartial(TestPartial):
283
284 thetype = PythonPartial
285
Jack Diederichd60c29e2009-03-31 23:46:48 +0000286 # the python version isn't picklable
Serhiy Storchaka71b71762016-02-02 18:45:59 +0200287 test_pickle = None
288 test_setstate = None
289 test_setstate_errors = None
290 test_setstate_subclasses = None
291 test_setstate_refcount = None
Serhiy Storchaka1e090062016-06-12 15:08:57 +0300292 test_recursive_pickle = None
Serhiy Storchaka71b71762016-02-02 18:45:59 +0200293
294 # the python version isn't deepcopyable
295 test_deepcopy = None
Zachary Ware1f702212013-12-10 14:09:20 -0600296
297 # the python version isn't a type
298 test_attributes = None
Jack Diederichd60c29e2009-03-31 23:46:48 +0000299
Nick Coghlan676725d2006-06-08 13:54:49 +0000300class TestUpdateWrapper(unittest.TestCase):
301
302 def check_wrapper(self, wrapper, wrapped,
303 assigned=functools.WRAPPER_ASSIGNMENTS,
304 updated=functools.WRAPPER_UPDATES):
305 # Check attributes were assigned
306 for name in assigned:
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000307 self.assertTrue(getattr(wrapper, name) is getattr(wrapped, name))
Nick Coghlan676725d2006-06-08 13:54:49 +0000308 # Check attributes were updated
309 for name in updated:
310 wrapper_attr = getattr(wrapper, name)
311 wrapped_attr = getattr(wrapped, name)
312 for key in wrapped_attr:
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000313 self.assertTrue(wrapped_attr[key] is wrapper_attr[key])
Nick Coghlan676725d2006-06-08 13:54:49 +0000314
R. David Murrayf28fd242010-02-23 00:24:49 +0000315 def _default_update(self):
Nick Coghlan676725d2006-06-08 13:54:49 +0000316 def f():
317 """This is a test"""
318 pass
319 f.attr = 'This is also a test'
320 def wrapper():
321 pass
322 functools.update_wrapper(wrapper, f)
R. David Murrayf28fd242010-02-23 00:24:49 +0000323 return wrapper, f
324
325 def test_default_update(self):
326 wrapper, f = self._default_update()
Nick Coghlan676725d2006-06-08 13:54:49 +0000327 self.check_wrapper(wrapper, f)
328 self.assertEqual(wrapper.__name__, 'f')
Nick Coghlan676725d2006-06-08 13:54:49 +0000329 self.assertEqual(wrapper.attr, 'This is also a test')
330
R. David Murrayf28fd242010-02-23 00:24:49 +0000331 @unittest.skipIf(sys.flags.optimize >= 2,
332 "Docstrings are omitted with -O2 and above")
333 def test_default_update_doc(self):
334 wrapper, f = self._default_update()
335 self.assertEqual(wrapper.__doc__, 'This is a test')
336
Nick Coghlan676725d2006-06-08 13:54:49 +0000337 def test_no_update(self):
338 def f():
339 """This is a test"""
340 pass
341 f.attr = 'This is also a test'
342 def wrapper():
343 pass
344 functools.update_wrapper(wrapper, f, (), ())
345 self.check_wrapper(wrapper, f, (), ())
346 self.assertEqual(wrapper.__name__, 'wrapper')
347 self.assertEqual(wrapper.__doc__, None)
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000348 self.assertFalse(hasattr(wrapper, 'attr'))
Nick Coghlan676725d2006-06-08 13:54:49 +0000349
350 def test_selective_update(self):
351 def f():
352 pass
353 f.attr = 'This is a different test'
354 f.dict_attr = dict(a=1, b=2, c=3)
355 def wrapper():
356 pass
357 wrapper.dict_attr = {}
358 assign = ('attr',)
359 update = ('dict_attr',)
360 functools.update_wrapper(wrapper, f, assign, update)
361 self.check_wrapper(wrapper, f, assign, update)
362 self.assertEqual(wrapper.__name__, 'wrapper')
363 self.assertEqual(wrapper.__doc__, None)
364 self.assertEqual(wrapper.attr, 'This is a different test')
365 self.assertEqual(wrapper.dict_attr, f.dict_attr)
366
Serhiy Storchaka72121c62013-01-27 19:45:49 +0200367 @test_support.requires_docstrings
Andrew M. Kuchling41eb7162006-10-27 16:39:10 +0000368 def test_builtin_update(self):
369 # Test for bug #1576241
370 def wrapper():
371 pass
372 functools.update_wrapper(wrapper, max)
373 self.assertEqual(wrapper.__name__, 'max')
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000374 self.assertTrue(wrapper.__doc__.startswith('max('))
Nick Coghlan676725d2006-06-08 13:54:49 +0000375
376class TestWraps(TestUpdateWrapper):
377
R. David Murrayf28fd242010-02-23 00:24:49 +0000378 def _default_update(self):
Nick Coghlan676725d2006-06-08 13:54:49 +0000379 def f():
380 """This is a test"""
381 pass
382 f.attr = 'This is also a test'
383 @functools.wraps(f)
384 def wrapper():
385 pass
386 self.check_wrapper(wrapper, f)
R. David Murrayf28fd242010-02-23 00:24:49 +0000387 return wrapper
388
389 def test_default_update(self):
390 wrapper = self._default_update()
Nick Coghlan676725d2006-06-08 13:54:49 +0000391 self.assertEqual(wrapper.__name__, 'f')
Nick Coghlan676725d2006-06-08 13:54:49 +0000392 self.assertEqual(wrapper.attr, 'This is also a test')
393
Serhiy Storchaka80a0a1e2013-01-28 13:24:01 +0200394 @unittest.skipIf(sys.flags.optimize >= 2,
R. David Murrayf28fd242010-02-23 00:24:49 +0000395 "Docstrings are omitted with -O2 and above")
396 def test_default_update_doc(self):
397 wrapper = self._default_update()
398 self.assertEqual(wrapper.__doc__, 'This is a test')
399
Nick Coghlan676725d2006-06-08 13:54:49 +0000400 def test_no_update(self):
401 def f():
402 """This is a test"""
403 pass
404 f.attr = 'This is also a test'
405 @functools.wraps(f, (), ())
406 def wrapper():
407 pass
408 self.check_wrapper(wrapper, f, (), ())
409 self.assertEqual(wrapper.__name__, 'wrapper')
410 self.assertEqual(wrapper.__doc__, None)
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000411 self.assertFalse(hasattr(wrapper, 'attr'))
Nick Coghlan676725d2006-06-08 13:54:49 +0000412
413 def test_selective_update(self):
414 def f():
415 pass
416 f.attr = 'This is a different test'
417 f.dict_attr = dict(a=1, b=2, c=3)
418 def add_dict_attr(f):
419 f.dict_attr = {}
420 return f
421 assign = ('attr',)
422 update = ('dict_attr',)
423 @functools.wraps(f, assign, update)
424 @add_dict_attr
425 def wrapper():
426 pass
427 self.check_wrapper(wrapper, f, assign, update)
428 self.assertEqual(wrapper.__name__, 'wrapper')
429 self.assertEqual(wrapper.__doc__, None)
430 self.assertEqual(wrapper.attr, 'This is a different test')
431 self.assertEqual(wrapper.dict_attr, f.dict_attr)
432
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000433
Brett Cannon83e81842008-08-09 23:30:55 +0000434class TestReduce(unittest.TestCase):
435
436 def test_reduce(self):
437 class Squares:
438
439 def __init__(self, max):
440 self.max = max
441 self.sofar = []
442
443 def __len__(self): return len(self.sofar)
444
445 def __getitem__(self, i):
446 if not 0 <= i < self.max: raise IndexError
447 n = len(self.sofar)
448 while n <= i:
449 self.sofar.append(n*n)
450 n += 1
451 return self.sofar[i]
452
453 reduce = functools.reduce
454 self.assertEqual(reduce(lambda x, y: x+y, ['a', 'b', 'c'], ''), 'abc')
455 self.assertEqual(
456 reduce(lambda x, y: x+y, [['a', 'c'], [], ['d', 'w']], []),
457 ['a','c','d','w']
458 )
459 self.assertEqual(reduce(lambda x, y: x*y, range(2,8), 1), 5040)
460 self.assertEqual(
461 reduce(lambda x, y: x*y, range(2,21), 1L),
462 2432902008176640000L
463 )
464 self.assertEqual(reduce(lambda x, y: x+y, Squares(10)), 285)
465 self.assertEqual(reduce(lambda x, y: x+y, Squares(10), 0), 285)
466 self.assertEqual(reduce(lambda x, y: x+y, Squares(0), 0), 0)
467 self.assertRaises(TypeError, reduce)
468 self.assertRaises(TypeError, reduce, 42, 42)
469 self.assertRaises(TypeError, reduce, 42, 42, 42)
470 self.assertEqual(reduce(42, "1"), "1") # func is never called with one item
471 self.assertEqual(reduce(42, "", "1"), "1") # func is never called with one item
472 self.assertRaises(TypeError, reduce, 42, (42, 42))
473
Raymond Hettingerbb006cf2010-04-04 21:45:01 +0000474class TestCmpToKey(unittest.TestCase):
475 def test_cmp_to_key(self):
476 def mycmp(x, y):
477 return y - x
478 self.assertEqual(sorted(range(5), key=functools.cmp_to_key(mycmp)),
479 [4, 3, 2, 1, 0])
Brett Cannon83e81842008-08-09 23:30:55 +0000480
Raymond Hettingere1d665a2010-04-05 18:53:43 +0000481 def test_hash(self):
482 def mycmp(x, y):
483 return y - x
484 key = functools.cmp_to_key(mycmp)
485 k = key(10)
486 self.assertRaises(TypeError, hash(k))
487
Raymond Hettinger06bc0b62010-04-04 22:24:03 +0000488class TestTotalOrdering(unittest.TestCase):
489
490 def test_total_ordering_lt(self):
491 @functools.total_ordering
492 class A:
493 def __init__(self, value):
494 self.value = value
495 def __lt__(self, other):
496 return self.value < other.value
Éric Araujo374274d2011-03-19 04:29:36 +0100497 def __eq__(self, other):
498 return self.value == other.value
Ezio Melotti2623a372010-11-21 13:34:58 +0000499 self.assertTrue(A(1) < A(2))
500 self.assertTrue(A(2) > A(1))
501 self.assertTrue(A(1) <= A(2))
502 self.assertTrue(A(2) >= A(1))
503 self.assertTrue(A(2) <= A(2))
504 self.assertTrue(A(2) >= A(2))
Raymond Hettinger06bc0b62010-04-04 22:24:03 +0000505
506 def test_total_ordering_le(self):
507 @functools.total_ordering
508 class A:
509 def __init__(self, value):
510 self.value = value
511 def __le__(self, other):
512 return self.value <= other.value
Éric Araujo374274d2011-03-19 04:29:36 +0100513 def __eq__(self, other):
514 return self.value == other.value
Ezio Melotti2623a372010-11-21 13:34:58 +0000515 self.assertTrue(A(1) < A(2))
516 self.assertTrue(A(2) > A(1))
517 self.assertTrue(A(1) <= A(2))
518 self.assertTrue(A(2) >= A(1))
519 self.assertTrue(A(2) <= A(2))
520 self.assertTrue(A(2) >= A(2))
Raymond Hettinger06bc0b62010-04-04 22:24:03 +0000521
522 def test_total_ordering_gt(self):
523 @functools.total_ordering
524 class A:
525 def __init__(self, value):
526 self.value = value
527 def __gt__(self, other):
528 return self.value > other.value
Éric Araujo374274d2011-03-19 04:29:36 +0100529 def __eq__(self, other):
530 return self.value == other.value
Ezio Melotti2623a372010-11-21 13:34:58 +0000531 self.assertTrue(A(1) < A(2))
532 self.assertTrue(A(2) > A(1))
533 self.assertTrue(A(1) <= A(2))
534 self.assertTrue(A(2) >= A(1))
535 self.assertTrue(A(2) <= A(2))
536 self.assertTrue(A(2) >= A(2))
Raymond Hettinger06bc0b62010-04-04 22:24:03 +0000537
538 def test_total_ordering_ge(self):
539 @functools.total_ordering
540 class A:
541 def __init__(self, value):
542 self.value = value
543 def __ge__(self, other):
544 return self.value >= other.value
Éric Araujo374274d2011-03-19 04:29:36 +0100545 def __eq__(self, other):
546 return self.value == other.value
Ezio Melotti2623a372010-11-21 13:34:58 +0000547 self.assertTrue(A(1) < A(2))
548 self.assertTrue(A(2) > A(1))
549 self.assertTrue(A(1) <= A(2))
550 self.assertTrue(A(2) >= A(1))
551 self.assertTrue(A(2) <= A(2))
552 self.assertTrue(A(2) >= A(2))
Raymond Hettinger06bc0b62010-04-04 22:24:03 +0000553
554 def test_total_ordering_no_overwrite(self):
555 # new methods should not overwrite existing
556 @functools.total_ordering
Benjamin Peterson9d0eaac2010-08-23 17:45:31 +0000557 class A(str):
Raymond Hettinger06bc0b62010-04-04 22:24:03 +0000558 pass
Ezio Melotti2623a372010-11-21 13:34:58 +0000559 self.assertTrue(A("a") < A("b"))
560 self.assertTrue(A("b") > A("a"))
561 self.assertTrue(A("a") <= A("b"))
562 self.assertTrue(A("b") >= A("a"))
563 self.assertTrue(A("b") <= A("b"))
564 self.assertTrue(A("b") >= A("b"))
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000565
Benjamin Petersona11da592010-04-11 01:40:32 +0000566 def test_no_operations_defined(self):
567 with self.assertRaises(ValueError):
568 @functools.total_ordering
569 class A:
570 pass
571
Éric Araujo374274d2011-03-19 04:29:36 +0100572 def test_bug_10042(self):
573 @functools.total_ordering
574 class TestTO:
575 def __init__(self, value):
576 self.value = value
577 def __eq__(self, other):
578 if isinstance(other, TestTO):
579 return self.value == other.value
580 return False
581 def __lt__(self, other):
582 if isinstance(other, TestTO):
583 return self.value < other.value
584 raise TypeError
585 with self.assertRaises(TypeError):
586 TestTO(8) <= ()
587
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000588def test_main(verbose=None):
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000589 test_classes = (
590 TestPartial,
591 TestPartialSubclass,
592 TestPythonPartial,
Nick Coghlan676725d2006-06-08 13:54:49 +0000593 TestUpdateWrapper,
Benjamin Peterson9d0eaac2010-08-23 17:45:31 +0000594 TestTotalOrdering,
Brett Cannon83e81842008-08-09 23:30:55 +0000595 TestWraps,
596 TestReduce,
Raymond Hettinger9c323f82005-02-28 19:39:44 +0000597 )
598 test_support.run_unittest(*test_classes)
599
600 # verify reference counting
601 if verbose and hasattr(sys, "gettotalrefcount"):
602 import gc
603 counts = [None] * 5
604 for i in xrange(len(counts)):
605 test_support.run_unittest(*test_classes)
606 gc.collect()
607 counts[i] = sys.gettotalrefcount()
608 print counts
609
610if __name__ == '__main__':
611 test_main(verbose=True)