How to extract functions used in python code file?

I would like to create a list of all the functions used in the code file. For example, if we have the following code in a file named 'add_random.py'

`

import numpy as np from numpy import linalg def foo(): print np.random.rand(4) + np.random.randn(4) print linalg.norm(np.random.rand(4)) 

`

I would like to extract the following list: [numpy.random.rand, np.random.randn, np.linalg.norm, np.random.rand]

The list contains functions used in the code with their actual name in the form 'module.submodule.function'. Is there anything in python that can help me do this?

+6
source share
2 answers

You can print all call expressions with:

 import ast class CallCollector(ast.NodeVisitor): def __init__(self): self.calls = [] self.current = None def visit_Call(self, node): # new call, trace the function expression self.current = '' self.visit(node.func) self.calls.append(self.current) self.current = None def generic_visit(self, node): if self.current is not None: print "warning: {} node in function expression not supported".format( node.__class__.__name__) super(CallCollector, self).generic_visit(node) # record the func expression def visit_Name(self, node): if self.current is None: return self.current += node.id def visit_Attribute(self, node): if self.current is None: self.generic_visit(node) self.visit(node.value) self.current += '.' + node.attr 

Use this with the ast parsing tree:

 tree = ast.parse(yoursource) cc = CallCollector() cc.visit(tree) print cc.calls 

Demo:

 >>> tree = ast.parse('''\ ... def foo(): ... print np.random.rand(4) + np.random.randn(4) ... print linalg.norm(np.random.rand(4)) ... ''') >>> cc = CallCollector() >>> cc.visit(tree) >>> cc.calls ['np.random.rand', 'np.random.randn', 'linalg.norm'] 

The above walker only processes names and attributes; if you need more sophisticated expression support, you will have to extend this.

Note that collecting names like this is not a trivial task . Any feedback will not be processed. You can create a dictionary in your function code to call and dynamically replace function objects, and static analysis like the one above cannot track it.

+3
source

In general, this problem is unsolvable; for example, getattribute(random, "random")() .

If you need static analysis, jedi is best

If you make dynamic decisions, then coverage is your best friend. It will display all the functions used, not just links to them.

Finally, you can always roll your own dynamic hardware into lines:

 import random import logging class Proxy(object): def __getattr__(self, name): logging.debug("tried to use random.%s", name) return getattribute(_random, name) _random = random random = Proxy() 
+1
source

Source: https://habr.com/ru/post/975759/


All Articles