Path: blob/master/elisp/emacs-for-python/rope-dist/rope/base/pyscopes.py
1415 views
import rope.base.builtins1import rope.base.codeanalyze2import rope.base.pynames3from rope.base import ast, exceptions, utils456class Scope(object):78def __init__(self, pycore, pyobject, parent_scope):9self.pycore = pycore10self.pyobject = pyobject11self.parent = parent_scope1213def get_names(self):14"""Return the names defined or imported in this scope"""15return self.pyobject.get_attributes()1617def get_defined_names(self):18"""Return the names defined in this scope"""19return self.pyobject._get_structural_attributes()2021def get_name(self, name):22"""Return name `PyName` defined in this scope"""23if name not in self.get_names():24raise exceptions.NameNotFoundError('name %s not found' % name)25return self.get_names()[name]2627def __getitem__(self, key):28"""The same as ``get_name(key)``"""29return self.get_name(key)3031def __contains__(self, key):32"""The same as ``key in self.get_names()``"""33return key in self.get_names()3435@utils.saveit36def get_scopes(self):37"""Return the subscopes of this scope3839The returned scopes should be sorted by the order they appear.40"""41return self._create_scopes()4243def lookup(self, name):44if name in self.get_names():45return self.get_names()[name]46if self.parent is not None:47return self.parent._propagated_lookup(name)48return None4950def get_propagated_names(self):51"""Return the visible names of this scope5253Return the names defined in this scope that are visible from54scopes containing this scope. This method returns the same55dictionary returned by `get_names()` except for `ClassScope`56which returns an empty dict.57"""58return self.get_names()5960def _propagated_lookup(self, name):61if name in self.get_propagated_names():62return self.get_propagated_names()[name]63if self.parent is not None:64return self.parent._propagated_lookup(name)65return None6667def _create_scopes(self):68return [pydefined.get_scope()69for pydefined in self.pyobject._get_defined_objects()]7071def _get_global_scope(self):72current = self73while current.parent is not None:74current = current.parent75return current7677def get_start(self):78return self.pyobject.get_ast().lineno7980def get_body_start(self):81body = self.pyobject.get_ast().body82if body:83return body[0].lineno84return self.get_start()8586def get_end(self):87pymodule = self._get_global_scope().pyobject88return pymodule.logical_lines.logical_line_in(self.logical_end)[1]8990@utils.saveit91def get_logical_end(self):92global_scope = self._get_global_scope()93return global_scope._scope_finder.find_scope_end(self)9495start = property(get_start)96end = property(get_end)97logical_end = property(get_logical_end)9899def get_kind(self):100pass101102103class GlobalScope(Scope):104105def __init__(self, pycore, module):106super(GlobalScope, self).__init__(pycore, module, None)107self.names = module._get_concluded_data()108109def get_start(self):110return 1111112def get_kind(self):113return 'Module'114115def get_name(self, name):116try:117return self.pyobject[name]118except exceptions.AttributeNotFoundError:119if name in self.builtin_names:120return self.builtin_names[name]121raise exceptions.NameNotFoundError('name %s not found' % name)122123def get_names(self):124if self.names.get() is None:125result = dict(self.builtin_names)126result.update(super(GlobalScope, self).get_names())127self.names.set(result)128return self.names.get()129130def get_inner_scope_for_line(self, lineno, indents=None):131return self._scope_finder.get_holding_scope(self, lineno, indents)132133def get_inner_scope_for_offset(self, offset):134return self._scope_finder.get_holding_scope_for_offset(self, offset)135136@property137@utils.saveit138def _scope_finder(self):139return _HoldingScopeFinder(self.pyobject)140141@property142def builtin_names(self):143return rope.base.builtins.builtins.get_attributes()144145146class FunctionScope(Scope):147148def __init__(self, pycore, pyobject, visitor):149super(FunctionScope, self).__init__(pycore, pyobject,150pyobject.parent.get_scope())151self.names = None152self.returned_asts = None153self.is_generator = None154self.defineds = None155self.visitor = visitor156157def _get_names(self):158if self.names is None:159self._visit_function()160return self.names161162def _visit_function(self):163if self.names is None:164new_visitor = self.visitor(self.pycore, self.pyobject)165for n in ast.get_child_nodes(self.pyobject.get_ast()):166ast.walk(n, new_visitor)167self.names = new_visitor.names168self.names.update(self.pyobject.get_parameters())169self.returned_asts = new_visitor.returned_asts170self.is_generator = new_visitor.generator171self.defineds = new_visitor.defineds172173def _get_returned_asts(self):174if self.names is None:175self._visit_function()176return self.returned_asts177178def _is_generator(self):179if self.is_generator is None:180self._get_returned_asts()181return self.is_generator182183def get_names(self):184return self._get_names()185186def _create_scopes(self):187if self.defineds is None:188self._visit_function()189return [pydefined.get_scope() for pydefined in self.defineds]190191def get_kind(self):192return 'Function'193194def invalidate_data(self):195for pyname in self.get_names().values():196if isinstance(pyname, (rope.base.pynames.AssignedName,197rope.base.pynames.EvaluatedName)):198pyname.invalidate()199200201class ClassScope(Scope):202203def __init__(self, pycore, pyobject):204super(ClassScope, self).__init__(pycore, pyobject,205pyobject.parent.get_scope())206207def get_kind(self):208return 'Class'209210def get_propagated_names(self):211return {}212213214class _HoldingScopeFinder(object):215216def __init__(self, pymodule):217self.pymodule = pymodule218219def get_indents(self, lineno):220return rope.base.codeanalyze.count_line_indents(221self.lines.get_line(lineno))222223def _get_scope_indents(self, scope):224return self.get_indents(scope.get_start())225226def get_holding_scope(self, module_scope, lineno, line_indents=None):227if line_indents is None:228line_indents = self.get_indents(lineno)229current_scope = module_scope230new_scope = current_scope231while new_scope is not None and \232(new_scope.get_kind() == 'Module' or233self._get_scope_indents(new_scope) <= line_indents):234current_scope = new_scope235if current_scope.get_start() == lineno and \236current_scope.get_kind() != 'Module':237return current_scope238new_scope = None239for scope in current_scope.get_scopes():240if scope.get_start() <= lineno:241if lineno <= scope.get_end():242new_scope = scope243break244else:245break246return current_scope247248def _is_empty_line(self, lineno):249line = self.lines.get_line(lineno)250return line.strip() == '' or line.lstrip().startswith('#')251252def _get_body_indents(self, scope):253return self.get_indents(scope.get_body_start())254255def get_holding_scope_for_offset(self, scope, offset):256return self.get_holding_scope(257scope, self.lines.get_line_number(offset))258259def find_scope_end(self, scope):260if not scope.parent:261return self.lines.length()262end = scope.pyobject.get_ast().body[-1].lineno263scope_start = self.pymodule.logical_lines.logical_line_in(scope.start)264if scope_start[1] >= end:265# handling one-liners266body_indents = self._get_scope_indents(scope) + 4267else:268body_indents = self._get_body_indents(scope)269for l in self.logical_lines.generate_starts(270min(end + 1, self.lines.length()), self.lines.length() + 1):271if not self._is_empty_line(l):272if self.get_indents(l) < body_indents:273return end274else:275end = l276return end277278@property279def lines(self):280return self.pymodule.lines281282@property283def code(self):284return self.pymodule.source_code285286@property287def logical_lines(self):288return self.pymodule.logical_lines289290class TemporaryScope(Scope):291"""Currently used for list comprehensions and generator expressions292293These scopes do not appear in the `get_scopes()` method of their294parent scopes.295"""296297def __init__(self, pycore, parent_scope, names):298super(TemporaryScope, self).__init__(299pycore, parent_scope.pyobject, parent_scope)300self.names = names301302def get_names(self):303return self.names304305def get_defined_names(self):306return self.names307308def _create_scopes(self):309return []310311def get_kind(self):312return 'Temporary'313314315