~ubuntu-branches/debian/experimental/spyder/experimental

« back to all changes in this revision

Viewing changes to spyderlib/utils/classparser.py

  • Committer: Package Import Robot
  • Author(s): Picca Frédéric-Emmanuel
  • Date: 2013-02-27 09:51:28 UTC
  • mfrom: (1.1.18)
  • Revision ID: package-import@ubuntu.com-20130227095128-wtx1irpvf4vl79lj
Tags: 2.2.0~beta3+dfsg-1
* Imported Upstream version 2.2.0~beta3+dfsg
* debian /patches
  - 0002-feature-forwarded-add-icon-to-desktop-file.patch (deleted)
    this patch was integrated by the upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# -*- coding: utf-8 -*-
2
 
#
3
 
# Copyright © 2009 Pierre Raybaut
4
 
# Licensed under the terms of the MIT License
5
 
# (see spyderlib/__init__.py for details)
6
 
 
7
 
"""
8
 
Python class/function parser
9
 
 
10
 
Derived from "Demo/parser/example.py" from Python distribution
11
 
 
12
 
******************************** WARNING ***************************************
13
 
    This module is not used anymore in Spyder since v1.1.0.
14
 
    However, it will still be part of spyderlib module for a little while -
15
 
    we never know, it could be useful...
16
 
********************************************************************************
17
 
"""
18
 
 
19
 
import os
20
 
import parser
21
 
import symbol
22
 
from types import ListType, TupleType
23
 
 
24
 
 
25
 
def get_info(fileName):
26
 
    source = open(fileName, "U").read() + "\n"
27
 
    basename = os.path.basename(os.path.splitext(fileName)[0])
28
 
    ast = parser.suite(source)
29
 
    return ModuleInfo(ast.totuple(line_info=True), basename)
30
 
 
31
 
def get_classes(filename):
32
 
    """
33
 
    Return classes (with methods) and functions of module *filename*:
34
 
    [ (class1_lineno, class1_name, [ (method1_lineno, method1_name), ]),
35
 
      (func1_lineno, func1_name, None),]
36
 
    """
37
 
    moduleinfo = get_info(filename)
38
 
    classes = []
39
 
    for classname in moduleinfo.get_class_names():
40
 
        clinfo = moduleinfo.get_class_info(classname)
41
 
        methods = []
42
 
        for methodname in clinfo.get_method_names():
43
 
            minfo = clinfo.get_method_info(methodname)
44
 
            methods.append( (minfo.get_lineno(), methodname) )
45
 
        methods.sort()
46
 
        classes.append( (clinfo.get_lineno(), classname, methods) )
47
 
    for funcname in moduleinfo.get_function_names():
48
 
        finfo = moduleinfo.get_function_info(funcname)
49
 
        classes.append( (finfo.get_lineno(), funcname, None) )
50
 
    classes.sort()
51
 
    return classes
52
 
 
53
 
 
54
 
class SuiteInfoBase:
55
 
    _name = ''
56
 
    _lineno = -1
57
 
    #  This pattern identifies compound statements, allowing them to be readily
58
 
    #  differentiated from simple statements.
59
 
    #
60
 
    COMPOUND_STMT_PATTERN = (
61
 
        symbol.stmt,
62
 
        (symbol.compound_stmt, ['compound'])
63
 
        )
64
 
 
65
 
    def __init__(self, tree = None):
66
 
        self._class_info = {}
67
 
        self._function_info = {}
68
 
        if tree:
69
 
            self._extract_info(tree)
70
 
 
71
 
    def _extract_info(self, tree):
72
 
        # extract docstring
73
 
        # discover inner definitions
74
 
        for node in tree[1:]:
75
 
            found, vars = match(self.COMPOUND_STMT_PATTERN, node)
76
 
            if found:
77
 
                cstmt = vars['compound']
78
 
                if cstmt[0] == symbol.funcdef:
79
 
                    func_info = FunctionInfo(cstmt)
80
 
                    self._function_info[func_info._name] = func_info
81
 
                elif cstmt[0] == symbol.classdef:
82
 
                    class_info = ClassInfo(cstmt)
83
 
                    self._class_info[class_info._name] = class_info
84
 
 
85
 
    def get_name(self):
86
 
        return self._name
87
 
        
88
 
    def get_lineno(self):
89
 
        return self._lineno
90
 
 
91
 
    def get_class_names(self):
92
 
        return self._class_info.keys()
93
 
 
94
 
    def get_class_info(self, name):
95
 
        return self._class_info[name]
96
 
 
97
 
    def __getitem__(self, name):
98
 
        try:
99
 
            return self._class_info[name]
100
 
        except KeyError:
101
 
            return self._function_info[name]
102
 
 
103
 
 
104
 
class SuiteFuncInfo:
105
 
    #  Mixin class providing access to function names and info.
106
 
 
107
 
    def get_function_names(self):
108
 
        return self._function_info.keys()
109
 
 
110
 
    def get_function_info(self, name):
111
 
        return self._function_info[name]
112
 
 
113
 
 
114
 
class FunctionInfo(SuiteInfoBase, SuiteFuncInfo):
115
 
    def __init__(self, tree = None):
116
 
        index = 2
117
 
        prefix = ''
118
 
        if tree[1][0] == symbol.decorators:
119
 
            index += 1
120
 
            prefix = '@'
121
 
        self._name = prefix + tree[index][1]
122
 
        self._lineno = tree[index][2]
123
 
        SuiteInfoBase.__init__(self, tree and tree[-1] or None)
124
 
 
125
 
 
126
 
class ClassInfo(SuiteInfoBase):
127
 
    def __init__(self, tree = None):
128
 
        self._name = tree[2][1]
129
 
        self._lineno = tree[2][2]
130
 
        SuiteInfoBase.__init__(self, tree and tree[-1] or None)
131
 
 
132
 
    def get_method_names(self):
133
 
        return self._function_info.keys()
134
 
 
135
 
    def get_method_info(self, name):
136
 
        return self._function_info[name]
137
 
 
138
 
 
139
 
class ModuleInfo(SuiteInfoBase, SuiteFuncInfo):
140
 
    def __init__(self, tree = None, name = "<string>"):
141
 
        self._name = name
142
 
        self._lineno = 0
143
 
        if tree[0] == symbol.encoding_decl:
144
 
            self._encoding = tree[2]
145
 
            tree = tree[1]
146
 
        else:
147
 
            self._encoding = 'ascii'
148
 
        SuiteInfoBase.__init__(self, tree)
149
 
 
150
 
 
151
 
def match(pattern, data, vars=None):
152
 
    """Match `data' to `pattern', with variable extraction.
153
 
 
154
 
    pattern
155
 
        Pattern to match against, possibly containing variables.
156
 
 
157
 
    data
158
 
        Data to be checked and against which variables are extracted.
159
 
 
160
 
    vars
161
 
        Dictionary of variables which have already been found.  If not
162
 
        provided, an empty dictionary is created.
163
 
 
164
 
    The `pattern' value may contain variables of the form ['varname'] which
165
 
    are allowed to match anything.  The value that is matched is returned as
166
 
    part of a dictionary which maps 'varname' to the matched value.  'varname'
167
 
    is not required to be a string object, but using strings makes patterns
168
 
    and the code which uses them more readable.
169
 
 
170
 
    This function returns two values: a boolean indicating whether a match
171
 
    was found and a dictionary mapping variable names to their associated
172
 
    values.
173
 
    """
174
 
    if vars is None:
175
 
        vars = {}
176
 
    if type(pattern) is ListType:       # 'variables' are ['varname']
177
 
        vars[pattern[0]] = data
178
 
        return 1, vars
179
 
    if type(pattern) is not TupleType:
180
 
        return (pattern == data), vars
181
 
    if len(data) != len(pattern):
182
 
        return 0, vars
183
 
    for pattern, data in map(None, pattern, data):
184
 
        same, vars = match(pattern, data, vars)
185
 
        if not same:
186
 
            break
187
 
    return same, vars
188
 
 
189
 
 
190
 
if __name__ == '__main__':
191
 
    import sys, time
192
 
    t0 = time.time()
193
 
    classes = get_classes(sys.argv[1])
194
 
    print "Elapsed time: %s ms" % round((time.time()-t0)*1000)
195
 
#    from pprint import pprint
196
 
#    pprint(classes)
 
1
# -*- coding: utf-8 -*-
 
2
#
 
3
# Copyright © 2009 Pierre Raybaut
 
4
# Licensed under the terms of the MIT License
 
5
# (see spyderlib/__init__.py for details)
 
6
 
 
7
"""
 
8
Python class/function parser
 
9
 
 
10
Derived from "Demo/parser/example.py" from Python distribution
 
11
 
 
12
******************************** WARNING ***************************************
 
13
    This module is not used anymore in Spyder since v1.1.0.
 
14
    However, it will still be part of spyderlib module for a little while -
 
15
    we never know, it could be useful...
 
16
********************************************************************************
 
17
"""
 
18
 
 
19
import os
 
20
import parser
 
21
import symbol
 
22
from types import ListType, TupleType
 
23
 
 
24
 
 
25
def get_info(fileName):
 
26
    source = open(fileName, "U").read() + "\n"
 
27
    basename = os.path.basename(os.path.splitext(fileName)[0])
 
28
    ast = parser.suite(source)
 
29
    return ModuleInfo(ast.totuple(line_info=True), basename)
 
30
 
 
31
def get_classes(filename):
 
32
    """
 
33
    Return classes (with methods) and functions of module *filename*:
 
34
    [ (class1_lineno, class1_name, [ (method1_lineno, method1_name), ]),
 
35
      (func1_lineno, func1_name, None),]
 
36
    """
 
37
    moduleinfo = get_info(filename)
 
38
    classes = []
 
39
    for classname in moduleinfo.get_class_names():
 
40
        clinfo = moduleinfo.get_class_info(classname)
 
41
        methods = []
 
42
        for methodname in clinfo.get_method_names():
 
43
            minfo = clinfo.get_method_info(methodname)
 
44
            methods.append( (minfo.get_lineno(), methodname) )
 
45
        methods.sort()
 
46
        classes.append( (clinfo.get_lineno(), classname, methods) )
 
47
    for funcname in moduleinfo.get_function_names():
 
48
        finfo = moduleinfo.get_function_info(funcname)
 
49
        classes.append( (finfo.get_lineno(), funcname, None) )
 
50
    classes.sort()
 
51
    return classes
 
52
 
 
53
 
 
54
class SuiteInfoBase:
 
55
    _name = ''
 
56
    _lineno = -1
 
57
    #  This pattern identifies compound statements, allowing them to be readily
 
58
    #  differentiated from simple statements.
 
59
    #
 
60
    COMPOUND_STMT_PATTERN = (
 
61
        symbol.stmt,
 
62
        (symbol.compound_stmt, ['compound'])
 
63
        )
 
64
 
 
65
    def __init__(self, tree = None):
 
66
        self._class_info = {}
 
67
        self._function_info = {}
 
68
        if tree:
 
69
            self._extract_info(tree)
 
70
 
 
71
    def _extract_info(self, tree):
 
72
        # extract docstring
 
73
        # discover inner definitions
 
74
        for node in tree[1:]:
 
75
            found, vars = match(self.COMPOUND_STMT_PATTERN, node)
 
76
            if found:
 
77
                cstmt = vars['compound']
 
78
                if cstmt[0] == symbol.funcdef:
 
79
                    func_info = FunctionInfo(cstmt)
 
80
                    self._function_info[func_info._name] = func_info
 
81
                elif cstmt[0] == symbol.classdef:
 
82
                    class_info = ClassInfo(cstmt)
 
83
                    self._class_info[class_info._name] = class_info
 
84
 
 
85
    def get_name(self):
 
86
        return self._name
 
87
        
 
88
    def get_lineno(self):
 
89
        return self._lineno
 
90
 
 
91
    def get_class_names(self):
 
92
        return self._class_info.keys()
 
93
 
 
94
    def get_class_info(self, name):
 
95
        return self._class_info[name]
 
96
 
 
97
    def __getitem__(self, name):
 
98
        try:
 
99
            return self._class_info[name]
 
100
        except KeyError:
 
101
            return self._function_info[name]
 
102
 
 
103
 
 
104
class SuiteFuncInfo:
 
105
    #  Mixin class providing access to function names and info.
 
106
 
 
107
    def get_function_names(self):
 
108
        return self._function_info.keys()
 
109
 
 
110
    def get_function_info(self, name):
 
111
        return self._function_info[name]
 
112
 
 
113
 
 
114
class FunctionInfo(SuiteInfoBase, SuiteFuncInfo):
 
115
    def __init__(self, tree = None):
 
116
        index = 2
 
117
        prefix = ''
 
118
        if tree[1][0] == symbol.decorators:
 
119
            index += 1
 
120
            prefix = '@'
 
121
        self._name = prefix + tree[index][1]
 
122
        self._lineno = tree[index][2]
 
123
        SuiteInfoBase.__init__(self, tree and tree[-1] or None)
 
124
 
 
125
 
 
126
class ClassInfo(SuiteInfoBase):
 
127
    def __init__(self, tree = None):
 
128
        self._name = tree[2][1]
 
129
        self._lineno = tree[2][2]
 
130
        SuiteInfoBase.__init__(self, tree and tree[-1] or None)
 
131
 
 
132
    def get_method_names(self):
 
133
        return self._function_info.keys()
 
134
 
 
135
    def get_method_info(self, name):
 
136
        return self._function_info[name]
 
137
 
 
138
 
 
139
class ModuleInfo(SuiteInfoBase, SuiteFuncInfo):
 
140
    def __init__(self, tree = None, name = "<string>"):
 
141
        self._name = name
 
142
        self._lineno = 0
 
143
        if tree[0] == symbol.encoding_decl:
 
144
            self._encoding = tree[2]
 
145
            tree = tree[1]
 
146
        else:
 
147
            self._encoding = 'ascii'
 
148
        SuiteInfoBase.__init__(self, tree)
 
149
 
 
150
 
 
151
def match(pattern, data, vars=None):
 
152
    """Match `data' to `pattern', with variable extraction.
 
153
 
 
154
    pattern
 
155
        Pattern to match against, possibly containing variables.
 
156
 
 
157
    data
 
158
        Data to be checked and against which variables are extracted.
 
159
 
 
160
    vars
 
161
        Dictionary of variables which have already been found.  If not
 
162
        provided, an empty dictionary is created.
 
163
 
 
164
    The `pattern' value may contain variables of the form ['varname'] which
 
165
    are allowed to match anything.  The value that is matched is returned as
 
166
    part of a dictionary which maps 'varname' to the matched value.  'varname'
 
167
    is not required to be a string object, but using strings makes patterns
 
168
    and the code which uses them more readable.
 
169
 
 
170
    This function returns two values: a boolean indicating whether a match
 
171
    was found and a dictionary mapping variable names to their associated
 
172
    values.
 
173
    """
 
174
    if vars is None:
 
175
        vars = {}
 
176
    if type(pattern) is ListType:       # 'variables' are ['varname']
 
177
        vars[pattern[0]] = data
 
178
        return 1, vars
 
179
    if type(pattern) is not TupleType:
 
180
        return (pattern == data), vars
 
181
    if len(data) != len(pattern):
 
182
        return 0, vars
 
183
    for pattern, data in map(None, pattern, data):
 
184
        same, vars = match(pattern, data, vars)
 
185
        if not same:
 
186
            break
 
187
    return same, vars
 
188
 
 
189
 
 
190
if __name__ == '__main__':
 
191
    import sys, time
 
192
    t0 = time.time()
 
193
    classes = get_classes(sys.argv[1])
 
194
    print "Elapsed time: %s ms" % round((time.time()-t0)*1000)
 
195
#    from pprint import pprint
 
196
#    pprint(classes)