@@ -1901,7 +1901,7 @@ def getasyncgenlocals(agen):
19011901 types .BuiltinFunctionType )
19021902
19031903
1904- def _signature_get_user_defined_method (cls , method_name ):
1904+ def _signature_get_user_defined_method (cls , method_name , * , follow_wrapper_chains = True ):
19051905 """Private helper. Checks if ``cls`` has an attribute
19061906 named ``method_name`` and returns it only if it is a
19071907 pure python function.
@@ -1910,12 +1910,20 @@ def _signature_get_user_defined_method(cls, method_name):
19101910 meth = getattr (cls , method_name , None )
19111911 else :
19121912 meth = getattr_static (cls , method_name , None )
1913- if meth is None or isinstance (meth , _NonUserDefinedCallables ):
1913+ if meth is None :
1914+ return None
1915+
1916+ if follow_wrapper_chains :
1917+ meth = unwrap (meth , stop = (lambda m : hasattr (m , "__signature__" )
1918+ or _signature_is_builtin (m )))
1919+ if isinstance (meth , _NonUserDefinedCallables ):
19141920 # Once '__signature__' will be added to 'C'-level
19151921 # callables, this check won't be necessary
19161922 return None
19171923 if method_name != '__new__' :
19181924 meth = _descriptor_get (meth , cls )
1925+ if follow_wrapper_chains :
1926+ meth = unwrap (meth , stop = lambda m : hasattr (m , "__signature__" ))
19191927 return meth
19201928
19211929
@@ -2507,12 +2515,26 @@ def _signature_from_callable(obj, *,
25072515
25082516 # First, let's see if it has an overloaded __call__ defined
25092517 # in its metaclass
2510- call = _signature_get_user_defined_method (type (obj ), '__call__' )
2518+ call = _signature_get_user_defined_method (
2519+ type (obj ),
2520+ '__call__' ,
2521+ follow_wrapper_chains = follow_wrapper_chains ,
2522+ )
25112523 if call is not None :
25122524 return _get_signature_of (call )
25132525
2514- new = _signature_get_user_defined_method (obj , '__new__' )
2515- init = _signature_get_user_defined_method (obj , '__init__' )
2526+ # NOTE: The user-defined method can be a function with a thin wrapper
2527+ # around object.__new__ (e.g., generated by `@warnings.deprecated`)
2528+ new = _signature_get_user_defined_method (
2529+ obj ,
2530+ '__new__' ,
2531+ follow_wrapper_chains = follow_wrapper_chains ,
2532+ )
2533+ init = _signature_get_user_defined_method (
2534+ obj ,
2535+ '__init__' ,
2536+ follow_wrapper_chains = follow_wrapper_chains ,
2537+ )
25162538
25172539 # Go through the MRO and see if any class has user-defined
25182540 # pure Python __new__ or __init__ method
@@ -2552,10 +2574,14 @@ def _signature_from_callable(obj, *,
25522574 # Last option is to check if its '__init__' is
25532575 # object.__init__ or type.__init__.
25542576 if type not in obj .__mro__ :
2577+ obj_init = obj .__init__
2578+ obj_new = obj .__new__
2579+ if follow_wrapper_chains :
2580+ obj_init = unwrap (obj_init )
2581+ obj_new = unwrap (obj_new )
25552582 # We have a class (not metaclass), but no user-defined
25562583 # __init__ or __new__ for it
2557- if (obj .__init__ is object .__init__ and
2558- obj .__new__ is object .__new__ ):
2584+ if obj_init is object .__init__ and obj_new is object .__new__ :
25592585 # Return a signature of 'object' builtin.
25602586 return sigcls .from_callable (object )
25612587 else :
0 commit comments