Statistics
| Revision:

gvsig-scripting / org.gvsig.scripting / trunk / org.gvsig.scripting / org.gvsig.scripting.app / org.gvsig.scripting.app.mainplugin / src / main / resources-plugin / scripting / lib / pylint / pyreverse / utils.py @ 745

History | View | Annotate | Download (6.3 KB)

1
# Copyright (c) 2002-2013 LOGILAB S.A. (Paris, FRANCE).
2
# http://www.logilab.fr/ -- mailto:contact@logilab.fr
3
#
4
# This program is free software; you can redistribute it and/or modify it under
5
# the terms of the GNU General Public License as published by the Free Software
6
# Foundation; either version 2 of the License, or (at your option) any later
7
# version.
8
#
9
# This program is distributed in the hope that it will be useful, but WITHOUT
10
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License along with
14
# this program; if not, write to the Free Software Foundation, Inc.,
15
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16
"""
17
generic classes/functions for pyreverse core/extensions
18
"""
19
from __future__ import print_function
20

    
21
import os
22
import re
23
import sys
24

    
25
########### pyreverse option utils ##############################
26

    
27

    
28
RCFILE = '.pyreverserc'
29

    
30
def get_default_options():
31
    """
32
    Read config file and return list of options
33
    """
34
    options = []
35
    home = os.environ.get('HOME', '')
36
    if home:
37
        rcfile = os.path.join(home, RCFILE)
38
        try:
39
            options = open(rcfile).read().split()
40
        except IOError:
41
            pass # ignore if no config file found
42
    return options
43

    
44
def insert_default_options():
45
    """insert default options to sys.argv
46
    """
47
    options = get_default_options()
48
    options.reverse()
49
    for arg in options:
50
        sys.argv.insert(1, arg)
51

    
52

    
53

    
54
# astroid utilities ###########################################################
55

    
56
SPECIAL = re.compile('^__[A-Za-z0-9]+[A-Za-z0-9_]*__$')
57
PRIVATE = re.compile('^__[_A-Za-z0-9]*[A-Za-z0-9]+_?$')
58
PROTECTED = re.compile('^_[_A-Za-z0-9]*$')
59

    
60
def get_visibility(name):
61
    """return the visibility from a name: public, protected, private or special
62
    """
63
    if SPECIAL.match(name):
64
        visibility = 'special'
65
    elif PRIVATE.match(name):
66
        visibility = 'private'
67
    elif PROTECTED.match(name):
68
        visibility = 'protected'
69

    
70
    else:
71
        visibility = 'public'
72
    return visibility
73

    
74
ABSTRACT = re.compile('^.*Abstract.*')
75
FINAL = re.compile('^[A-Z_]*$')
76

    
77
def is_abstract(node):
78
    """return true if the given class node correspond to an abstract class
79
    definition
80
    """
81
    return ABSTRACT.match(node.name)
82

    
83
def is_final(node):
84
    """return true if the given class/function node correspond to final
85
    definition
86
    """
87
    return FINAL.match(node.name)
88

    
89
def is_interface(node):
90
    # bw compat
91
    return node.type == 'interface'
92

    
93
def is_exception(node):
94
    # bw compat
95
    return node.type == 'exception'
96

    
97

    
98
# Helpers #####################################################################
99

    
100
_CONSTRUCTOR = 1
101
_SPECIAL = 2
102
_PROTECTED = 4
103
_PRIVATE = 8
104
MODES = {
105
    'ALL'       : 0,
106
    'PUB_ONLY'  : _SPECIAL + _PROTECTED + _PRIVATE,
107
    'SPECIAL'   : _SPECIAL,
108
    'OTHER'     : _PROTECTED + _PRIVATE,
109
}
110
VIS_MOD = {'special': _SPECIAL, 'protected': _PROTECTED,
111
           'private': _PRIVATE, 'public': 0}
112

    
113

    
114
class FilterMixIn(object):
115
    """filter nodes according to a mode and nodes' visibility
116
    """
117
    def __init__(self, mode):
118
        "init filter modes"
119
        __mode = 0
120
        for nummod in mode.split('+'):
121
            try:
122
                __mode += MODES[nummod]
123
            except KeyError as ex:
124
                print('Unknown filter mode %s' % ex, file=sys.stderr)
125
        self.__mode = __mode
126

    
127

    
128
    def show_attr(self, node):
129
        """return true if the node should be treated
130
        """
131
        visibility = get_visibility(getattr(node, 'name', node))
132
        return not self.__mode & VIS_MOD[visibility]
133

    
134

    
135
class ASTWalker(object):
136
    """a walker visiting a tree in preorder, calling on the handler:
137

138
    * visit_<class name> on entering a node, where class name is the class of
139
    the node in lower case
140

141
    * leave_<class name> on leaving a node, where class name is the class of
142
    the node in lower case
143
    """
144

    
145
    def __init__(self, handler):
146
        self.handler = handler
147
        self._cache = {}
148

    
149
    def walk(self, node, _done=None):
150
        """walk on the tree from <node>, getting callbacks from handler"""
151
        if _done is None:
152
            _done = set()
153
        if node in _done:
154
            raise AssertionError((id(node), node, node.parent))
155
        _done.add(node)
156
        self.visit(node)
157
        for child_node in node.get_children():
158
            assert child_node is not node
159
            self.walk(child_node, _done)
160
        self.leave(node)
161
        assert node.parent is not node
162

    
163
    def get_callbacks(self, node):
164
        """get callbacks from handler for the visited node"""
165
        klass = node.__class__
166
        methods = self._cache.get(klass)
167
        if methods is None:
168
            handler = self.handler
169
            kid = klass.__name__.lower()
170
            e_method = getattr(handler, 'visit_%s' % kid,
171
                               getattr(handler, 'visit_default', None))
172
            l_method = getattr(handler, 'leave_%s' % kid,
173
                               getattr(handler, 'leave_default', None))
174
            self._cache[klass] = (e_method, l_method)
175
        else:
176
            e_method, l_method = methods
177
        return e_method, l_method
178

    
179
    def visit(self, node):
180
        """walk on the tree from <node>, getting callbacks from handler"""
181
        method = self.get_callbacks(node)[0]
182
        if method is not None:
183
            method(node)
184

    
185
    def leave(self, node):
186
        """walk on the tree from <node>, getting callbacks from handler"""
187
        method = self.get_callbacks(node)[1]
188
        if method is not None:
189
            method(node)
190

    
191

    
192
class LocalsVisitor(ASTWalker):
193
    """visit a project by traversing the locals dictionary"""
194
    def __init__(self):
195
        ASTWalker.__init__(self, self)
196
        self._visited = {}
197

    
198
    def visit(self, node):
199
        """launch the visit starting from the given node"""
200
        if node in self._visited:
201
            return
202
        self._visited[node] = 1 # FIXME: use set ?
203
        methods = self.get_callbacks(node)
204
        if methods[0] is not None:
205
            methods[0](node)
206
        if hasattr(node, 'locals'): # skip Instance and other proxy
207
            for local_node in node.values():
208
                self.visit(local_node)
209
        if methods[1] is not None:
210
            return methods[1](node)