context.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. from abc import abstractmethod
  2. from contextlib import contextmanager
  3. from pathlib import Path
  4. from typing import Optional
  5. from parso.tree import search_ancestor
  6. from parso.python.tree import Name
  7. from jedi.inference.filters import ParserTreeFilter, MergedFilter, \
  8. GlobalNameFilter
  9. from jedi.inference.names import AnonymousParamName, TreeNameDefinition
  10. from jedi.inference.base_value import NO_VALUES, ValueSet
  11. from jedi.parser_utils import get_parent_scope
  12. from jedi import debug
  13. from jedi import parser_utils
  14. class AbstractContext:
  15. # Must be defined: inference_state and tree_node and parent_context as an attribute/property
  16. def __init__(self, inference_state):
  17. self.inference_state = inference_state
  18. self.predefined_names = {}
  19. @abstractmethod
  20. def get_filters(self, until_position=None, origin_scope=None):
  21. raise NotImplementedError
  22. def goto(self, name_or_str, position):
  23. from jedi.inference import finder
  24. filters = _get_global_filters_for_name(
  25. self, name_or_str if isinstance(name_or_str, Name) else None, position,
  26. )
  27. names = finder.filter_name(filters, name_or_str)
  28. debug.dbg('context.goto %s in (%s): %s', name_or_str, self, names)
  29. return names
  30. def py__getattribute__(self, name_or_str, name_context=None, position=None,
  31. analysis_errors=True):
  32. """
  33. :param position: Position of the last statement -> tuple of line, column
  34. """
  35. if name_context is None:
  36. name_context = self
  37. names = self.goto(name_or_str, position)
  38. string_name = name_or_str.value if isinstance(name_or_str, Name) else name_or_str
  39. # This paragraph is currently needed for proper branch type inference
  40. # (static analysis).
  41. found_predefined_types = None
  42. if self.predefined_names and isinstance(name_or_str, Name):
  43. node = name_or_str
  44. while node is not None and not parser_utils.is_scope(node):
  45. node = node.parent
  46. if node.type in ("if_stmt", "for_stmt", "comp_for", 'sync_comp_for'):
  47. try:
  48. name_dict = self.predefined_names[node]
  49. types = name_dict[string_name]
  50. except KeyError:
  51. continue
  52. else:
  53. found_predefined_types = types
  54. break
  55. if found_predefined_types is not None and names:
  56. from jedi.inference import flow_analysis
  57. check = flow_analysis.reachability_check(
  58. context=self,
  59. value_scope=self.tree_node,
  60. node=name_or_str,
  61. )
  62. if check is flow_analysis.UNREACHABLE:
  63. values = NO_VALUES
  64. else:
  65. values = found_predefined_types
  66. else:
  67. values = ValueSet.from_sets(name.infer() for name in names)
  68. if not names and not values and analysis_errors:
  69. if isinstance(name_or_str, Name):
  70. from jedi.inference import analysis
  71. message = ("NameError: name '%s' is not defined." % string_name)
  72. analysis.add(name_context, 'name-error', name_or_str, message)
  73. debug.dbg('context.names_to_types: %s -> %s', names, values)
  74. if values:
  75. return values
  76. return self._check_for_additional_knowledge(name_or_str, name_context, position)
  77. def _check_for_additional_knowledge(self, name_or_str, name_context, position):
  78. name_context = name_context or self
  79. # Add isinstance and other if/assert knowledge.
  80. if isinstance(name_or_str, Name) and not name_context.is_instance():
  81. flow_scope = name_or_str
  82. base_nodes = [name_context.tree_node]
  83. if any(b.type in ('comp_for', 'sync_comp_for') for b in base_nodes):
  84. return NO_VALUES
  85. from jedi.inference.finder import check_flow_information
  86. while True:
  87. flow_scope = get_parent_scope(flow_scope, include_flows=True)
  88. n = check_flow_information(name_context, flow_scope,
  89. name_or_str, position)
  90. if n is not None:
  91. return n
  92. if flow_scope in base_nodes:
  93. break
  94. return NO_VALUES
  95. def get_root_context(self):
  96. parent_context = self.parent_context
  97. if parent_context is None:
  98. return self
  99. return parent_context.get_root_context()
  100. def is_module(self):
  101. return False
  102. def is_builtins_module(self):
  103. return False
  104. def is_class(self):
  105. return False
  106. def is_stub(self):
  107. return False
  108. def is_instance(self):
  109. return False
  110. def is_compiled(self):
  111. return False
  112. def is_bound_method(self):
  113. return False
  114. @abstractmethod
  115. def py__name__(self):
  116. raise NotImplementedError
  117. def get_value(self):
  118. raise NotImplementedError
  119. @property
  120. def name(self):
  121. return None
  122. def get_qualified_names(self):
  123. return ()
  124. def py__doc__(self):
  125. return ''
  126. @contextmanager
  127. def predefine_names(self, flow_scope, dct):
  128. predefined = self.predefined_names
  129. predefined[flow_scope] = dct
  130. try:
  131. yield
  132. finally:
  133. del predefined[flow_scope]
  134. class ValueContext(AbstractContext):
  135. """
  136. Should be defined, otherwise the API returns empty types.
  137. """
  138. def __init__(self, value):
  139. super().__init__(value.inference_state)
  140. self._value = value
  141. @property
  142. def tree_node(self):
  143. return self._value.tree_node
  144. @property
  145. def parent_context(self):
  146. return self._value.parent_context
  147. def is_module(self):
  148. return self._value.is_module()
  149. def is_builtins_module(self):
  150. return self._value == self.inference_state.builtins_module
  151. def is_class(self):
  152. return self._value.is_class()
  153. def is_stub(self):
  154. return self._value.is_stub()
  155. def is_instance(self):
  156. return self._value.is_instance()
  157. def is_compiled(self):
  158. return self._value.is_compiled()
  159. def is_bound_method(self):
  160. return self._value.is_bound_method()
  161. def py__name__(self):
  162. return self._value.py__name__()
  163. @property
  164. def name(self):
  165. return self._value.name
  166. def get_qualified_names(self):
  167. return self._value.get_qualified_names()
  168. def py__doc__(self):
  169. return self._value.py__doc__()
  170. def get_value(self):
  171. return self._value
  172. def __repr__(self):
  173. return '%s(%s)' % (self.__class__.__name__, self._value)
  174. class TreeContextMixin:
  175. def infer_node(self, node):
  176. from jedi.inference.syntax_tree import infer_node
  177. return infer_node(self, node)
  178. def create_value(self, node):
  179. from jedi.inference import value
  180. if node == self.tree_node:
  181. assert self.is_module()
  182. return self.get_value()
  183. parent_context = self.create_context(node)
  184. if node.type in ('funcdef', 'lambdef'):
  185. func = value.FunctionValue.from_context(parent_context, node)
  186. if parent_context.is_class():
  187. class_value = parent_context.parent_context.create_value(parent_context.tree_node)
  188. instance = value.AnonymousInstance(
  189. self.inference_state, parent_context.parent_context, class_value)
  190. func = value.BoundMethod(
  191. instance=instance,
  192. class_context=class_value.as_context(),
  193. function=func
  194. )
  195. return func
  196. elif node.type == 'classdef':
  197. return value.ClassValue(self.inference_state, parent_context, node)
  198. else:
  199. raise NotImplementedError("Probably shouldn't happen: %s" % node)
  200. def create_context(self, node):
  201. def from_scope_node(scope_node, is_nested=True):
  202. if scope_node == self.tree_node:
  203. return self
  204. if scope_node.type in ('funcdef', 'lambdef', 'classdef'):
  205. return self.create_value(scope_node).as_context()
  206. elif scope_node.type in ('comp_for', 'sync_comp_for'):
  207. parent_context = from_scope_node(parent_scope(scope_node.parent))
  208. if node.start_pos >= scope_node.children[-1].start_pos:
  209. return parent_context
  210. return CompForContext(parent_context, scope_node)
  211. raise Exception("There's a scope that was not managed: %s" % scope_node)
  212. def parent_scope(node):
  213. while True:
  214. node = node.parent
  215. if parser_utils.is_scope(node):
  216. return node
  217. elif node.type in ('argument', 'testlist_comp'):
  218. if node.children[1].type in ('comp_for', 'sync_comp_for'):
  219. return node.children[1]
  220. elif node.type == 'dictorsetmaker':
  221. for n in node.children[1:4]:
  222. # In dictionaries it can be pretty much anything.
  223. if n.type in ('comp_for', 'sync_comp_for'):
  224. return n
  225. scope_node = parent_scope(node)
  226. if scope_node.type in ('funcdef', 'classdef'):
  227. colon = scope_node.children[scope_node.children.index(':')]
  228. if node.start_pos < colon.start_pos:
  229. parent = node.parent
  230. if not (parent.type == 'param' and parent.name == node):
  231. scope_node = parent_scope(scope_node)
  232. return from_scope_node(scope_node, is_nested=True)
  233. def create_name(self, tree_name):
  234. definition = tree_name.get_definition()
  235. if definition and definition.type == 'param' and definition.name == tree_name:
  236. funcdef = search_ancestor(definition, 'funcdef', 'lambdef')
  237. func = self.create_value(funcdef)
  238. return AnonymousParamName(func, tree_name)
  239. else:
  240. context = self.create_context(tree_name)
  241. return TreeNameDefinition(context, tree_name)
  242. class FunctionContext(TreeContextMixin, ValueContext):
  243. def get_filters(self, until_position=None, origin_scope=None):
  244. yield ParserTreeFilter(
  245. self.inference_state,
  246. parent_context=self,
  247. until_position=until_position,
  248. origin_scope=origin_scope
  249. )
  250. class ModuleContext(TreeContextMixin, ValueContext):
  251. def py__file__(self) -> Optional[Path]:
  252. return self._value.py__file__() # type: ignore[no-any-return]
  253. def get_filters(self, until_position=None, origin_scope=None):
  254. filters = self._value.get_filters(origin_scope)
  255. # Skip the first filter and replace it.
  256. next(filters, None)
  257. yield MergedFilter(
  258. ParserTreeFilter(
  259. parent_context=self,
  260. until_position=until_position,
  261. origin_scope=origin_scope
  262. ),
  263. self.get_global_filter(),
  264. )
  265. yield from filters
  266. def get_global_filter(self):
  267. return GlobalNameFilter(self)
  268. @property
  269. def string_names(self):
  270. return self._value.string_names
  271. @property
  272. def code_lines(self):
  273. return self._value.code_lines
  274. def get_value(self):
  275. """
  276. This is the only function that converts a context back to a value.
  277. This is necessary for stub -> python conversion and vice versa. However
  278. this method shouldn't be moved to AbstractContext.
  279. """
  280. return self._value
  281. class NamespaceContext(TreeContextMixin, ValueContext):
  282. def get_filters(self, until_position=None, origin_scope=None):
  283. return self._value.get_filters()
  284. def get_value(self):
  285. return self._value
  286. @property
  287. def string_names(self):
  288. return self._value.string_names
  289. def py__file__(self) -> Optional[Path]:
  290. return self._value.py__file__() # type: ignore[no-any-return]
  291. class ClassContext(TreeContextMixin, ValueContext):
  292. def get_filters(self, until_position=None, origin_scope=None):
  293. yield self.get_global_filter(until_position, origin_scope)
  294. def get_global_filter(self, until_position=None, origin_scope=None):
  295. return ParserTreeFilter(
  296. parent_context=self,
  297. until_position=until_position,
  298. origin_scope=origin_scope
  299. )
  300. class CompForContext(TreeContextMixin, AbstractContext):
  301. def __init__(self, parent_context, comp_for):
  302. super().__init__(parent_context.inference_state)
  303. self.tree_node = comp_for
  304. self.parent_context = parent_context
  305. def get_filters(self, until_position=None, origin_scope=None):
  306. yield ParserTreeFilter(self)
  307. def get_value(self):
  308. return None
  309. def py__name__(self):
  310. return '<comprehension context>'
  311. def __repr__(self):
  312. return '%s(%s)' % (self.__class__.__name__, self.tree_node)
  313. class CompiledContext(ValueContext):
  314. def get_filters(self, until_position=None, origin_scope=None):
  315. return self._value.get_filters()
  316. class CompiledModuleContext(CompiledContext):
  317. code_lines = None
  318. def get_value(self):
  319. return self._value
  320. @property
  321. def string_names(self):
  322. return self._value.string_names
  323. def py__file__(self) -> Optional[Path]:
  324. return self._value.py__file__() # type: ignore[no-any-return]
  325. def _get_global_filters_for_name(context, name_or_none, position):
  326. # For functions and classes the defaults don't belong to the
  327. # function and get inferred in the value before the function. So
  328. # make sure to exclude the function/class name.
  329. if name_or_none is not None:
  330. ancestor = search_ancestor(name_or_none, 'funcdef', 'classdef', 'lambdef')
  331. lambdef = None
  332. if ancestor == 'lambdef':
  333. # For lambdas it's even more complicated since parts will
  334. # be inferred later.
  335. lambdef = ancestor
  336. ancestor = search_ancestor(name_or_none, 'funcdef', 'classdef')
  337. if ancestor is not None:
  338. colon = ancestor.children[-2]
  339. if position is not None and position < colon.start_pos:
  340. if lambdef is None or position < lambdef.children[-2].start_pos:
  341. position = ancestor.start_pos
  342. return get_global_filters(context, position, name_or_none)
  343. def get_global_filters(context, until_position, origin_scope):
  344. """
  345. Returns all filters in order of priority for name resolution.
  346. For global name lookups. The filters will handle name resolution
  347. themselves, but here we gather possible filters downwards.
  348. >>> from jedi import Script
  349. >>> script = Script('''
  350. ... x = ['a', 'b', 'c']
  351. ... def func():
  352. ... y = None
  353. ... ''')
  354. >>> module_node = script._module_node
  355. >>> scope = next(module_node.iter_funcdefs())
  356. >>> scope
  357. <Function: func@3-5>
  358. >>> context = script._get_module_context().create_context(scope)
  359. >>> filters = list(get_global_filters(context, (4, 0), None))
  360. First we get the names from the function scope.
  361. >>> print(filters[0]) # doctest: +ELLIPSIS
  362. MergedFilter(<ParserTreeFilter: ...>, <GlobalNameFilter: ...>)
  363. >>> sorted(str(n) for n in filters[0].values()) # doctest: +NORMALIZE_WHITESPACE
  364. ['<TreeNameDefinition: string_name=func start_pos=(3, 4)>',
  365. '<TreeNameDefinition: string_name=x start_pos=(2, 0)>']
  366. >>> filters[0]._filters[0]._until_position
  367. (4, 0)
  368. >>> filters[0]._filters[1]._until_position
  369. Then it yields the names from one level "lower". In this example, this is
  370. the module scope (including globals).
  371. As a side note, you can see, that the position in the filter is None on the
  372. globals filter, because there the whole module is searched.
  373. >>> list(filters[1].values()) # package modules -> Also empty.
  374. []
  375. >>> sorted(name.string_name for name in filters[2].values()) # Module attributes
  376. ['__doc__', '__name__', '__package__']
  377. Finally, it yields the builtin filter, if `include_builtin` is
  378. true (default).
  379. >>> list(filters[3].values()) # doctest: +ELLIPSIS
  380. [...]
  381. """
  382. base_context = context
  383. from jedi.inference.value.function import BaseFunctionExecutionContext
  384. while context is not None:
  385. # Names in methods cannot be resolved within the class.
  386. yield from context.get_filters(
  387. until_position=until_position,
  388. origin_scope=origin_scope
  389. )
  390. if isinstance(context, (BaseFunctionExecutionContext, ModuleContext)):
  391. # The position should be reset if the current scope is a function.
  392. until_position = None
  393. context = context.parent_context
  394. b = next(base_context.inference_state.builtins_module.get_filters(), None)
  395. assert b is not None
  396. # Add builtins to the global scope.
  397. yield b