4 from test
import test_support
5 from weakref
import proxy
9 def PythonPartial(func
, *args
, **keywords
):
10 'Pure Python approximation of partial()'
11 def newfunc(*fargs
, **fkeywords
):
12 newkeywords
= keywords
.copy()
13 newkeywords
.update(fkeywords
)
14 return func(*(args
+ fargs
), **newkeywords
)
17 newfunc
.keywords
= keywords
20 def capture(*args
, **kw
):
21 """capture all positional and keyword arguments"""
25 """ return the signature of a partial object """
26 return (part
.func
, part
.args
, part
.keywords
, part
.__dict
__)
28 class TestPartial(unittest
.TestCase
):
30 thetype
= functools
.partial
32 def test_basic_examples(self
):
33 p
= self
.thetype(capture
, 1, 2, a
=10, b
=20)
34 self
.assertEqual(p(3, 4, b
=30, c
=40),
35 ((1, 2, 3, 4), dict(a
=10, b
=30, c
=40)))
36 p
= self
.thetype(map, lambda x
: x
*10)
37 self
.assertEqual(p([1,2,3,4]), [10, 20, 30, 40])
39 def test_attributes(self
):
40 p
= self
.thetype(capture
, 1, 2, a
=10, b
=20)
41 # attributes should be readable
42 self
.assertEqual(p
.func
, capture
)
43 self
.assertEqual(p
.args
, (1, 2))
44 self
.assertEqual(p
.keywords
, dict(a
=10, b
=20))
45 # attributes should not be writable
46 if not isinstance(self
.thetype
, type):
48 self
.assertRaises(TypeError, setattr, p
, 'func', map)
49 self
.assertRaises(TypeError, setattr, p
, 'args', (1, 2))
50 self
.assertRaises(TypeError, setattr, p
, 'keywords', dict(a
=1, b
=2))
58 self
.fail('partial object allowed __dict__ to be deleted')
60 def test_argument_checking(self
):
61 self
.assertRaises(TypeError, self
.thetype
) # need at least a func arg
67 self
.fail('First arg not checked for callability')
69 def test_protection_of_callers_dict_argument(self
):
70 # a caller's dictionary should not be altered by partial
74 p
= self
.thetype(func
, a
=5)
75 self
.assertEqual(p(**d
), 3)
76 self
.assertEqual(d
, {'a':3})
78 self
.assertEqual(d
, {'a':3})
80 def test_arg_combinations(self
):
81 # exercise special code paths for zero args in either partial
82 # object or the caller
83 p
= self
.thetype(capture
)
84 self
.assertEqual(p(), ((), {}))
85 self
.assertEqual(p(1,2), ((1,2), {}))
86 p
= self
.thetype(capture
, 1, 2)
87 self
.assertEqual(p(), ((1,2), {}))
88 self
.assertEqual(p(3,4), ((1,2,3,4), {}))
90 def test_kw_combinations(self
):
91 # exercise special code paths for no keyword args in
92 # either the partial object or the caller
93 p
= self
.thetype(capture
)
94 self
.assertEqual(p(), ((), {}))
95 self
.assertEqual(p(a
=1), ((), {'a':1}))
96 p
= self
.thetype(capture
, a
=1)
97 self
.assertEqual(p(), ((), {'a':1}))
98 self
.assertEqual(p(b
=2), ((), {'a':1, 'b':2}))
99 # keyword args in the call override those in the partial object
100 self
.assertEqual(p(a
=3, b
=2), ((), {'a':3, 'b':2}))
102 def test_positional(self
):
103 # make sure positional arguments are captured correctly
104 for args
in [(), (0,), (0,1), (0,1,2), (0,1,2,3)]:
105 p
= self
.thetype(capture
, *args
)
106 expected
= args
+ ('x',)
108 self
.assertTrue(expected
== got
and empty
== {})
110 def test_keyword(self
):
111 # make sure keyword arguments are captured correctly
112 for a
in ['a', 0, None, 3.5]:
113 p
= self
.thetype(capture
, a
=a
)
114 expected
= {'a':a
,'x':None}
115 empty
, got
= p(x
=None)
116 self
.assertTrue(expected
== got
and empty
== ())
118 def test_no_side_effects(self
):
119 # make sure there are no side effects that affect subsequent calls
120 p
= self
.thetype(capture
, 0, a
=1)
121 args1
, kw1
= p(1, b
=2)
122 self
.assertTrue(args1
== (0,1) and kw1
== {'a':1,'b':2})
124 self
.assertTrue(args2
== (0,) and kw2
== {'a':1})
126 def test_error_propagation(self
):
129 self
.assertRaises(ZeroDivisionError, self
.thetype(f
, 1, 0))
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
, y
=0), 1)
134 def test_weakref(self
):
135 f
= self
.thetype(int, base
=16)
137 self
.assertEqual(f
.func
, p
.func
)
139 self
.assertRaises(ReferenceError, getattr, p
, 'func')
141 def test_with_bound_and_unbound_methods(self
):
142 data
= map(str, range(10))
143 join
= self
.thetype(str.join
, '')
144 self
.assertEqual(join(data
), '0123456789')
145 join
= self
.thetype(''.join
)
146 self
.assertEqual(join(data
), '0123456789')
148 def test_pickle(self
):
149 f
= self
.thetype(signature
, 'asdf', bar
=True)
150 f
.add_something_to__dict__
= True
151 f_copy
= pickle
.loads(pickle
.dumps(f
))
152 self
.assertEqual(signature(f
), signature(f_copy
))
154 class PartialSubclass(functools
.partial
):
157 class TestPartialSubclass(TestPartial
):
159 thetype
= PartialSubclass
161 class TestPythonPartial(TestPartial
):
163 thetype
= PythonPartial
165 # the python version isn't picklable
166 def test_pickle(self
): pass
168 class TestUpdateWrapper(unittest
.TestCase
):
170 def check_wrapper(self
, wrapper
, wrapped
,
171 assigned
=functools
.WRAPPER_ASSIGNMENTS
,
172 updated
=functools
.WRAPPER_UPDATES
):
173 # Check attributes were assigned
174 for name
in assigned
:
175 self
.assertTrue(getattr(wrapper
, name
) is getattr(wrapped
, name
))
176 # Check attributes were updated
178 wrapper_attr
= getattr(wrapper
, name
)
179 wrapped_attr
= getattr(wrapped
, name
)
180 for key
in wrapped_attr
:
181 self
.assertTrue(wrapped_attr
[key
] is wrapper_attr
[key
])
183 def _default_update(self
):
187 f
.attr
= 'This is also a test'
190 functools
.update_wrapper(wrapper
, f
)
193 def test_default_update(self
):
194 wrapper
, f
= self
._default
_update
()
195 self
.check_wrapper(wrapper
, f
)
196 self
.assertEqual(wrapper
.__name
__, 'f')
197 self
.assertEqual(wrapper
.attr
, 'This is also a test')
199 @unittest.skipIf(sys
.flags
.optimize
>= 2,
200 "Docstrings are omitted with -O2 and above")
201 def test_default_update_doc(self
):
202 wrapper
, f
= self
._default
_update
()
203 self
.assertEqual(wrapper
.__doc
__, 'This is a test')
205 def test_no_update(self
):
209 f
.attr
= 'This is also a test'
212 functools
.update_wrapper(wrapper
, f
, (), ())
213 self
.check_wrapper(wrapper
, f
, (), ())
214 self
.assertEqual(wrapper
.__name
__, 'wrapper')
215 self
.assertEqual(wrapper
.__doc
__, None)
216 self
.assertFalse(hasattr(wrapper
, 'attr'))
218 def test_selective_update(self
):
221 f
.attr
= 'This is a different test'
222 f
.dict_attr
= dict(a
=1, b
=2, c
=3)
225 wrapper
.dict_attr
= {}
227 update
= ('dict_attr',)
228 functools
.update_wrapper(wrapper
, f
, assign
, update
)
229 self
.check_wrapper(wrapper
, f
, assign
, update
)
230 self
.assertEqual(wrapper
.__name
__, 'wrapper')
231 self
.assertEqual(wrapper
.__doc
__, None)
232 self
.assertEqual(wrapper
.attr
, 'This is a different test')
233 self
.assertEqual(wrapper
.dict_attr
, f
.dict_attr
)
235 def test_builtin_update(self
):
236 # Test for bug #1576241
239 functools
.update_wrapper(wrapper
, max)
240 self
.assertEqual(wrapper
.__name
__, 'max')
241 self
.assertTrue(wrapper
.__doc
__.startswith('max('))
243 class TestWraps(TestUpdateWrapper
):
245 def _default_update(self
):
249 f
.attr
= 'This is also a test'
253 self
.check_wrapper(wrapper
, f
)
256 def test_default_update(self
):
257 wrapper
= self
._default
_update
()
258 self
.assertEqual(wrapper
.__name
__, 'f')
259 self
.assertEqual(wrapper
.attr
, 'This is also a test')
261 @unittest.skipIf(not sys
.flags
.optimize
<= 1,
262 "Docstrings are omitted with -O2 and above")
263 def test_default_update_doc(self
):
264 wrapper
= self
._default
_update
()
265 self
.assertEqual(wrapper
.__doc
__, 'This is a test')
267 def test_no_update(self
):
271 f
.attr
= 'This is also a test'
272 @functools.wraps(f
, (), ())
275 self
.check_wrapper(wrapper
, f
, (), ())
276 self
.assertEqual(wrapper
.__name
__, 'wrapper')
277 self
.assertEqual(wrapper
.__doc
__, None)
278 self
.assertFalse(hasattr(wrapper
, 'attr'))
280 def test_selective_update(self
):
283 f
.attr
= 'This is a different test'
284 f
.dict_attr
= dict(a
=1, b
=2, c
=3)
285 def add_dict_attr(f
):
289 update
= ('dict_attr',)
290 @functools.wraps(f
, assign
, update
)
294 self
.check_wrapper(wrapper
, f
, assign
, update
)
295 self
.assertEqual(wrapper
.__name
__, 'wrapper')
296 self
.assertEqual(wrapper
.__doc
__, None)
297 self
.assertEqual(wrapper
.attr
, 'This is a different test')
298 self
.assertEqual(wrapper
.dict_attr
, f
.dict_attr
)
301 class TestReduce(unittest
.TestCase
):
303 def test_reduce(self
):
306 def __init__(self
, max):
310 def __len__(self
): return len(self
.sofar
)
312 def __getitem__(self
, i
):
313 if not 0 <= i
< self
.max: raise IndexError
316 self
.sofar
.append(n
*n
)
320 reduce = functools
.reduce
321 self
.assertEqual(reduce(lambda x
, y
: x
+y
, ['a', 'b', 'c'], ''), 'abc')
323 reduce(lambda x
, y
: x
+y
, [['a', 'c'], [], ['d', 'w']], []),
326 self
.assertEqual(reduce(lambda x
, y
: x
*y
, range(2,8), 1), 5040)
328 reduce(lambda x
, y
: x
*y
, range(2,21), 1L),
331 self
.assertEqual(reduce(lambda x
, y
: x
+y
, Squares(10)), 285)
332 self
.assertEqual(reduce(lambda x
, y
: x
+y
, Squares(10), 0), 285)
333 self
.assertEqual(reduce(lambda x
, y
: x
+y
, Squares(0), 0), 0)
334 self
.assertRaises(TypeError, reduce)
335 self
.assertRaises(TypeError, reduce, 42, 42)
336 self
.assertRaises(TypeError, reduce, 42, 42, 42)
337 self
.assertEqual(reduce(42, "1"), "1") # func is never called with one item
338 self
.assertEqual(reduce(42, "", "1"), "1") # func is never called with one item
339 self
.assertRaises(TypeError, reduce, 42, (42, 42))
341 class TestCmpToKey(unittest
.TestCase
):
342 def test_cmp_to_key(self
):
345 self
.assertEqual(sorted(range(5), key
=functools
.cmp_to_key(mycmp
)),
351 key
= functools
.cmp_to_key(mycmp
)
353 self
.assertRaises(TypeError, hash(k
))
355 class TestTotalOrdering(unittest
.TestCase
):
357 def test_total_ordering_lt(self
):
358 @functools.total_ordering
360 def __init__(self
, value
):
362 def __lt__(self
, other
):
363 return self
.value
< other
.value
364 self
.assert_(A(1) < A(2))
365 self
.assert_(A(2) > A(1))
366 self
.assert_(A(1) <= A(2))
367 self
.assert_(A(2) >= A(1))
368 self
.assert_(A(2) <= A(2))
369 self
.assert_(A(2) >= A(2))
371 def test_total_ordering_le(self
):
372 @functools.total_ordering
374 def __init__(self
, value
):
376 def __le__(self
, other
):
377 return self
.value
<= other
.value
378 self
.assert_(A(1) < A(2))
379 self
.assert_(A(2) > A(1))
380 self
.assert_(A(1) <= A(2))
381 self
.assert_(A(2) >= A(1))
382 self
.assert_(A(2) <= A(2))
383 self
.assert_(A(2) >= A(2))
385 def test_total_ordering_gt(self
):
386 @functools.total_ordering
388 def __init__(self
, value
):
390 def __gt__(self
, other
):
391 return self
.value
> other
.value
392 self
.assert_(A(1) < A(2))
393 self
.assert_(A(2) > A(1))
394 self
.assert_(A(1) <= A(2))
395 self
.assert_(A(2) >= A(1))
396 self
.assert_(A(2) <= A(2))
397 self
.assert_(A(2) >= A(2))
399 def test_total_ordering_ge(self
):
400 @functools.total_ordering
402 def __init__(self
, value
):
404 def __ge__(self
, other
):
405 return self
.value
>= other
.value
406 self
.assert_(A(1) < A(2))
407 self
.assert_(A(2) > A(1))
408 self
.assert_(A(1) <= A(2))
409 self
.assert_(A(2) >= A(1))
410 self
.assert_(A(2) <= A(2))
411 self
.assert_(A(2) >= A(2))
413 def test_total_ordering_no_overwrite(self
):
414 # new methods should not overwrite existing
415 @functools.total_ordering
418 self
.assert_(A(1) < A(2))
419 self
.assert_(A(2) > A(1))
420 self
.assert_(A(1) <= A(2))
421 self
.assert_(A(2) >= A(1))
422 self
.assert_(A(2) <= A(2))
423 self
.assert_(A(2) >= A(2))
425 def test_no_operations_defined(self
):
426 with self
.assertRaises(ValueError):
427 @functools.total_ordering
431 def test_main(verbose
=None):
440 test_support
.run_unittest(*test_classes
)
442 # verify reference counting
443 if verbose
and hasattr(sys
, "gettotalrefcount"):
446 for i
in xrange(len(counts
)):
447 test_support
.run_unittest(*test_classes
)
449 counts
[i
] = sys
.gettotalrefcount()
452 if __name__
== '__main__':
453 test_main(verbose
=True)