|
""" source browser using compiler module |
|
WARNING!!! |
|
This is very simple and very silly attempt to make so. |
|
""" |
|
from compiler import parse, ast |
import py |
|
from py.__.path.common import PathBase |
|
blockers = [ast.Function, ast.Class] |
|
class BaseElem(object): |
def listnames(self): |
if getattr(self, 'parent', None): |
return self.parent.listnames() + '.' + self.name |
return self.name |
|
class Module(BaseElem): |
def __init__(self, path, _dict): |
self.path = path |
self.dict = _dict |
|
def __getattr__(self, attr): |
try: |
return self.dict[attr] |
except KeyError: |
raise AttributeError(attr) |
|
def get_children(self): |
values = self.dict.values() |
all = values[:] |
for v in values: |
all += v.get_children() |
return all |
|
def get_endline(start, lst): |
l = lst[::-1] |
for i in l: |
if i.lineno: |
return i.lineno |
end_ch = get_endline(None, i.getChildNodes()) |
if end_ch: |
return end_ch |
return start |
|
class Function(BaseElem): |
def __init__(self, name, parent, firstlineno, endlineno): |
self.firstlineno = firstlineno |
self.endlineno = endlineno |
self.name = name |
self.parent = parent |
|
def get_children(self): |
return [] |
|
class Method(BaseElem): |
def __init__(self, name, parent, firstlineno, endlineno): |
self.name = name |
self.firstlineno = firstlineno |
self.endlineno = endlineno |
self.parent = parent |
|
def function_from_ast(ast, cls_ast, cls=Function): |
startline = ast.lineno |
endline = get_endline(startline, ast.getChildNodes()) |
assert endline |
return cls(ast.name, cls_ast, startline, endline) |
|
def class_from_ast(cls_ast): |
bases = [i.name for i in cls_ast.bases if isinstance(i, ast.Name)] |
|
methods = {} |
startline = cls_ast.lineno |
name = cls_ast.name |
endline = get_endline(startline, cls_ast.getChildNodes()) |
cls = Class(name, startline, endline, bases, []) |
cls.methods = dict([(i.name, function_from_ast(i, cls, Method)) for i in \ |
cls_ast.code.nodes if isinstance(i, ast.Function)]) |
return cls |
|
class Class(BaseElem): |
def __init__(self, name, firstlineno, endlineno, bases, methods): |
self.bases = bases |
self.firstlineno = firstlineno |
self.endlineno = endlineno |
self.name = name |
self.methods = methods |
|
def __getattr__(self, attr): |
try: |
return self.methods[attr] |
except KeyError: |
raise AttributeError(attr) |
|
def get_children(self): |
return self.methods.values() |
|
def dir_nodes(st): |
""" List all the subnodes, which are not blockers |
""" |
res = [] |
for i in st.getChildNodes(): |
res.append(i) |
if not i.__class__ in blockers: |
res += dir_nodes(i) |
return res |
|
def update_mod_dict(imp_mod, mod_dict): |
|
|
for key, value in mod_dict.items(): |
if not hasattr(imp_mod, key): |
del mod_dict[key] |
|
def parse_path(path): |
if not isinstance(path, PathBase): |
path = py.path.local(path) |
buf = path.open().read() |
st = parse(buf) |
|
nodes = dir_nodes(st) |
function_ast = [i for i in nodes if isinstance(i, ast.Function)] |
classes_ast = [i for i in nodes if isinstance(i, ast.Class)] |
mod_dict = dict([(i.name, function_from_ast(i, None)) for i in function_ast] |
+ [(i.name, class_from_ast(i)) for i in classes_ast]) |
|
try: |
mod = path.pyimport() |
except (KeyboardInterrupt, SystemExit): |
raise |
except: |
|
|
pass |
else: |
update_mod_dict(mod, mod_dict) |
return Module(path, mod_dict) |
|
|