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) |