sources for browser.py [rev. unknown]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
""" 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)]
    # XXX
    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):
    # make sure that things that are in mod_dict, and not in imp_mod,
    # are not shown
    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)
    # first go - we get all functions and classes defined on top-level
    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])
    # we check all the elements, if they're really there
    try:
        mod = path.pyimport()
    except (KeyboardInterrupt, SystemExit):
        raise
    except:  # catch all other import problems generically
        # XXX some import problem: we probably should not
        # pretend to have an empty module 
        pass
    else:
        update_mod_dict(mod, mod_dict)
    return Module(path, mod_dict)