Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
marvel
GitHub Repository: marvel/qnf
Path: blob/master/elisp/emacs-for-python/rope-dist/rope/base/pyscopes.py
1415 views
1
import rope.base.builtins
2
import rope.base.codeanalyze
3
import rope.base.pynames
4
from rope.base import ast, exceptions, utils
5
6
7
class Scope(object):
8
9
def __init__(self, pycore, pyobject, parent_scope):
10
self.pycore = pycore
11
self.pyobject = pyobject
12
self.parent = parent_scope
13
14
def get_names(self):
15
"""Return the names defined or imported in this scope"""
16
return self.pyobject.get_attributes()
17
18
def get_defined_names(self):
19
"""Return the names defined in this scope"""
20
return self.pyobject._get_structural_attributes()
21
22
def get_name(self, name):
23
"""Return name `PyName` defined in this scope"""
24
if name not in self.get_names():
25
raise exceptions.NameNotFoundError('name %s not found' % name)
26
return self.get_names()[name]
27
28
def __getitem__(self, key):
29
"""The same as ``get_name(key)``"""
30
return self.get_name(key)
31
32
def __contains__(self, key):
33
"""The same as ``key in self.get_names()``"""
34
return key in self.get_names()
35
36
@utils.saveit
37
def get_scopes(self):
38
"""Return the subscopes of this scope
39
40
The returned scopes should be sorted by the order they appear.
41
"""
42
return self._create_scopes()
43
44
def lookup(self, name):
45
if name in self.get_names():
46
return self.get_names()[name]
47
if self.parent is not None:
48
return self.parent._propagated_lookup(name)
49
return None
50
51
def get_propagated_names(self):
52
"""Return the visible names of this scope
53
54
Return the names defined in this scope that are visible from
55
scopes containing this scope. This method returns the same
56
dictionary returned by `get_names()` except for `ClassScope`
57
which returns an empty dict.
58
"""
59
return self.get_names()
60
61
def _propagated_lookup(self, name):
62
if name in self.get_propagated_names():
63
return self.get_propagated_names()[name]
64
if self.parent is not None:
65
return self.parent._propagated_lookup(name)
66
return None
67
68
def _create_scopes(self):
69
return [pydefined.get_scope()
70
for pydefined in self.pyobject._get_defined_objects()]
71
72
def _get_global_scope(self):
73
current = self
74
while current.parent is not None:
75
current = current.parent
76
return current
77
78
def get_start(self):
79
return self.pyobject.get_ast().lineno
80
81
def get_body_start(self):
82
body = self.pyobject.get_ast().body
83
if body:
84
return body[0].lineno
85
return self.get_start()
86
87
def get_end(self):
88
pymodule = self._get_global_scope().pyobject
89
return pymodule.logical_lines.logical_line_in(self.logical_end)[1]
90
91
@utils.saveit
92
def get_logical_end(self):
93
global_scope = self._get_global_scope()
94
return global_scope._scope_finder.find_scope_end(self)
95
96
start = property(get_start)
97
end = property(get_end)
98
logical_end = property(get_logical_end)
99
100
def get_kind(self):
101
pass
102
103
104
class GlobalScope(Scope):
105
106
def __init__(self, pycore, module):
107
super(GlobalScope, self).__init__(pycore, module, None)
108
self.names = module._get_concluded_data()
109
110
def get_start(self):
111
return 1
112
113
def get_kind(self):
114
return 'Module'
115
116
def get_name(self, name):
117
try:
118
return self.pyobject[name]
119
except exceptions.AttributeNotFoundError:
120
if name in self.builtin_names:
121
return self.builtin_names[name]
122
raise exceptions.NameNotFoundError('name %s not found' % name)
123
124
def get_names(self):
125
if self.names.get() is None:
126
result = dict(self.builtin_names)
127
result.update(super(GlobalScope, self).get_names())
128
self.names.set(result)
129
return self.names.get()
130
131
def get_inner_scope_for_line(self, lineno, indents=None):
132
return self._scope_finder.get_holding_scope(self, lineno, indents)
133
134
def get_inner_scope_for_offset(self, offset):
135
return self._scope_finder.get_holding_scope_for_offset(self, offset)
136
137
@property
138
@utils.saveit
139
def _scope_finder(self):
140
return _HoldingScopeFinder(self.pyobject)
141
142
@property
143
def builtin_names(self):
144
return rope.base.builtins.builtins.get_attributes()
145
146
147
class FunctionScope(Scope):
148
149
def __init__(self, pycore, pyobject, visitor):
150
super(FunctionScope, self).__init__(pycore, pyobject,
151
pyobject.parent.get_scope())
152
self.names = None
153
self.returned_asts = None
154
self.is_generator = None
155
self.defineds = None
156
self.visitor = visitor
157
158
def _get_names(self):
159
if self.names is None:
160
self._visit_function()
161
return self.names
162
163
def _visit_function(self):
164
if self.names is None:
165
new_visitor = self.visitor(self.pycore, self.pyobject)
166
for n in ast.get_child_nodes(self.pyobject.get_ast()):
167
ast.walk(n, new_visitor)
168
self.names = new_visitor.names
169
self.names.update(self.pyobject.get_parameters())
170
self.returned_asts = new_visitor.returned_asts
171
self.is_generator = new_visitor.generator
172
self.defineds = new_visitor.defineds
173
174
def _get_returned_asts(self):
175
if self.names is None:
176
self._visit_function()
177
return self.returned_asts
178
179
def _is_generator(self):
180
if self.is_generator is None:
181
self._get_returned_asts()
182
return self.is_generator
183
184
def get_names(self):
185
return self._get_names()
186
187
def _create_scopes(self):
188
if self.defineds is None:
189
self._visit_function()
190
return [pydefined.get_scope() for pydefined in self.defineds]
191
192
def get_kind(self):
193
return 'Function'
194
195
def invalidate_data(self):
196
for pyname in self.get_names().values():
197
if isinstance(pyname, (rope.base.pynames.AssignedName,
198
rope.base.pynames.EvaluatedName)):
199
pyname.invalidate()
200
201
202
class ClassScope(Scope):
203
204
def __init__(self, pycore, pyobject):
205
super(ClassScope, self).__init__(pycore, pyobject,
206
pyobject.parent.get_scope())
207
208
def get_kind(self):
209
return 'Class'
210
211
def get_propagated_names(self):
212
return {}
213
214
215
class _HoldingScopeFinder(object):
216
217
def __init__(self, pymodule):
218
self.pymodule = pymodule
219
220
def get_indents(self, lineno):
221
return rope.base.codeanalyze.count_line_indents(
222
self.lines.get_line(lineno))
223
224
def _get_scope_indents(self, scope):
225
return self.get_indents(scope.get_start())
226
227
def get_holding_scope(self, module_scope, lineno, line_indents=None):
228
if line_indents is None:
229
line_indents = self.get_indents(lineno)
230
current_scope = module_scope
231
new_scope = current_scope
232
while new_scope is not None and \
233
(new_scope.get_kind() == 'Module' or
234
self._get_scope_indents(new_scope) <= line_indents):
235
current_scope = new_scope
236
if current_scope.get_start() == lineno and \
237
current_scope.get_kind() != 'Module':
238
return current_scope
239
new_scope = None
240
for scope in current_scope.get_scopes():
241
if scope.get_start() <= lineno:
242
if lineno <= scope.get_end():
243
new_scope = scope
244
break
245
else:
246
break
247
return current_scope
248
249
def _is_empty_line(self, lineno):
250
line = self.lines.get_line(lineno)
251
return line.strip() == '' or line.lstrip().startswith('#')
252
253
def _get_body_indents(self, scope):
254
return self.get_indents(scope.get_body_start())
255
256
def get_holding_scope_for_offset(self, scope, offset):
257
return self.get_holding_scope(
258
scope, self.lines.get_line_number(offset))
259
260
def find_scope_end(self, scope):
261
if not scope.parent:
262
return self.lines.length()
263
end = scope.pyobject.get_ast().body[-1].lineno
264
scope_start = self.pymodule.logical_lines.logical_line_in(scope.start)
265
if scope_start[1] >= end:
266
# handling one-liners
267
body_indents = self._get_scope_indents(scope) + 4
268
else:
269
body_indents = self._get_body_indents(scope)
270
for l in self.logical_lines.generate_starts(
271
min(end + 1, self.lines.length()), self.lines.length() + 1):
272
if not self._is_empty_line(l):
273
if self.get_indents(l) < body_indents:
274
return end
275
else:
276
end = l
277
return end
278
279
@property
280
def lines(self):
281
return self.pymodule.lines
282
283
@property
284
def code(self):
285
return self.pymodule.source_code
286
287
@property
288
def logical_lines(self):
289
return self.pymodule.logical_lines
290
291
class TemporaryScope(Scope):
292
"""Currently used for list comprehensions and generator expressions
293
294
These scopes do not appear in the `get_scopes()` method of their
295
parent scopes.
296
"""
297
298
def __init__(self, pycore, parent_scope, names):
299
super(TemporaryScope, self).__init__(
300
pycore, parent_scope.pyobject, parent_scope)
301
self.names = names
302
303
def get_names(self):
304
return self.names
305
306
def get_defined_names(self):
307
return self.names
308
309
def _create_scopes(self):
310
return []
311
312
def get_kind(self):
313
return 'Temporary'
314
315