diff options
author | Yury Selivanov <yselivanov@sprymix.com> | 2014-03-27 16:09:24 (GMT) |
---|---|---|
committer | Yury Selivanov <yselivanov@sprymix.com> | 2014-03-27 16:09:24 (GMT) |
commit | da39645ad300a097decc4e35bb3ea6dbf0633886 (patch) | |
tree | 07ccb20f627b8c26a84851df3ebe035d9f0a401c /Lib/inspect.py | |
parent | a5d63dd7b880dd38282ad52f52e3579f965b20e0 (diff) | |
download | cpython-da39645ad300a097decc4e35bb3ea6dbf0633886.zip cpython-da39645ad300a097decc4e35bb3ea6dbf0633886.tar.gz cpython-da39645ad300a097decc4e35bb3ea6dbf0633886.tar.bz2 |
inspect.Signature: Add 'Signature.from_callable' classmethod. Closes #17373
Diffstat (limited to 'Lib/inspect.py')
-rw-r--r-- | Lib/inspect.py | 86 |
1 files changed, 56 insertions, 30 deletions
diff --git a/Lib/inspect.py b/Lib/inspect.py index bce0516..acb8071 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -969,7 +969,8 @@ def getfullargspec(func): sig = _signature_internal(func, follow_wrapper_chains=False, - skip_bound_arg=False) + skip_bound_arg=False, + sigcls=Signature) except Exception as ex: # Most of the times 'signature' will raise ValueError. # But, it can also raise AttributeError, and, maybe something @@ -1861,7 +1862,10 @@ def _signature_from_builtin(cls, func, skip_bound_arg=True): return _signature_fromstr(cls, func, s, skip_bound_arg) -def _signature_internal(obj, follow_wrapper_chains=True, skip_bound_arg=True): +def _signature_internal(obj, *, + follow_wrapper_chains=True, + skip_bound_arg=True, + sigcls): if not callable(obj): raise TypeError('{!r} is not a callable object'.format(obj)) @@ -1869,9 +1873,12 @@ def _signature_internal(obj, follow_wrapper_chains=True, skip_bound_arg=True): if isinstance(obj, types.MethodType): # In this case we skip the first parameter of the underlying # function (usually `self` or `cls`). - sig = _signature_internal(obj.__func__, - follow_wrapper_chains, - skip_bound_arg) + sig = _signature_internal( + obj.__func__, + follow_wrapper_chains=follow_wrapper_chains, + skip_bound_arg=skip_bound_arg, + sigcls=sigcls) + if skip_bound_arg: return _signature_bound_method(sig) else: @@ -1902,9 +1909,12 @@ def _signature_internal(obj, follow_wrapper_chains=True, skip_bound_arg=True): # (usually `self`, or `cls`) will not be passed # automatically (as for boundmethods) - wrapped_sig = _signature_internal(partialmethod.func, - follow_wrapper_chains, - skip_bound_arg) + wrapped_sig = _signature_internal( + partialmethod.func, + follow_wrapper_chains=follow_wrapper_chains, + skip_bound_arg=skip_bound_arg, + sigcls=sigcls) + sig = _signature_get_partial(wrapped_sig, partialmethod, (None,)) first_wrapped_param = tuple(wrapped_sig.parameters.values())[0] @@ -1915,16 +1925,18 @@ def _signature_internal(obj, follow_wrapper_chains=True, skip_bound_arg=True): if isfunction(obj) or _signature_is_functionlike(obj): # If it's a pure Python function, or an object that is duck type # of a Python function (Cython functions, for instance), then: - return Signature.from_function(obj) + return sigcls.from_function(obj) if _signature_is_builtin(obj): - return _signature_from_builtin(Signature, obj, + return _signature_from_builtin(sigcls, obj, skip_bound_arg=skip_bound_arg) if isinstance(obj, functools.partial): - wrapped_sig = _signature_internal(obj.func, - follow_wrapper_chains, - skip_bound_arg) + wrapped_sig = _signature_internal( + obj.func, + follow_wrapper_chains=follow_wrapper_chains, + skip_bound_arg=skip_bound_arg, + sigcls=sigcls) return _signature_get_partial(wrapped_sig, obj) sig = None @@ -1935,23 +1947,29 @@ def _signature_internal(obj, follow_wrapper_chains=True, skip_bound_arg=True): # in its metaclass call = _signature_get_user_defined_method(type(obj), '__call__') if call is not None: - sig = _signature_internal(call, - follow_wrapper_chains, - skip_bound_arg) + sig = _signature_internal( + call, + follow_wrapper_chains=follow_wrapper_chains, + skip_bound_arg=skip_bound_arg, + sigcls=sigcls) else: # Now we check if the 'obj' class has a '__new__' method new = _signature_get_user_defined_method(obj, '__new__') if new is not None: - sig = _signature_internal(new, - follow_wrapper_chains, - skip_bound_arg) + sig = _signature_internal( + new, + follow_wrapper_chains=follow_wrapper_chains, + skip_bound_arg=skip_bound_arg, + sigcls=sigcls) else: # Finally, we should have at least __init__ implemented init = _signature_get_user_defined_method(obj, '__init__') if init is not None: - sig = _signature_internal(init, - follow_wrapper_chains, - skip_bound_arg) + sig = _signature_internal( + init, + follow_wrapper_chains=follow_wrapper_chains, + skip_bound_arg=skip_bound_arg, + sigcls=sigcls) if sig is None: # At this point we know, that `obj` is a class, with no user- @@ -1973,7 +1991,7 @@ def _signature_internal(obj, follow_wrapper_chains=True, skip_bound_arg=True): if text_sig: # If 'obj' class has a __text_signature__ attribute: # return a signature based on it - return _signature_fromstr(Signature, obj, text_sig) + return _signature_fromstr(sigcls, obj, text_sig) # No '__text_signature__' was found for the 'obj' class. # Last option is to check if its '__init__' is @@ -1993,9 +2011,11 @@ def _signature_internal(obj, follow_wrapper_chains=True, skip_bound_arg=True): call = _signature_get_user_defined_method(type(obj), '__call__') if call is not None: try: - sig = _signature_internal(call, - follow_wrapper_chains, - skip_bound_arg) + sig = _signature_internal( + call, + follow_wrapper_chains=follow_wrapper_chains, + skip_bound_arg=skip_bound_arg, + sigcls=sigcls) except ValueError as ex: msg = 'no signature found for {!r}'.format(obj) raise ValueError(msg) from ex @@ -2015,10 +2035,6 @@ def _signature_internal(obj, follow_wrapper_chains=True, skip_bound_arg=True): raise ValueError('callable {!r} is not supported by signature'.format(obj)) -def signature(obj): - '''Get a signature object for the passed callable.''' - return _signature_internal(obj) - class _void: '''A private marker - used in Parameter & Signature''' @@ -2464,6 +2480,10 @@ class Signature: def from_builtin(cls, func): return _signature_from_builtin(cls, func) + @classmethod + def from_callable(cls, obj): + return _signature_internal(obj, sigcls=cls) + @property def parameters(self): return self._parameters @@ -2723,6 +2743,12 @@ class Signature: return rendered + +def signature(obj): + '''Get a signature object for the passed callable.''' + return Signature.from_callable(obj) + + def _main(): """ Logic for inspecting an object given at command line """ import argparse |