forked from DonJayamanne/pythonVSCode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwildcards.py
More file actions
178 lines (145 loc) · 5.7 KB
/
wildcards.py
File metadata and controls
178 lines (145 loc) · 5.7 KB
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
from rope.base import ast, evaluate, builtins, pyobjects
from rope.refactor import patchedast, occurrences
class Wildcard(object):
def get_name(self):
"""Return the name of this wildcard"""
def matches(self, suspect, arg):
"""Return `True` if `suspect` matches this wildcard"""
class Suspect(object):
def __init__(self, pymodule, node, name):
self.name = name
self.pymodule = pymodule
self.node = node
class DefaultWildcard(object):
"""The default restructuring wildcard
The argument passed to this wildcard is in the
``key1=value1,key2=value2,...`` format. Possible keys are:
* name - for checking the reference
* type - for checking the type
* object - for checking the object
* instance - for checking types but similar to builtin isinstance
* exact - matching only occurrences with the same name as the wildcard
* unsure - matching unsure occurrences
"""
def __init__(self, project):
self.project = project
def get_name(self):
return 'default'
def matches(self, suspect, arg=''):
args = parse_arg(arg)
if not self._check_exact(args, suspect):
return False
if not self._check_object(args, suspect):
return False
return True
def _check_object(self, args, suspect):
kind = None
expected = None
unsure = args.get('unsure', False)
for check in ['name', 'object', 'type', 'instance']:
if check in args:
kind = check
expected = args[check]
if expected is not None:
checker = _CheckObject(self.project, expected,
kind, unsure=unsure)
return checker(suspect.pymodule, suspect.node)
return True
def _check_exact(self, args, suspect):
node = suspect.node
if args.get('exact'):
if not isinstance(node, ast.Name) or not node.id == suspect.name:
return False
else:
if not isinstance(node, ast.expr):
return False
return True
def parse_arg(arg):
if isinstance(arg, dict):
return arg
result = {}
tokens = arg.split(',')
for token in tokens:
if '=' in token:
parts = token.split('=', 1)
result[parts[0].strip()] = parts[1].strip()
else:
result[token.strip()] = True
return result
class _CheckObject(object):
def __init__(self, project, expected, kind='object', unsure=False):
self.project = project
self.kind = kind
self.unsure = unsure
self.expected = self._evaluate(expected)
def __call__(self, pymodule, node):
pyname = self._evaluate_node(pymodule, node)
if pyname is None or self.expected is None:
return self.unsure
if self._unsure_pyname(pyname, unbound=self.kind == 'name'):
return True
if self.kind == 'name':
return self._same_pyname(self.expected, pyname)
else:
pyobject = pyname.get_object()
if self.kind == 'object':
objects = [pyobject]
if self.kind == 'type':
objects = [pyobject.get_type()]
if self.kind == 'instance':
objects = [pyobject]
objects.extend(self._get_super_classes(pyobject))
objects.extend(self._get_super_classes(pyobject.get_type()))
for pyobject in objects:
if self._same_pyobject(self.expected.get_object(), pyobject):
return True
return False
def _get_super_classes(self, pyobject):
result = []
if isinstance(pyobject, pyobjects.AbstractClass):
for superclass in pyobject.get_superclasses():
result.append(superclass)
result.extend(self._get_super_classes(superclass))
return result
def _same_pyobject(self, expected, pyobject):
return expected == pyobject
def _same_pyname(self, expected, pyname):
return occurrences.same_pyname(expected, pyname)
def _unsure_pyname(self, pyname, unbound=True):
return self.unsure and occurrences.unsure_pyname(pyname, unbound)
def _split_name(self, name):
parts = name.split('.')
expression, kind = parts[0], parts[-1]
if len(parts) == 1:
kind = 'name'
return expression, kind
def _evaluate_node(self, pymodule, node):
scope = pymodule.get_scope().get_inner_scope_for_line(node.lineno)
expression = node
if isinstance(expression, ast.Name) and \
isinstance(expression.ctx, ast.Store):
start, end = patchedast.node_region(expression)
text = pymodule.source_code[start:end]
return evaluate.eval_str(scope, text)
else:
return evaluate.eval_node(scope, expression)
def _evaluate(self, code):
attributes = code.split('.')
pyname = None
if attributes[0] in ('__builtin__', '__builtins__'):
class _BuiltinsStub(object):
def get_attribute(self, name):
return builtins.builtins[name]
def __getitem__(self, name):
return builtins.builtins[name]
def __contains__(self, name):
return name in builtins.builtins
pyobject = _BuiltinsStub()
else:
pyobject = self.project.get_module(attributes[0])
for attribute in attributes[1:]:
pyname = pyobject[attribute]
if pyname is None:
return None
pyobject = pyname.get_object()
return pyname