diff options
author | Jason R. Coombs <jaraco@jaraco.com> | 2020-12-27 12:46:59 -0500 |
---|---|---|
committer | Jason R. Coombs <jaraco@jaraco.com> | 2020-12-27 12:46:59 -0500 |
commit | a78f0158a28734f965218b834ea8c0b166b7353f (patch) | |
tree | dca70268e2a41d49658e7eed783c6fc243d119cd /Lib/inspect.py | |
parent | ec8e6895a3ce9cd69b6ceb75a15fcc74d4a522dc (diff) | |
parent | bf64d9064ab641b1ef9a0c4bda097ebf1204faf4 (diff) | |
download | cpython-git-revert-23107-revert-13893-fix-issue-37193.tar.gz |
Merge branch 'master' into revert-23107-revert-13893-fix-issue-37193revert-23107-revert-13893-fix-issue-37193
Diffstat (limited to 'Lib/inspect.py')
-rw-r--r-- | Lib/inspect.py | 101 |
1 files changed, 49 insertions, 52 deletions
diff --git a/Lib/inspect.py b/Lib/inspect.py index ac127cbd72..70c5ef7bb6 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -707,10 +707,13 @@ def getsourcefile(object): if os.path.exists(filename): return filename # only return a non-existent filename if the module has a PEP 302 loader - if getattr(getmodule(object, filename), '__loader__', None) is not None: + module = getmodule(object, filename) + if getattr(module, '__loader__', None) is not None: + return filename + elif getattr(getattr(module, "__spec__", None), "loader", None) is not None: return filename # or it is in the linecache - if filename in linecache.cache: + elif filename in linecache.cache: return filename def getabsfile(object, _filename=None): @@ -865,7 +868,12 @@ def findsource(object): lnum = object.co_firstlineno - 1 pat = re.compile(r'^(\s*def\s)|(\s*async\s+def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)') while lnum > 0: - if pat.match(lines[lnum]): break + try: + line = lines[lnum] + except IndexError: + raise OSError('lineno is out of bounds') + if pat.match(line): + break lnum = lnum - 1 return lines, lnum raise OSError('could not find code object') @@ -927,6 +935,7 @@ class BlockFinder: self.indecorator = False self.decoratorhasargs = False self.last = 1 + self.body_col0 = None def tokeneater(self, type, token, srowcol, erowcol, line): if not self.started and not self.indecorator: @@ -958,6 +967,8 @@ class BlockFinder: elif self.passline: pass elif type == tokenize.INDENT: + if self.body_col0 is None and self.started: + self.body_col0 = erowcol[1] self.indent = self.indent + 1 self.passline = True elif type == tokenize.DEDENT: @@ -967,6 +978,10 @@ class BlockFinder: # not e.g. for "if: else:" or "try: finally:" blocks) if self.indent <= 0: raise EndOfBlock + elif type == tokenize.COMMENT: + if self.body_col0 is not None and srowcol[1] >= self.body_col0: + # Include comments if indented at least as much as the block + self.last = srowcol[0] elif self.indent == 0 and type not in (tokenize.COMMENT, tokenize.NL): # any other token on the same indentation level end the previous # block as well, except the pseudo-tokens COMMENT and NL. @@ -2122,9 +2137,9 @@ def _signature_fromstr(cls, obj, s, skip_bound_arg=True): return cls(parameters, return_annotation=cls.empty) -def _get_type_hints(func): +def _get_type_hints(func, **kwargs): try: - return typing.get_type_hints(func) + return typing.get_type_hints(func, **kwargs) except Exception: # First, try to use the get_type_hints to resolve # annotations. But for keeping the behavior intact @@ -2149,7 +2164,8 @@ def _signature_from_builtin(cls, func, skip_bound_arg=True): return _signature_fromstr(cls, func, s, skip_bound_arg) -def _signature_from_function(cls, func, skip_bound_arg=True): +def _signature_from_function(cls, func, skip_bound_arg=True, + globalns=None, localns=None): """Private helper: constructs Signature for the given python function.""" is_duck_function = False @@ -2175,7 +2191,7 @@ def _signature_from_function(cls, func, skip_bound_arg=True): positional = arg_names[:pos_count] keyword_only_count = func_code.co_kwonlyargcount keyword_only = arg_names[pos_count:pos_count + keyword_only_count] - annotations = _get_type_hints(func) + annotations = _get_type_hints(func, globalns=globalns, localns=localns) defaults = func.__defaults__ kwdefaults = func.__kwdefaults__ @@ -2247,23 +2263,28 @@ def _signature_from_function(cls, func, skip_bound_arg=True): def _signature_from_callable(obj, *, follow_wrapper_chains=True, skip_bound_arg=True, + globalns=None, + localns=None, sigcls): """Private helper function to get signature for arbitrary callable objects. """ + _get_signature_of = functools.partial(_signature_from_callable, + follow_wrapper_chains=follow_wrapper_chains, + skip_bound_arg=skip_bound_arg, + globalns=globalns, + localns=localns, + sigcls=sigcls) + if not callable(obj): raise TypeError('{!r} is not a callable object'.format(obj)) if isinstance(obj, types.MethodType): # In this case we skip the first parameter of the underlying # function (usually `self` or `cls`). - sig = _signature_from_callable( - obj.__func__, - follow_wrapper_chains=follow_wrapper_chains, - skip_bound_arg=skip_bound_arg, - sigcls=sigcls) + sig = _get_signature_of(obj.__func__) if skip_bound_arg: return _signature_bound_method(sig) @@ -2277,11 +2298,7 @@ def _signature_from_callable(obj, *, # If the unwrapped object is a *method*, we might want to # skip its first parameter (self). # See test_signature_wrapped_bound_method for details. - return _signature_from_callable( - obj, - follow_wrapper_chains=follow_wrapper_chains, - skip_bound_arg=skip_bound_arg, - sigcls=sigcls) + return _get_signature_of(obj) try: sig = obj.__signature__ @@ -2308,11 +2325,7 @@ def _signature_from_callable(obj, *, # (usually `self`, or `cls`) will not be passed # automatically (as for boundmethods) - wrapped_sig = _signature_from_callable( - partialmethod.func, - follow_wrapper_chains=follow_wrapper_chains, - skip_bound_arg=skip_bound_arg, - sigcls=sigcls) + wrapped_sig = _get_signature_of(partialmethod.func) sig = _signature_get_partial(wrapped_sig, partialmethod, (None,)) first_wrapped_param = tuple(wrapped_sig.parameters.values())[0] @@ -2331,18 +2344,15 @@ def _signature_from_callable(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(sigcls, obj, - skip_bound_arg=skip_bound_arg) + skip_bound_arg=skip_bound_arg, + globalns=globalns, localns=localns) if _signature_is_builtin(obj): return _signature_from_builtin(sigcls, obj, skip_bound_arg=skip_bound_arg) if isinstance(obj, functools.partial): - wrapped_sig = _signature_from_callable( - obj.func, - follow_wrapper_chains=follow_wrapper_chains, - skip_bound_arg=skip_bound_arg, - sigcls=sigcls) + wrapped_sig = _get_signature_of(obj.func) return _signature_get_partial(wrapped_sig, obj) sig = None @@ -2353,29 +2363,17 @@ def _signature_from_callable(obj, *, # in its metaclass call = _signature_get_user_defined_method(type(obj), '__call__') if call is not None: - sig = _signature_from_callable( - call, - follow_wrapper_chains=follow_wrapper_chains, - skip_bound_arg=skip_bound_arg, - sigcls=sigcls) + sig = _get_signature_of(call) 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_from_callable( - new, - follow_wrapper_chains=follow_wrapper_chains, - skip_bound_arg=skip_bound_arg, - sigcls=sigcls) + sig = _get_signature_of(new) else: # Finally, we should have at least __init__ implemented init = _signature_get_user_defined_method(obj, '__init__') if init is not None: - sig = _signature_from_callable( - init, - follow_wrapper_chains=follow_wrapper_chains, - skip_bound_arg=skip_bound_arg, - sigcls=sigcls) + sig = _get_signature_of(init) if sig is None: # At this point we know, that `obj` is a class, with no user- @@ -2421,11 +2419,7 @@ def _signature_from_callable(obj, *, call = _signature_get_user_defined_method(type(obj), '__call__') if call is not None: try: - sig = _signature_from_callable( - call, - follow_wrapper_chains=follow_wrapper_chains, - skip_bound_arg=skip_bound_arg, - sigcls=sigcls) + sig = _get_signature_of(call) except ValueError as ex: msg = 'no signature found for {!r}'.format(obj) raise ValueError(msg) from ex @@ -2877,10 +2871,12 @@ class Signature: return _signature_from_builtin(cls, func) @classmethod - def from_callable(cls, obj, *, follow_wrapped=True): + def from_callable(cls, obj, *, + follow_wrapped=True, globalns=None, localns=None): """Constructs Signature for the given callable object.""" return _signature_from_callable(obj, sigcls=cls, - follow_wrapper_chains=follow_wrapped) + follow_wrapper_chains=follow_wrapped, + globalns=globalns, localns=localns) @property def parameters(self): @@ -3128,9 +3124,10 @@ class Signature: return rendered -def signature(obj, *, follow_wrapped=True): +def signature(obj, *, follow_wrapped=True, globalns=None, localns=None): """Get a signature object for the passed callable.""" - return Signature.from_callable(obj, follow_wrapped=follow_wrapped) + return Signature.from_callable(obj, follow_wrapped=follow_wrapped, + globalns=globalns, localns=localns) def _main(): |