Reputation: 395
I am trying to build a program which allows the user to browse to a folder which contains python modules. Once the folder has been selected it will list all python files within that folder as well as all the classes and methods for each module. My question is, are there any way I can do this without opening each file and parsing for "def" or "class"? I noticed that there's a function called mro which returns the attribute of a class but that requires me to have access to that class through an import. So is there any way I can get the same result? Thank you in advance!
Upvotes: 3
Views: 6688
Reputation: 651
Thanks, useful example for this first time ast user. Code above with the import, printed output, and without the 1 spelling error ;-)
import ast
classList = []
className = None
methodName = None
fileName = "C:\\fullPathToAPythonFile.py"
fileObject = open(fileName ,"r")
text = fileObject.read()
p = ast.parse(text)
node = ast.NodeVisitor()
for node in ast.walk(p):
if isinstance(node, ast.FunctionDef) or isinstance(node, ast.ClassDef):
if isinstance(node, ast.ClassDef):
className = node.name
else:
methodName = node.name
if className != None and methodName != None:
subList = (methodName , className)
classList.append(subList)
print("class: " + className + ", method: " + methodName)
Upvotes: 0
Reputation: 5239
I had to replace a lot of code in one of my modules, here is my way of getting classes and methods:
def listClass(file):
with open(file,"r") as f:
p = ast.parse(f.read())
# get all classes from the given python file.
classes = [c for c in ast.walk(p) if isinstance(c,ast.ClassDef)]
out = dict()
for x in classes:
out[x.name] = [fun.name for fun in ast.walk(x) if isinstance(fun,ast.FunctionDef)]
return out
Sample pprint output:
{'Alert': ['__init__',
'fg',
'fg',
'bg',
'bg',
'paintEvent',
'drawBG',
'drawAlert'],
'AlertMouse': ['__init__', 'paintEvent', 'mouseMoveEvent'],
'AlertPopup': ['__init__', 'mousePressEvent', 'keyPressEvent', 'systemInfo']}
Upvotes: 0
Reputation: 395
This is what I came up with using the AST module, it has exactly what I was looking for.
def fillClassList(file):
classList = []
className = None
mehotdName = None
fileName = "C:\Transcriber\Framework\ctetest\RegressionTest\GeneralTest\\" + file
fileObject = open(fileName,"r")
text = fileObject.read()
p = ast.parse(text)
node = ast.NodeVisitor()
for node in ast.walk(p):
if isinstance(node, ast.FunctionDef) or isinstance(node, ast.ClassDef):
if isinstance(node, ast.ClassDef):
className = node.name
else:
methodName = node.name
if className != None and methodName != None:
subList = (methodName , className)
classList.append(subList)
return classList
Upvotes: 3
Reputation: 77952
Most of Python's implementation (parser included) is available in the stdlib, so by carefully reading the modules index you should find what you need. The first modules / packages that come to mind are importlib, inspect and ast but there surely other modules of interest.
Upvotes: 0
Reputation: 1797
If you want to know the contents of the file, there's no way around looking into the file :)
Your choice comes down to whether you want to parse out the content-of-interest yourself, or if you want to let Python load the file and then ask it about what it found.
For a very simple Python file like testme.py below you can do something like this (warning: not for those with weak stomachs):
testme.py:
class Foo (object):
pass
def bar():
pass
analyze.py:
import os.path
files = ['testme.py']
for f in files:
print f
modname = os.path.splitext(f)[0]
exec('import ' + modname)
mod = eval(modname)
for symbol in dir(mod):
if symbol.startswith('__'):
continue
print ' ', symbol, type(eval(modname + '.' + symbol))
Output:
testme.py
Foo <type 'type'>
bar <type 'function'>
However, that's going to start to get pretty grotty when you expand it to deal with nested packages and modules and broken code and blah blah blah. Might be easier just to grep
for class
and/or def
and go from there.
Have fun with it! I :heart: metaprogramming
Upvotes: 0