diff options
author | Karthikeyan Singaravelan <tir.karthi@gmail.com> | 2020-04-18 16:19:32 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-18 16:19:32 (GMT) |
commit | 696136b993e11b37c4f34d729a0375e5ad544ade (patch) | |
tree | 19b1085d34db9d665b8f131e3f99bd0c2a40fcb6 /Lib/inspect.py | |
parent | ce578831a4e573eac422a488930100bc5380f227 (diff) | |
download | cpython-696136b993e11b37c4f34d729a0375e5ad544ade.zip cpython-696136b993e11b37c4f34d729a0375e5ad544ade.tar.gz cpython-696136b993e11b37c4f34d729a0375e5ad544ade.tar.bz2 |
bpo-35113: Fix inspect.getsource to return correct source for inner classes (#10307)
* Use ast module to find class definition
* Add NEWS entry
* Fix class with multiple children and move decorator code to the method
* Fix PR comments
1. Use node.decorator_list to select decorators
2. Remove unwanted variables in ClassVisitor
3. Simplify stack management as per review
* Add test for nested functions and async calls
* Fix pydoc test since comments are returned now correctly
* Set event loop policy as None to fix environment related change
* Refactor visit_AsyncFunctionDef and tests
* Refactor to use local variables and fix tests
* Add patch attribution
* Use self.addCleanup for asyncio
* Rename ClassVisitor to ClassFinder and fix asyncio cleanup
* Return first class inside conditional in case of multiple definitions. Remove decorator for class source.
* Add docstring to make the test correct
* Modify NEWS entry regarding decorators
* Return decorators too for bpo-15856
* Move ast and the class source code to top. Use proper Exception.
Diffstat (limited to 'Lib/inspect.py')
-rw-r--r-- | Lib/inspect.py | 65 |
1 files changed, 46 insertions, 19 deletions
diff --git a/Lib/inspect.py b/Lib/inspect.py index 6f7d5cd..ad7e8cb 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -32,6 +32,7 @@ __author__ = ('Ka-Ping Yee <ping@lfw.org>', 'Yury Selivanov <yselivanov@sprymix.com>') import abc +import ast import dis import collections.abc import enum @@ -770,6 +771,42 @@ def getmodule(object, _filename=None): if builtinobject is object: return builtin + +class ClassFoundException(Exception): + pass + + +class _ClassFinder(ast.NodeVisitor): + + def __init__(self, qualname): + self.stack = [] + self.qualname = qualname + + def visit_FunctionDef(self, node): + self.stack.append(node.name) + self.stack.append('<locals>') + self.generic_visit(node) + self.stack.pop() + self.stack.pop() + + visit_AsyncFunctionDef = visit_FunctionDef + + def visit_ClassDef(self, node): + self.stack.append(node.name) + if self.qualname == '.'.join(self.stack): + # Return the decorator for the class if present + if node.decorator_list: + line_number = node.decorator_list[0].lineno + else: + line_number = node.lineno + + # decrement by one since lines starts with indexing by zero + line_number -= 1 + raise ClassFoundException(line_number) + self.generic_visit(node) + self.stack.pop() + + def findsource(object): """Return the entire source file and starting line number for an object. @@ -802,25 +839,15 @@ def findsource(object): return lines, 0 if isclass(object): - name = object.__name__ - pat = re.compile(r'^(\s*)class\s*' + name + r'\b') - # make some effort to find the best matching class definition: - # use the one with the least indentation, which is the one - # that's most probably not inside a function definition. - candidates = [] - for i in range(len(lines)): - match = pat.match(lines[i]) - if match: - # if it's at toplevel, it's already the best one - if lines[i][0] == 'c': - return lines, i - # else add whitespace to candidate list - candidates.append((match.group(1), i)) - if candidates: - # this will sort by whitespace, and by line number, - # less whitespace first - candidates.sort() - return lines, candidates[0][1] + qualname = object.__qualname__ + source = ''.join(lines) + tree = ast.parse(source) + class_finder = _ClassFinder(qualname) + try: + class_finder.visit(tree) + except ClassFoundException as e: + line_number = e.args[0] + return lines, line_number else: raise OSError('could not find class definition') |