99
1010import inspect
1111import weakref
12- from functools import wraps
12+ from functools import wraps , partial
1313from threading import Event
1414from collections import deque
1515from time import time
@@ -255,7 +255,16 @@ def _wrap_callback(self, fn):
255255 return None
256256 elif not callable (fn ):
257257 raise BadEventHandler ('value must be None or a callable' )
258- elif inspect .isbuiltin (fn ):
258+ # If fn is wrapped with partial (i.e. partial, partialmethod, or wraps
259+ # has been used to produce it) we need to dig out the "real" function
260+ # that's been wrapped along with all the mandatory positional args
261+ # used in the wrapper so we can test the binding
262+ args = ()
263+ wrapped_fn = fn
264+ while isinstance (wrapped_fn , partial ):
265+ args = wrapped_fn .args + args
266+ wrapped_fn = wrapped_fn .func
267+ if inspect .isbuiltin (wrapped_fn ):
259268 # We can't introspect the prototype of builtins. In this case we
260269 # assume that the builtin has no (mandatory) parameters; this is
261270 # the most reasonable assumption on the basis that pre-existing
@@ -267,13 +276,13 @@ def _wrap_callback(self, fn):
267276 # If this works, assume the function is capable of accepting no
268277 # parameters
269278 try :
270- inspect .getcallargs (fn )
279+ inspect .getcallargs (wrapped_fn , * args )
271280 return fn
272281 except TypeError :
273282 try :
274283 # If the above fails, try binding with a single parameter
275284 # (ourselves). If this works, wrap the specified callback
276- inspect .getcallargs (fn , self )
285+ inspect .getcallargs (wrapped_fn , * ( args + ( self ,)) )
277286 @wraps (fn )
278287 def wrapper ():
279288 return fn (self )
0 commit comments