mirror of
https://github.com/python/cpython.git
synced 2025-08-04 08:59:19 +00:00
gh-119605: Respect follow_wrapped
for __init__
and __new__
when getting class signature with inspect.signature
(#132055)
This commit is contained in:
parent
c14134020f
commit
b8633f9aca
4 changed files with 136 additions and 8 deletions
|
@ -1901,7 +1901,7 @@ _NonUserDefinedCallables = (types.WrapperDescriptorType,
|
|||
types.BuiltinFunctionType)
|
||||
|
||||
|
||||
def _signature_get_user_defined_method(cls, method_name):
|
||||
def _signature_get_user_defined_method(cls, method_name, *, follow_wrapper_chains=True):
|
||||
"""Private helper. Checks if ``cls`` has an attribute
|
||||
named ``method_name`` and returns it only if it is a
|
||||
pure python function.
|
||||
|
@ -1910,12 +1910,20 @@ def _signature_get_user_defined_method(cls, method_name):
|
|||
meth = getattr(cls, method_name, None)
|
||||
else:
|
||||
meth = getattr_static(cls, method_name, None)
|
||||
if meth is None or isinstance(meth, _NonUserDefinedCallables):
|
||||
if meth is None:
|
||||
return None
|
||||
|
||||
if follow_wrapper_chains:
|
||||
meth = unwrap(meth, stop=(lambda m: hasattr(m, "__signature__")
|
||||
or _signature_is_builtin(m)))
|
||||
if isinstance(meth, _NonUserDefinedCallables):
|
||||
# Once '__signature__' will be added to 'C'-level
|
||||
# callables, this check won't be necessary
|
||||
return None
|
||||
if method_name != '__new__':
|
||||
meth = _descriptor_get(meth, cls)
|
||||
if follow_wrapper_chains:
|
||||
meth = unwrap(meth, stop=lambda m: hasattr(m, "__signature__"))
|
||||
return meth
|
||||
|
||||
|
||||
|
@ -2507,12 +2515,26 @@ def _signature_from_callable(obj, *,
|
|||
|
||||
# First, let's see if it has an overloaded __call__ defined
|
||||
# in its metaclass
|
||||
call = _signature_get_user_defined_method(type(obj), '__call__')
|
||||
call = _signature_get_user_defined_method(
|
||||
type(obj),
|
||||
'__call__',
|
||||
follow_wrapper_chains=follow_wrapper_chains,
|
||||
)
|
||||
if call is not None:
|
||||
return _get_signature_of(call)
|
||||
|
||||
new = _signature_get_user_defined_method(obj, '__new__')
|
||||
init = _signature_get_user_defined_method(obj, '__init__')
|
||||
# NOTE: The user-defined method can be a function with a thin wrapper
|
||||
# around object.__new__ (e.g., generated by `@warnings.deprecated`)
|
||||
new = _signature_get_user_defined_method(
|
||||
obj,
|
||||
'__new__',
|
||||
follow_wrapper_chains=follow_wrapper_chains,
|
||||
)
|
||||
init = _signature_get_user_defined_method(
|
||||
obj,
|
||||
'__init__',
|
||||
follow_wrapper_chains=follow_wrapper_chains,
|
||||
)
|
||||
|
||||
# Go through the MRO and see if any class has user-defined
|
||||
# pure Python __new__ or __init__ method
|
||||
|
@ -2552,10 +2574,14 @@ def _signature_from_callable(obj, *,
|
|||
# Last option is to check if its '__init__' is
|
||||
# object.__init__ or type.__init__.
|
||||
if type not in obj.__mro__:
|
||||
obj_init = obj.__init__
|
||||
obj_new = obj.__new__
|
||||
if follow_wrapper_chains:
|
||||
obj_init = unwrap(obj_init)
|
||||
obj_new = unwrap(obj_new)
|
||||
# We have a class (not metaclass), but no user-defined
|
||||
# __init__ or __new__ for it
|
||||
if (obj.__init__ is object.__init__ and
|
||||
obj.__new__ is object.__new__):
|
||||
if obj_init is object.__init__ and obj_new is object.__new__:
|
||||
# Return a signature of 'object' builtin.
|
||||
return sigcls.from_callable(object)
|
||||
else:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue