I am trying to create a tool that identifies the number of lines of code in each function in a given python file. However- I do not want to actually run the code which is required with something like the inspect library suggested in other posts.
Is there a pre-existing tool I can use to get the source code for each function, or even a given function within the plain text of a .py file? Or will I need to create some custom regex/code for this?
Edit : Want to clarify since people are suggesting a few things I have already tried. AST provides me the ability to find the function name- but not the number of lines of the function, nor the source for the function or anything else that would lead me to it (from what I can see). Inspect can do it, but requires running the code (unless I am misunderstanding something).
You can use the ast
module to walk through the parse tree of a Python program. This requires that the program not have any syntax errors, but it will not attempt to execute the program, so runtime errors won't hinder the process. (In particular, since it doesn't execute import
statements, it won't descend into imported modules.)
The following very simple sample assumes that:
node.end_lineno - node.lineno + 1
if you just want the line count.)class
blocks as well as def
blocks, indenting nested objects by four spaces (or the value of the indent
argument).import ast
class ListVisitor(ast.NodeVisitor):
def __init__(self, indent=4):
self.cur = 0
self.ind = indent
def visit_FunctionDef(self, node):
print(f"{'':>{self.cur}}Function {node.name} {node.lineno}->{node.end_lineno}")
self.cur += self.ind
self.generic_visit(node)
self.cur -= self.ind
def visit_ClassDef(self, node):
print(f"{'':>{self.cur}}Class {node.name} {node.lineno}->{node.end_lineno}")
self.cur += self.ind
self.generic_visit(node)
self.cur -= self.ind
if __name__ == "__main__":
from sys import argv
v = ListVisitor()
for fn in argv[1:]:
try:
with open(fn) as source:
v.visit(ast.parse(source.read(), filename=fn, mode='exec'))
except SyntaxError as e:
print(e)
except OSError as e:
print(e)
Here's what the output looks like when I call it on itself:
$ python3.9 -m listfuncs listfuncs.py
Class ListVisitor 2->15
Function __init__ 3->5
Function visit_FunctionDef 6->10
Function visit_ClassDef 11->15