]> crepu.dev Git - config.git/blame_incremental - djavu-asus/elpy/rpc-venv/lib/python3.11/site-packages/jedi/inference/names.py
ActualizaciĆ³n de Readme
[config.git] / djavu-asus / elpy / rpc-venv / lib / python3.11 / site-packages / jedi / inference / names.py
... / ...
CommitLineData
1from abc import abstractmethod
2from inspect import Parameter
3from typing import Optional, Tuple
4
5from parso.tree import search_ancestor
6
7from jedi.parser_utils import find_statement_documentation, clean_scope_docstring
8from jedi.inference.utils import unite
9from jedi.inference.base_value import ValueSet, NO_VALUES
10from jedi.inference.cache import inference_state_method_cache
11from jedi.inference import docstrings
12from jedi.cache import memoize_method
13from jedi.inference.helpers import deep_ast_copy, infer_call_of_leaf
14from jedi.plugins import plugin_manager
15
16
17def _merge_name_docs(names):
18 doc = ''
19 for name in names:
20 if doc:
21 # In case we have multiple values, just return all of them
22 # separated by a few dashes.
23 doc += '\n' + '-' * 30 + '\n'
24 doc += name.py__doc__()
25 return doc
26
27
28class AbstractNameDefinition:
29 start_pos: Optional[Tuple[int, int]] = None
30 string_name: str
31 parent_context = None
32 tree_name = None
33 is_value_name = True
34 """
35 Used for the Jedi API to know if it's a keyword or an actual name.
36 """
37
38 @abstractmethod
39 def infer(self):
40 raise NotImplementedError
41
42 @abstractmethod
43 def goto(self):
44 # Typically names are already definitions and therefore a goto on that
45 # name will always result on itself.
46 return {self}
47
48 def get_qualified_names(self, include_module_names=False):
49 qualified_names = self._get_qualified_names()
50 if qualified_names is None or not include_module_names:
51 return qualified_names
52
53 module_names = self.get_root_context().string_names
54 if module_names is None:
55 return None
56 return module_names + qualified_names
57
58 def _get_qualified_names(self):
59 # By default, a name has no qualified names.
60 return None
61
62 def get_root_context(self):
63 return self.parent_context.get_root_context()
64
65 def get_public_name(self):
66 return self.string_name
67
68 def __repr__(self):
69 if self.start_pos is None:
70 return '<%s: string_name=%s>' % (self.__class__.__name__, self.string_name)
71 return '<%s: string_name=%s start_pos=%s>' % (self.__class__.__name__,
72 self.string_name, self.start_pos)
73
74 def is_import(self):
75 return False
76
77 def py__doc__(self):
78 return ''
79
80 @property
81 def api_type(self):
82 return self.parent_context.api_type
83
84 def get_defining_qualified_value(self):
85 """
86 Returns either None or the value that is public and qualified. Won't
87 return a function, because a name in a function is never public.
88 """
89 return None
90
91
92class AbstractArbitraryName(AbstractNameDefinition):
93 """
94 When you e.g. want to complete dicts keys, you probably want to complete
95 string literals, which is not really a name, but for Jedi we use this
96 concept of Name for completions as well.
97 """
98 is_value_name = False
99
100 def __init__(self, inference_state, string):
101 self.inference_state = inference_state
102 self.string_name = string
103 self.parent_context = inference_state.builtins_module
104
105 def infer(self):
106 return NO_VALUES
107
108
109class AbstractTreeName(AbstractNameDefinition):
110 def __init__(self, parent_context, tree_name):
111 self.parent_context = parent_context
112 self.tree_name = tree_name
113
114 def get_qualified_names(self, include_module_names=False):
115 import_node = search_ancestor(self.tree_name, 'import_name', 'import_from')
116 # For import nodes we cannot just have names, because it's very unclear
117 # how they would look like. For now we just ignore them in most cases.
118 # In case of level == 1, it works always, because it's like a submodule
119 # lookup.
120 if import_node is not None and not (import_node.level == 1
121 and self.get_root_context().get_value().is_package()):
122 # TODO improve the situation for when level is present.
123 if include_module_names and not import_node.level:
124 return tuple(n.value for n in import_node.get_path_for_name(self.tree_name))
125 else:
126 return None
127
128 return super().get_qualified_names(include_module_names)
129
130 def _get_qualified_names(self):
131 parent_names = self.parent_context.get_qualified_names()
132 if parent_names is None:
133 return None
134 return parent_names + (self.tree_name.value,)
135
136 def get_defining_qualified_value(self):
137 if self.is_import():
138 raise NotImplementedError("Shouldn't really happen, please report")
139 elif self.parent_context:
140 return self.parent_context.get_value() # Might be None
141 return None
142
143 def goto(self):
144 context = self.parent_context
145 name = self.tree_name
146 definition = name.get_definition(import_name_always=True)
147 if definition is not None:
148 type_ = definition.type
149 if type_ == 'expr_stmt':
150 # Only take the parent, because if it's more complicated than just
151 # a name it's something you can "goto" again.
152 is_simple_name = name.parent.type not in ('power', 'trailer')
153 if is_simple_name:
154 return [self]
155 elif type_ in ('import_from', 'import_name'):
156 from jedi.inference.imports import goto_import
157 module_names = goto_import(context, name)
158 return module_names
159 else:
160 return [self]
161 else:
162 from jedi.inference.imports import follow_error_node_imports_if_possible
163 values = follow_error_node_imports_if_possible(context, name)
164 if values is not None:
165 return [value.name for value in values]
166
167 par = name.parent
168 node_type = par.type
169 if node_type == 'argument' and par.children[1] == '=' and par.children[0] == name:
170 # Named param goto.
171 trailer = par.parent
172 if trailer.type == 'arglist':
173 trailer = trailer.parent
174 if trailer.type != 'classdef':
175 if trailer.type == 'decorator':
176 value_set = context.infer_node(trailer.children[1])
177 else:
178 i = trailer.parent.children.index(trailer)
179 to_infer = trailer.parent.children[:i]
180 if to_infer[0] == 'await':
181 to_infer.pop(0)
182 value_set = context.infer_node(to_infer[0])
183 from jedi.inference.syntax_tree import infer_trailer
184 for trailer in to_infer[1:]:
185 value_set = infer_trailer(context, value_set, trailer)
186 param_names = []
187 for value in value_set:
188 for signature in value.get_signatures():
189 for param_name in signature.get_param_names():
190 if param_name.string_name == name.value:
191 param_names.append(param_name)
192 return param_names
193 elif node_type == 'dotted_name': # Is a decorator.
194 index = par.children.index(name)
195 if index > 0:
196 new_dotted = deep_ast_copy(par)
197 new_dotted.children[index - 1:] = []
198 values = context.infer_node(new_dotted)
199 return unite(
200 value.goto(name, name_context=context)
201 for value in values
202 )
203
204 if node_type == 'trailer' and par.children[0] == '.':
205 values = infer_call_of_leaf(context, name, cut_own_trailer=True)
206 return values.goto(name, name_context=context)
207 else:
208 stmt = search_ancestor(
209 name, 'expr_stmt', 'lambdef'
210 ) or name
211 if stmt.type == 'lambdef':
212 stmt = name
213 return context.goto(name, position=stmt.start_pos)
214
215 def is_import(self):
216 imp = search_ancestor(self.tree_name, 'import_from', 'import_name')
217 return imp is not None
218
219 @property
220 def string_name(self):
221 return self.tree_name.value
222
223 @property
224 def start_pos(self):
225 return self.tree_name.start_pos
226
227
228class ValueNameMixin:
229 def infer(self):
230 return ValueSet([self._value])
231
232 def py__doc__(self):
233 doc = self._value.py__doc__()
234 if not doc and self._value.is_stub():
235 from jedi.inference.gradual.conversion import convert_names
236 names = convert_names([self], prefer_stub_to_compiled=False)
237 if self not in names:
238 return _merge_name_docs(names)
239 return doc
240
241 def _get_qualified_names(self):
242 return self._value.get_qualified_names()
243
244 def get_root_context(self):
245 if self.parent_context is None: # A module
246 return self._value.as_context()
247 return super().get_root_context()
248
249 def get_defining_qualified_value(self):
250 context = self.parent_context
251 if context is not None and (context.is_module() or context.is_class()):
252 return self.parent_context.get_value() # Might be None
253 return None
254
255 @property
256 def api_type(self):
257 return self._value.api_type
258
259
260class ValueName(ValueNameMixin, AbstractTreeName):
261 def __init__(self, value, tree_name):
262 super().__init__(value.parent_context, tree_name)
263 self._value = value
264
265 def goto(self):
266 return ValueSet([self._value.name])
267
268
269class TreeNameDefinition(AbstractTreeName):
270 _API_TYPES = dict(
271 import_name='module',
272 import_from='module',
273 funcdef='function',
274 param='param',
275 classdef='class',
276 )
277
278 def infer(self):
279 # Refactor this, should probably be here.
280 from jedi.inference.syntax_tree import tree_name_to_values
281 return tree_name_to_values(
282 self.parent_context.inference_state,
283 self.parent_context,
284 self.tree_name
285 )
286
287 @property
288 def api_type(self):
289 definition = self.tree_name.get_definition(import_name_always=True)
290 if definition is None:
291 return 'statement'
292 return self._API_TYPES.get(definition.type, 'statement')
293
294 def assignment_indexes(self):
295 """
296 Returns an array of tuple(int, node) of the indexes that are used in
297 tuple assignments.
298
299 For example if the name is ``y`` in the following code::
300
301 x, (y, z) = 2, ''
302
303 would result in ``[(1, xyz_node), (0, yz_node)]``.
304
305 When searching for b in the case ``a, *b, c = [...]`` it will return::
306
307 [(slice(1, -1), abc_node)]
308 """
309 indexes = []
310 is_star_expr = False
311 node = self.tree_name.parent
312 compare = self.tree_name
313 while node is not None:
314 if node.type in ('testlist', 'testlist_comp', 'testlist_star_expr', 'exprlist'):
315 for i, child in enumerate(node.children):
316 if child == compare:
317 index = int(i / 2)
318 if is_star_expr:
319 from_end = int((len(node.children) - i) / 2)
320 index = slice(index, -from_end)
321 indexes.insert(0, (index, node))
322 break
323 else:
324 raise LookupError("Couldn't find the assignment.")
325 is_star_expr = False
326 elif node.type == 'star_expr':
327 is_star_expr = True
328 elif node.type in ('expr_stmt', 'sync_comp_for'):
329 break
330
331 compare = node
332 node = node.parent
333 return indexes
334
335 @property
336 def inference_state(self):
337 # Used by the cache function below
338 return self.parent_context.inference_state
339
340 @inference_state_method_cache(default='')
341 def py__doc__(self):
342 api_type = self.api_type
343 if api_type in ('function', 'class', 'property'):
344 if self.parent_context.get_root_context().is_stub():
345 from jedi.inference.gradual.conversion import convert_names
346 names = convert_names([self], prefer_stub_to_compiled=False)
347 if self not in names:
348 return _merge_name_docs(names)
349
350 # Make sure the names are not TreeNameDefinitions anymore.
351 return clean_scope_docstring(self.tree_name.get_definition())
352
353 if api_type == 'module':
354 names = self.goto()
355 if self not in names:
356 return _merge_name_docs(names)
357
358 if api_type == 'statement' and self.tree_name.is_definition():
359 return find_statement_documentation(self.tree_name.get_definition())
360 return ''
361
362
363class _ParamMixin:
364 def maybe_positional_argument(self, include_star=True):
365 options = [Parameter.POSITIONAL_ONLY, Parameter.POSITIONAL_OR_KEYWORD]
366 if include_star:
367 options.append(Parameter.VAR_POSITIONAL)
368 return self.get_kind() in options
369
370 def maybe_keyword_argument(self, include_stars=True):
371 options = [Parameter.KEYWORD_ONLY, Parameter.POSITIONAL_OR_KEYWORD]
372 if include_stars:
373 options.append(Parameter.VAR_KEYWORD)
374 return self.get_kind() in options
375
376 def _kind_string(self):
377 kind = self.get_kind()
378 if kind == Parameter.VAR_POSITIONAL: # *args
379 return '*'
380 if kind == Parameter.VAR_KEYWORD: # **kwargs
381 return '**'
382 return ''
383
384 def get_qualified_names(self, include_module_names=False):
385 return None
386
387
388class ParamNameInterface(_ParamMixin):
389 api_type = 'param'
390
391 def get_kind(self):
392 raise NotImplementedError
393
394 def to_string(self):
395 raise NotImplementedError
396
397 def get_executed_param_name(self):
398 """
399 For dealing with type inference and working around the graph, we
400 sometimes want to have the param name of the execution. This feels a
401 bit strange and we might have to refactor at some point.
402
403 For now however it exists to avoid infering params when we don't really
404 need them (e.g. when we can just instead use annotations.
405 """
406 return None
407
408 @property
409 def star_count(self):
410 kind = self.get_kind()
411 if kind == Parameter.VAR_POSITIONAL:
412 return 1
413 if kind == Parameter.VAR_KEYWORD:
414 return 2
415 return 0
416
417 def infer_default(self):
418 return NO_VALUES
419
420
421class BaseTreeParamName(ParamNameInterface, AbstractTreeName):
422 annotation_node = None
423 default_node = None
424
425 def to_string(self):
426 output = self._kind_string() + self.get_public_name()
427 annotation = self.annotation_node
428 default = self.default_node
429 if annotation is not None:
430 output += ': ' + annotation.get_code(include_prefix=False)
431 if default is not None:
432 output += '=' + default.get_code(include_prefix=False)
433 return output
434
435 def get_public_name(self):
436 name = self.string_name
437 if name.startswith('__'):
438 # Params starting with __ are an equivalent to positional only
439 # variables in typeshed.
440 name = name[2:]
441 return name
442
443 def goto(self, **kwargs):
444 return [self]
445
446
447class _ActualTreeParamName(BaseTreeParamName):
448 def __init__(self, function_value, tree_name):
449 super().__init__(
450 function_value.get_default_param_context(), tree_name)
451 self.function_value = function_value
452
453 def _get_param_node(self):
454 return search_ancestor(self.tree_name, 'param')
455
456 @property
457 def annotation_node(self):
458 return self._get_param_node().annotation
459
460 def infer_annotation(self, execute_annotation=True, ignore_stars=False):
461 from jedi.inference.gradual.annotation import infer_param
462 values = infer_param(
463 self.function_value, self._get_param_node(),
464 ignore_stars=ignore_stars)
465 if execute_annotation:
466 values = values.execute_annotation()
467 return values
468
469 def infer_default(self):
470 node = self.default_node
471 if node is None:
472 return NO_VALUES
473 return self.parent_context.infer_node(node)
474
475 @property
476 def default_node(self):
477 return self._get_param_node().default
478
479 def get_kind(self):
480 tree_param = self._get_param_node()
481 if tree_param.star_count == 1: # *args
482 return Parameter.VAR_POSITIONAL
483 if tree_param.star_count == 2: # **kwargs
484 return Parameter.VAR_KEYWORD
485
486 # Params starting with __ are an equivalent to positional only
487 # variables in typeshed.
488 if tree_param.name.value.startswith('__'):
489 return Parameter.POSITIONAL_ONLY
490
491 parent = tree_param.parent
492 param_appeared = False
493 for p in parent.children:
494 if param_appeared:
495 if p == '/':
496 return Parameter.POSITIONAL_ONLY
497 else:
498 if p == '*':
499 return Parameter.KEYWORD_ONLY
500 if p.type == 'param':
501 if p.star_count:
502 return Parameter.KEYWORD_ONLY
503 if p == tree_param:
504 param_appeared = True
505 return Parameter.POSITIONAL_OR_KEYWORD
506
507 def infer(self):
508 values = self.infer_annotation()
509 if values:
510 return values
511
512 doc_params = docstrings.infer_param(self.function_value, self._get_param_node())
513 return doc_params
514
515
516class AnonymousParamName(_ActualTreeParamName):
517 @plugin_manager.decorate(name='goto_anonymous_param')
518 def goto(self):
519 return super().goto()
520
521 @plugin_manager.decorate(name='infer_anonymous_param')
522 def infer(self):
523 values = super().infer()
524 if values:
525 return values
526 from jedi.inference.dynamic_params import dynamic_param_lookup
527 param = self._get_param_node()
528 values = dynamic_param_lookup(self.function_value, param.position_index)
529 if values:
530 return values
531
532 if param.star_count == 1:
533 from jedi.inference.value.iterable import FakeTuple
534 value = FakeTuple(self.function_value.inference_state, [])
535 elif param.star_count == 2:
536 from jedi.inference.value.iterable import FakeDict
537 value = FakeDict(self.function_value.inference_state, {})
538 elif param.default is None:
539 return NO_VALUES
540 else:
541 return self.function_value.parent_context.infer_node(param.default)
542 return ValueSet({value})
543
544
545class ParamName(_ActualTreeParamName):
546 def __init__(self, function_value, tree_name, arguments):
547 super().__init__(function_value, tree_name)
548 self.arguments = arguments
549
550 def infer(self):
551 values = super().infer()
552 if values:
553 return values
554
555 return self.get_executed_param_name().infer()
556
557 def get_executed_param_name(self):
558 from jedi.inference.param import get_executed_param_names
559 params_names = get_executed_param_names(self.function_value, self.arguments)
560 return params_names[self._get_param_node().position_index]
561
562
563class ParamNameWrapper(_ParamMixin):
564 def __init__(self, param_name):
565 self._wrapped_param_name = param_name
566
567 def __getattr__(self, name):
568 return getattr(self._wrapped_param_name, name)
569
570 def __repr__(self):
571 return '<%s: %s>' % (self.__class__.__name__, self._wrapped_param_name)
572
573
574class ImportName(AbstractNameDefinition):
575 start_pos = (1, 0)
576 _level = 0
577
578 def __init__(self, parent_context, string_name):
579 self._from_module_context = parent_context
580 self.string_name = string_name
581
582 def get_qualified_names(self, include_module_names=False):
583 if include_module_names:
584 if self._level:
585 assert self._level == 1, "Everything else is not supported for now"
586 module_names = self._from_module_context.string_names
587 if module_names is None:
588 return module_names
589 return module_names + (self.string_name,)
590 return (self.string_name,)
591 return ()
592
593 @property
594 def parent_context(self):
595 m = self._from_module_context
596 import_values = self.infer()
597 if not import_values:
598 return m
599 # It's almost always possible to find the import or to not find it. The
600 # importing returns only one value, pretty much always.
601 return next(iter(import_values)).as_context()
602
603 @memoize_method
604 def infer(self):
605 from jedi.inference.imports import Importer
606 m = self._from_module_context
607 return Importer(m.inference_state, [self.string_name], m, level=self._level).follow()
608
609 def goto(self):
610 return [m.name for m in self.infer()]
611
612 @property
613 def api_type(self):
614 return 'module'
615
616 def py__doc__(self):
617 return _merge_name_docs(self.goto())
618
619
620class SubModuleName(ImportName):
621 _level = 1
622
623
624class NameWrapper:
625 def __init__(self, wrapped_name):
626 self._wrapped_name = wrapped_name
627
628 def __getattr__(self, name):
629 return getattr(self._wrapped_name, name)
630
631 def __repr__(self):
632 return '%s(%s)' % (self.__class__.__name__, self._wrapped_name)
633
634
635class StubNameMixin:
636 def py__doc__(self):
637 from jedi.inference.gradual.conversion import convert_names
638 # Stubs are not complicated and we can just follow simple statements
639 # that have an equals in them, because they typically make something
640 # else public. See e.g. stubs for `requests`.
641 names = [self]
642 if self.api_type == 'statement' and '=' in self.tree_name.get_definition().children:
643 names = [v.name for v in self.infer()]
644
645 names = convert_names(names, prefer_stub_to_compiled=False)
646 if self in names:
647 return super().py__doc__()
648 else:
649 # We have signatures ourselves in stubs, so don't use signatures
650 # from the implementation.
651 return _merge_name_docs(names)
652
653
654# From here on down we make looking up the sys.version_info fast.
655class StubName(StubNameMixin, TreeNameDefinition):
656 def infer(self):
657 inferred = super().infer()
658 if self.string_name == 'version_info' and self.get_root_context().py__name__() == 'sys':
659 from jedi.inference.gradual.stub_value import VersionInfo
660 return ValueSet(VersionInfo(c) for c in inferred)
661 return inferred
662
663
664class ModuleName(ValueNameMixin, AbstractNameDefinition):
665 start_pos = 1, 0
666
667 def __init__(self, value, name):
668 self._value = value
669 self._name = name
670
671 @property
672 def string_name(self):
673 return self._name
674
675
676class StubModuleName(StubNameMixin, ModuleName):
677 pass