It is alternative inspire by @Martijn Pieters - this production code using different approach in scanning.
It allow scan __main__
what is problem for inspect.getsource(obj)
.
It collect also types for each name and function - order scan will allow filter more attributes, functions and extract more information.
import ast
import sys
import codecs
import pprint
class A(object):
b = 1
a = 1
c = 1
e, f, g = (1, 2, 3)
z = x = 1
((a1, b1), (c1, d1)) = ((1, 2), (1, 2))
class B(A):
pass
class ClassOrderVisitor(ast.NodeVisitor):
def __init__(self):
self.classes = {}
def __parseTuple(self, astTuple, fields):
for element in astTuple.elts:
if isinstance(element, ast.Name):
fields.append((element.id, element))
elif isinstance(element, ast.Tuple):
self.__parseTuple(element, fields)
else:
raise NotImplementedError()
def visit_ClassDef(self, node):
fields = []
for field in ast.iter_fields(node):
# class name
if field[0] == 'name':
className = field[1]
self.classes[className] = fields
# class body
elif field[0] == 'body':
for bodyItem in field[1]:
if isinstance(bodyItem, ast.Assign):
for target in bodyItem.targets:
if isinstance(target, ast.Name):
fields.append((target.id, target))
elif isinstance(target, ast.Tuple):
self.__parseTuple(target, fields)
else:
raise NotImplementedError()
elif isinstance(bodyItem, ast.FunctionDef):
fields.append((bodyItem.name, bodyItem))
# this file is named ast_parser.py not using inspect.getsource(obj)
# since problem with __main__ scan
def scanOrder(fileName):
with codecs.open(fileName, encoding = 'utf8') as sourceFile:
sourceCode = sourceFile.read()
codeTree = ast.parse(sourceCode, fileName)
classOrderVisitor = ClassOrderVisitor()
classOrderVisitor.visit(codeTree)
return classOrderVisitor.classes
# run
pprint.pprint(scanOrder('ast_parser.py'))
print [x for x in dir(A) if not x.startswith('__') and not x.endswith('__')]
Output:
{'A': [('b', <_ast.Name object at 0x01375E70>),
('a', <_ast.Name object at 0x01375ED0>),
('c', <_ast.Name object at 0x01375F30>),
('e', <_ast.Name object at 0x01375FB0>),
('f', <_ast.Name object at 0x01375FD0>),
('g', <_ast.Name object at 0x01375FF0>),
('z', <_ast.Name object at 0x0137B0D0>),
('x', <_ast.Name object at 0x0137B0F0>),
('a1', <_ast.Name object at 0x0137B190>),
('b1', <_ast.Name object at 0x0137B1B0>),
('c1', <_ast.Name object at 0x0137B1F0>),
('d1', <_ast.Name object at 0x0137B210>)],
'B': [],
'ClassOrderVisitor': [('__init__', <_ast.FunctionDef object at 0x0137B3D0>),
('__parseTuple',
<_ast.FunctionDef object at 0x0137B4F0>),
('visit_ClassDef',
<_ast.FunctionDef object at 0x0137BA10>)]}
['a', 'a1', 'b', 'b1', 'c', 'c1', 'd1', 'e', 'f', 'g', 'x', 'z']