forked from DonJayamanne/pythonVSCode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhelpers.py
More file actions
executable file
·179 lines (146 loc) · 5.39 KB
/
helpers.py
File metadata and controls
executable file
·179 lines (146 loc) · 5.39 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
179
import copy
from itertools import chain
from jedi.parser import tree
def deep_ast_copy(obj, parent=None, new_elements=None):
"""
Much, much faster than copy.deepcopy, but just for Parser elements (Doesn't
copy parents).
"""
if new_elements is None:
new_elements = {}
def copy_node(obj):
# If it's already in the cache, just return it.
try:
return new_elements[obj]
except KeyError:
# Actually copy and set attributes.
new_obj = copy.copy(obj)
new_elements[obj] = new_obj
# Copy children
new_children = []
for child in obj.children:
typ = child.type
if typ in ('whitespace', 'operator', 'keyword', 'number', 'string'):
# At the moment we're not actually copying those primitive
# elements, because there's really no need to. The parents are
# obviously wrong, but that's not an issue.
new_child = child
elif typ == 'name':
new_elements[child] = new_child = copy.copy(child)
new_child.parent = new_obj
else: # Is a BaseNode.
new_child = copy_node(child)
new_child.parent = new_obj
new_children.append(new_child)
new_obj.children = new_children
# Copy the names_dict (if there is one).
try:
names_dict = obj.names_dict
except AttributeError:
pass
else:
try:
new_obj.names_dict = new_names_dict = {}
except AttributeError: # Impossible to set CompFor.names_dict
pass
else:
for string, names in names_dict.items():
new_names_dict[string] = [new_elements[n] for n in names]
return new_obj
if obj.type == 'name':
# Special case of a Name object.
new_elements[obj] = new_obj = copy.copy(obj)
if parent is not None:
new_obj.parent = parent
elif isinstance(obj, tree.BaseNode):
new_obj = copy_node(obj)
if parent is not None:
for child in new_obj.children:
if isinstance(child, (tree.Name, tree.BaseNode)):
child.parent = parent
else: # String literals and so on.
new_obj = obj # Good enough, don't need to copy anything.
return new_obj
def call_of_name(name, cut_own_trailer=False):
"""
Creates a "call" node that consist of all ``trailer`` and ``power``
objects. E.g. if you call it with ``append``::
list([]).append(3) or None
You would get a node with the content ``list([]).append`` back.
This generates a copy of the original ast node.
"""
par = name
if tree.is_node(par.parent, 'trailer'):
par = par.parent
power = par.parent
if tree.is_node(power, 'power') and power.children[0] != name \
and not (power.children[-2] == '**' and
name.start_pos > power.children[-1].start_pos):
par = power
# Now the name must be part of a trailer
index = par.children.index(name.parent)
if index != len(par.children) - 1 or cut_own_trailer:
# Now we have to cut the other trailers away.
par = deep_ast_copy(par)
if not cut_own_trailer:
# Normally we would remove just the stuff after the index, but
# if the option is set remove the index as well. (for goto)
index = index + 1
par.children[index:] = []
return par
def get_module_names(module, all_scopes):
"""
Returns a dictionary with name parts as keys and their call paths as
values.
"""
if all_scopes:
dct = module.used_names
else:
dct = module.names_dict
return chain.from_iterable(dct.values())
class FakeImport(tree.ImportName):
def __init__(self, name, parent, level=0):
super(FakeImport, self).__init__([])
self.parent = parent
self._level = level
self.name = name
def get_defined_names(self):
return [self.name]
def aliases(self):
return {}
@property
def level(self):
return self._level
@property
def start_pos(self):
return 0, 0
def paths(self):
return [[self.name]]
def is_definition(self):
return True
class FakeName(tree.Name):
def __init__(self, name_str, parent=None, start_pos=(0, 0), is_definition=None):
"""
In case is_definition is defined (not None), that bool value will be
returned.
"""
super(FakeName, self).__init__(tree.zero_position_modifier, name_str, start_pos)
self.parent = parent
self._is_definition = is_definition
def get_definition(self):
return self.parent
def is_definition(self):
if self._is_definition is None:
return super(FakeName, self).is_definition()
else:
return self._is_definition
class LazyName(FakeName):
def __init__(self, name, parent_callback, is_definition=None):
super(LazyName, self).__init__(name, is_definition=is_definition)
self._parent_callback = parent_callback
@property
def parent(self):
return self._parent_callback()
@parent.setter
def parent(self, value):
pass # Do nothing, super classes can try to set the parent.