3 from test
import test_support
4 from weakref
import proxy
8 def PythonPartial(func
, *args
, **keywords
):
9 'Pure Python approximation of partial()'
10 def newfunc(*fargs
, **fkeywords
):
11 newkeywords
= keywords
.copy()
12 newkeywords
.update(fkeywords
)
13 return func(*(args
+ fargs
), **newkeywords
)
16 newfunc
.keywords
= keywords
19 def capture(*args
, **kw
):
20 """capture all positional and keyword arguments"""
24 """ return the signature of a partial object """
25 return (part
.func
, part
.args
, part
.keywords
, part
.__dict
__)
27 class TestPartial(unittest
.TestCase
):
29 thetype
= functools
.partial
31 def test_basic_examples(self
):
32 p
= self
.thetype(capture
, 1, 2, a
=10, b
=20)
33 self
.assertEqual(p(3, 4, b
=30, c
=40),
34 ((1, 2, 3, 4), dict(a
=10, b
=30, c
=40)))
35 p
= self
.thetype(map, lambda x
: x
*10)
36 self
.assertEqual(p([1,2,3,4]), [10, 20, 30, 40])
38 def test_attributes(self
):
39 p
= self
.thetype(capture
, 1, 2, a
=10, b
=20)
40 # attributes should be readable
41 self
.assertEqual(p
.func
, capture
)
42 self
.assertEqual(p
.args
, (1, 2))
43 self
.assertEqual(p
.keywords
, dict(a
=10, b
=20))
44 # attributes should not be writable
45 if not isinstance(self
.thetype
, type):
47 self
.assertRaises(TypeError, setattr, p
, 'func', map)
48 self
.assertRaises(TypeError, setattr, p
, 'args', (1, 2))
49 self
.assertRaises(TypeError, setattr, p
, 'keywords', dict(a
=1, b
=2))
51 def test_argument_checking(self
):
52 self
.assertRaises(TypeError, self
.thetype
) # need at least a func arg
58 self
.fail('First arg not checked for callability')
60 def test_protection_of_callers_dict_argument(self
):
61 # a caller's dictionary should not be altered by partial
65 p
= self
.thetype(func
, a
=5)
66 self
.assertEqual(p(**d
), 3)
67 self
.assertEqual(d
, {'a':3})
69 self
.assertEqual(d
, {'a':3})
71 def test_arg_combinations(self
):
72 # exercise special code paths for zero args in either partial
73 # object or the caller
74 p
= self
.thetype(capture
)
75 self
.assertEqual(p(), ((), {}))
76 self
.assertEqual(p(1,2), ((1,2), {}))
77 p
= self
.thetype(capture
, 1, 2)
78 self
.assertEqual(p(), ((1,2), {}))
79 self
.assertEqual(p(3,4), ((1,2,3,4), {}))
81 def test_kw_combinations(self
):
82 # exercise special code paths for no keyword args in
83 # either the partial object or the caller
84 p
= self
.thetype(capture
)
85 self
.assertEqual(p(), ((), {}))
86 self
.assertEqual(p(a
=1), ((), {'a':1}))
87 p
= self
.thetype(capture
, a
=1)
88 self
.assertEqual(p(), ((), {'a':1}))
89 self
.assertEqual(p(b
=2), ((), {'a':1, 'b':2}))
90 # keyword args in the call override those in the partial object
91 self
.assertEqual(p(a
=3, b
=2), ((), {'a':3, 'b':2}))
93 def test_positional(self
):
94 # make sure positional arguments are captured correctly
95 for args
in [(), (0,), (0,1), (0,1,2), (0,1,2,3)]:
96 p
= self
.thetype(capture
, *args
)
97 expected
= args
+ ('x',)
99 self
.assertTrue(expected
== got
and empty
== {})
101 def test_keyword(self
):
102 # make sure keyword arguments are captured correctly
103 for a
in ['a', 0, None, 3.5]:
104 p
= self
.thetype(capture
, a
=a
)
105 expected
= {'a':a
,'x':None}
106 empty
, got
= p(x
=None)
107 self
.assertTrue(expected
== got
and empty
== ())
109 def test_no_side_effects(self
):
110 # make sure there are no side effects that affect subsequent calls
111 p
= self
.thetype(capture
, 0, a
=1)
112 args1
, kw1
= p(1, b
=2)
113 self
.assertTrue(args1
== (0,1) and kw1
== {'a':1,'b':2})
115 self
.assertTrue(args2
== (0,) and kw2
== {'a':1})
117 def test_error_propagation(self
):
120 self
.assertRaises(ZeroDivisionError, self
.thetype(f
, 1, 0))
121 self
.assertRaises(ZeroDivisionError, self
.thetype(f
, 1), 0)
122 self
.assertRaises(ZeroDivisionError, self
.thetype(f
), 1, 0)
123 self
.assertRaises(ZeroDivisionError, self
.thetype(f
, y
=0), 1)
125 def test_attributes(self
):
126 p
= self
.thetype(hex)
132 self
.fail('partial object allowed __dict__ to be deleted')
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 test_default_update(self
):
187 f
.attr
= 'This is also a test'
190 functools
.update_wrapper(wrapper
, f
)
191 self
.check_wrapper(wrapper
, f
)
192 self
.assertEqual(wrapper
.__name
__, 'f')
193 self
.assertEqual(wrapper
.__doc
__, 'This is a test')
194 self
.assertEqual(wrapper
.attr
, 'This is also a test')
196 def test_no_update(self
):
200 f
.attr
= 'This is also a test'
203 functools
.update_wrapper(wrapper
, f
, (), ())
204 self
.check_wrapper(wrapper
, f
, (), ())
205 self
.assertEqual(wrapper
.__name
__, 'wrapper')
206 self
.assertEqual(wrapper
.__doc
__, None)
207 self
.assertFalse(hasattr(wrapper
, 'attr'))
209 def test_selective_update(self
):
212 f
.attr
= 'This is a different test'
213 f
.dict_attr
= dict(a
=1, b
=2, c
=3)
216 wrapper
.dict_attr
= {}
218 update
= ('dict_attr',)
219 functools
.update_wrapper(wrapper
, f
, assign
, update
)
220 self
.check_wrapper(wrapper
, f
, assign
, update
)
221 self
.assertEqual(wrapper
.__name
__, 'wrapper')
222 self
.assertEqual(wrapper
.__doc
__, None)
223 self
.assertEqual(wrapper
.attr
, 'This is a different test')
224 self
.assertEqual(wrapper
.dict_attr
, f
.dict_attr
)
226 def test_builtin_update(self
):
227 # Test for bug #1576241
230 functools
.update_wrapper(wrapper
, max)
231 self
.assertEqual(wrapper
.__name
__, 'max')
232 self
.assertTrue(wrapper
.__doc
__.startswith('max('))
234 class TestWraps(TestUpdateWrapper
):
236 def test_default_update(self
):
240 f
.attr
= 'This is also a test'
244 self
.check_wrapper(wrapper
, f
)
245 self
.assertEqual(wrapper
.__name
__, 'f')
246 self
.assertEqual(wrapper
.__doc
__, 'This is a test')
247 self
.assertEqual(wrapper
.attr
, 'This is also a test')
249 def test_no_update(self
):
253 f
.attr
= 'This is also a test'
254 @functools.wraps(f
, (), ())
257 self
.check_wrapper(wrapper
, f
, (), ())
258 self
.assertEqual(wrapper
.__name
__, 'wrapper')
259 self
.assertEqual(wrapper
.__doc
__, None)
260 self
.assertFalse(hasattr(wrapper
, 'attr'))
262 def test_selective_update(self
):
265 f
.attr
= 'This is a different test'
266 f
.dict_attr
= dict(a
=1, b
=2, c
=3)
267 def add_dict_attr(f
):
271 update
= ('dict_attr',)
272 @functools.wraps(f
, assign
, update
)
276 self
.check_wrapper(wrapper
, f
, assign
, update
)
277 self
.assertEqual(wrapper
.__name
__, 'wrapper')
278 self
.assertEqual(wrapper
.__doc
__, None)
279 self
.assertEqual(wrapper
.attr
, 'This is a different test')
280 self
.assertEqual(wrapper
.dict_attr
, f
.dict_attr
)
283 class TestReduce(unittest
.TestCase
):
285 def test_reduce(self
):
288 def __init__(self
, max):
292 def __len__(self
): return len(self
.sofar
)
294 def __getitem__(self
, i
):
295 if not 0 <= i
< self
.max: raise IndexError
298 self
.sofar
.append(n
*n
)
302 reduce = functools
.reduce
303 self
.assertEqual(reduce(lambda x
, y
: x
+y
, ['a', 'b', 'c'], ''), 'abc')
305 reduce(lambda x
, y
: x
+y
, [['a', 'c'], [], ['d', 'w']], []),
308 self
.assertEqual(reduce(lambda x
, y
: x
*y
, range(2,8), 1), 5040)
310 reduce(lambda x
, y
: x
*y
, range(2,21), 1L),
313 self
.assertEqual(reduce(lambda x
, y
: x
+y
, Squares(10)), 285)
314 self
.assertEqual(reduce(lambda x
, y
: x
+y
, Squares(10), 0), 285)
315 self
.assertEqual(reduce(lambda x
, y
: x
+y
, Squares(0), 0), 0)
316 self
.assertRaises(TypeError, reduce)
317 self
.assertRaises(TypeError, reduce, 42, 42)
318 self
.assertRaises(TypeError, reduce, 42, 42, 42)
319 self
.assertEqual(reduce(42, "1"), "1") # func is never called with one item
320 self
.assertEqual(reduce(42, "", "1"), "1") # func is never called with one item
321 self
.assertRaises(TypeError, reduce, 42, (42, 42))
326 def test_main(verbose
=None):
336 test_support
.run_unittest(*test_classes
)
338 # verify reference counting
339 if verbose
and hasattr(sys
, "gettotalrefcount"):
342 for i
in xrange(len(counts
)):
343 test_support
.run_unittest(*test_classes
)
345 counts
[i
] = sys
.gettotalrefcount()
348 if __name__
== '__main__':
349 test_main(verbose
=True)