Search code examples
pythonclassabstract-syntax-treeinspect

Class method won't return anything


When I write scripts, I have a common library of personal functions that I use by lazily importing the whole thing. So I wanted to clean that up so instead of importing thousands of lines of code, I could have a script automatically select the functions I need for that particular script and copy them into a file for publication. I got that working using a combination of ast and inspect, but now I want to copy the exact line of code where global variables are defined inside of my module.

For example if I use the shortcut eprint in the script it should scrape the line: eprint = Eprinter(verbose=1).eprint which creates a shortcut to a class method.

I'm trying to adopt the code I found here: https://stackoverflow.com/a/13230346/11343425

class GetAssignments(ast.NodeVisitor):
    def visit_Name(self, node):
        if isinstance(node.ctx, ast.Store):
            if node.id == 'eprint':
                print(node.id, node.lineno)
                return node.lineno

code = inspect.getsource(printing)
a = GetAssignments()
b = a.visit(ast.parse(code))
print('b =', b)

This will print the node.lineno just fine, but it returns None and I can't figure out why.


Solution

  • ast.NodeVisitor is meant to be subclassed which means visit_Name can't return anything. However, a custom function can be an intermediary like so:

    class GetAssignments(ast.NodeVisitor):
        def visit_Name(self, node):
            if isinstance(node.ctx, ast.Store):
                if node.id == self.expr:
                    print("Found line number", node.lineno)
                    self.lineno = node.lineno
    
        def search(self, node, expr):
            self.expr = expr
            self.visit(node)
            return self.lineno
            
    code = inspect.getsource(printing)
    
    lineno = GetAssignments().search(ast.parse(code), 'eprint')
    line = code.split('\n')[lineno-1]
    print(lineno, line)