pyscopes.py 9.5 KB

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