I have a python file with some classes and functions defined in it:
class A(object):
def __init__(self, an_arg, a_default_arg=None):
pass
def doStuff(an_other_arg, an_other_default_arg=None):
pass
And I want to get a list of all classes and functions in this file. (their names and parameter definitions are enough)
Now, I do know you can do this with __import__(module_descriptor)
and inspect
, but this is not an option as the file I'm scanning is from an untrusted source.
My first reaction was to try and create a safe environment to import them, but this seems impossible according to other stackoverflow-questions.
We can list down all the functions present in a Python module by simply using the dir() method in the Python shell or in the command prompt shell.
To list all functions in a Python module you can use dir(module).
To get the class name of an instance in Python: Use the type() function and __name__ to get the type or class of the Object/Instance. Using the combination of the __class__ and __name__ to get the type or class of the Object/Instance.
You can use the ast module to parse the source file, without actually executing any code. Then you can traverse the node tree to get the function and class names/parameters.
import ast
def show_info(functionNode):
print("Function name:", functionNode.name)
print("Args:")
for arg in functionNode.args.args:
#import pdb; pdb.set_trace()
print("\tParameter name:", arg.arg)
filename = "untrusted.py"
with open(filename) as file:
node = ast.parse(file.read())
functions = [n for n in node.body if isinstance(n, ast.FunctionDef)]
classes = [n for n in node.body if isinstance(n, ast.ClassDef)]
for function in functions:
show_info(function)
for class_ in classes:
print("Class name:", class_.name)
methods = [n for n in class_.body if isinstance(n, ast.FunctionDef)]
for method in methods:
show_info(method)
Result:
Function name: doStuff
Args:
Parameter name: an_other_arg
Parameter name: an_other_default_arg
Class name: A
Function name: __init__
Args:
Parameter name: self
Parameter name: an_arg
Parameter name: a_default_arg
The accepted solution is incomplete. Consider the following file:
def regular_function():
def nested_function():
pass
async def async_function():
pass
The accepted solution will only print:
Function name: regular_function
Args:
To get all functions, we need to make two changes:
async
functions as well as regular functionsHere is the corrected code, for finding functions:
import ast
from pathlib import Path
parsed_ast = ast.parse(Path(__file__).read_text())
functions = [
node
for node in ast.walk(parsed_ast)
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef))
]
for function in functions:
print(f"Function name: {function.name}")
print(f"Args: {', '.join([arg.arg for arg in function.args.args])}")
Note that this is pushing up against the bounds of what an AST walk should be used for. For anything more complicated, consider using NodeVisitor
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With