]> crepu.dev Git - config.git/blame - djavu-asus/elpy/rpc-venv/lib/python3.11/site-packages/jedi/api/completion.py
Configuracion en desarrollo PC pega
[config.git] / djavu-asus / elpy / rpc-venv / lib / python3.11 / site-packages / jedi / api / completion.py
CommitLineData
53e6db90
DC
1import re
2from textwrap import dedent
3from inspect import Parameter
4
5from parso.python.token import PythonTokenTypes
6from parso.python import tree
7from parso.tree import search_ancestor, Leaf
8from parso import split_lines
9
10from jedi import debug
11from jedi import settings
12from jedi.api import classes
13from jedi.api import helpers
14from jedi.api import keywords
15from jedi.api.strings import complete_dict
16from jedi.api.file_name import complete_file_name
17from jedi.inference import imports
18from jedi.inference.base_value import ValueSet
19from jedi.inference.helpers import infer_call_of_leaf, parse_dotted_names
20from jedi.inference.context import get_global_filters
21from jedi.inference.value import TreeInstance
22from jedi.inference.docstring_utils import DocstringModule
23from jedi.inference.names import ParamNameWrapper, SubModuleName
24from jedi.inference.gradual.conversion import convert_values, convert_names
25from jedi.parser_utils import cut_value_at_position
26from jedi.plugins import plugin_manager
27
28
29class ParamNameWithEquals(ParamNameWrapper):
30 def get_public_name(self):
31 return self.string_name + '='
32
33
34def _get_signature_param_names(signatures, positional_count, used_kwargs):
35 # Add named params
36 for call_sig in signatures:
37 for i, p in enumerate(call_sig.params):
38 kind = p.kind
39 if i < positional_count and kind == Parameter.POSITIONAL_OR_KEYWORD:
40 continue
41 if kind in (Parameter.POSITIONAL_OR_KEYWORD, Parameter.KEYWORD_ONLY) \
42 and p.name not in used_kwargs:
43 yield ParamNameWithEquals(p._name)
44
45
46def _must_be_kwarg(signatures, positional_count, used_kwargs):
47 if used_kwargs:
48 return True
49
50 must_be_kwarg = True
51 for signature in signatures:
52 for i, p in enumerate(signature.params):
53 kind = p.kind
54 if kind is Parameter.VAR_POSITIONAL:
55 # In case there were not already kwargs, the next param can
56 # always be a normal argument.
57 return False
58
59 if i >= positional_count and kind in (Parameter.POSITIONAL_OR_KEYWORD,
60 Parameter.POSITIONAL_ONLY):
61 must_be_kwarg = False
62 break
63 if not must_be_kwarg:
64 break
65 return must_be_kwarg
66
67
68def filter_names(inference_state, completion_names, stack, like_name, fuzzy, cached_name):
69 comp_dct = set()
70 if settings.case_insensitive_completion:
71 like_name = like_name.lower()
72 for name in completion_names:
73 string = name.string_name
74 if settings.case_insensitive_completion:
75 string = string.lower()
76 if helpers.match(string, like_name, fuzzy=fuzzy):
77 new = classes.Completion(
78 inference_state,
79 name,
80 stack,
81 len(like_name),
82 is_fuzzy=fuzzy,
83 cached_name=cached_name,
84 )
85 k = (new.name, new.complete) # key
86 if k not in comp_dct:
87 comp_dct.add(k)
88 tree_name = name.tree_name
89 if tree_name is not None:
90 definition = tree_name.get_definition()
91 if definition is not None and definition.type == 'del_stmt':
92 continue
93 yield new
94
95
96def _remove_duplicates(completions, other_completions):
97 names = {d.name for d in other_completions}
98 return [c for c in completions if c.name not in names]
99
100
101def get_user_context(module_context, position):
102 """
103 Returns the scope in which the user resides. This includes flows.
104 """
105 leaf = module_context.tree_node.get_leaf_for_position(position, include_prefixes=True)
106 return module_context.create_context(leaf)
107
108
109def get_flow_scope_node(module_node, position):
110 node = module_node.get_leaf_for_position(position, include_prefixes=True)
111 while not isinstance(node, (tree.Scope, tree.Flow)):
112 node = node.parent
113
114 return node
115
116
117@plugin_manager.decorate()
118def complete_param_names(context, function_name, decorator_nodes):
119 # Basically there's no way to do param completion. The plugins are
120 # responsible for this.
121 return []
122
123
124class Completion:
125 def __init__(self, inference_state, module_context, code_lines, position,
126 signatures_callback, fuzzy=False):
127 self._inference_state = inference_state
128 self._module_context = module_context
129 self._module_node = module_context.tree_node
130 self._code_lines = code_lines
131
132 # The first step of completions is to get the name
133 self._like_name = helpers.get_on_completion_name(self._module_node, code_lines, position)
134 # The actual cursor position is not what we need to calculate
135 # everything. We want the start of the name we're on.
136 self._original_position = position
137 self._signatures_callback = signatures_callback
138
139 self._fuzzy = fuzzy
140
141 def complete(self):
142 leaf = self._module_node.get_leaf_for_position(
143 self._original_position,
144 include_prefixes=True
145 )
146 string, start_leaf, quote = _extract_string_while_in_string(leaf, self._original_position)
147
148 prefixed_completions = complete_dict(
149 self._module_context,
150 self._code_lines,
151 start_leaf or leaf,
152 self._original_position,
153 None if string is None else quote + string,
154 fuzzy=self._fuzzy,
155 )
156
157 if string is not None and not prefixed_completions:
158 prefixed_completions = list(complete_file_name(
159 self._inference_state, self._module_context, start_leaf, quote, string,
160 self._like_name, self._signatures_callback,
161 self._code_lines, self._original_position,
162 self._fuzzy
163 ))
164 if string is not None:
165 if not prefixed_completions and '\n' in string:
166 # Complete only multi line strings
167 prefixed_completions = self._complete_in_string(start_leaf, string)
168 return prefixed_completions
169
170 cached_name, completion_names = self._complete_python(leaf)
171
172 completions = list(filter_names(self._inference_state, completion_names,
173 self.stack, self._like_name,
174 self._fuzzy, cached_name=cached_name))
175
176 return (
177 # Removing duplicates mostly to remove False/True/None duplicates.
178 _remove_duplicates(prefixed_completions, completions)
179 + sorted(completions, key=lambda x: (x.name.startswith('__'),
180 x.name.startswith('_'),
181 x.name.lower()))
182 )
183
184 def _complete_python(self, leaf):
185 """
186 Analyzes the current context of a completion and decides what to
187 return.
188
189 Technically this works by generating a parser stack and analysing the
190 current stack for possible grammar nodes.
191
192 Possible enhancements:
193 - global/nonlocal search global
194 - yield from / raise from <- could be only exceptions/generators
195 - In args: */**: no completion
196 - In params (also lambda): no completion before =
197 """
198 grammar = self._inference_state.grammar
199 self.stack = stack = None
200 self._position = (
201 self._original_position[0],
202 self._original_position[1] - len(self._like_name)
203 )
204 cached_name = None
205
206 try:
207 self.stack = stack = helpers.get_stack_at_position(
208 grammar, self._code_lines, leaf, self._position
209 )
210 except helpers.OnErrorLeaf as e:
211 value = e.error_leaf.value
212 if value == '.':
213 # After ErrorLeaf's that are dots, we will not do any
214 # completions since this probably just confuses the user.
215 return cached_name, []
216
217 # If we don't have a value, just use global completion.
218 return cached_name, self._complete_global_scope()
219
220 allowed_transitions = \
221 list(stack._allowed_transition_names_and_token_types())
222
223 if 'if' in allowed_transitions:
224 leaf = self._module_node.get_leaf_for_position(self._position, include_prefixes=True)
225 previous_leaf = leaf.get_previous_leaf()
226
227 indent = self._position[1]
228 if not (leaf.start_pos <= self._position <= leaf.end_pos):
229 indent = leaf.start_pos[1]
230
231 if previous_leaf is not None:
232 stmt = previous_leaf
233 while True:
234 stmt = search_ancestor(
235 stmt, 'if_stmt', 'for_stmt', 'while_stmt', 'try_stmt',
236 'error_node',
237 )
238 if stmt is None:
239 break
240
241 type_ = stmt.type
242 if type_ == 'error_node':
243 first = stmt.children[0]
244 if isinstance(first, Leaf):
245 type_ = first.value + '_stmt'
246 # Compare indents
247 if stmt.start_pos[1] == indent:
248 if type_ == 'if_stmt':
249 allowed_transitions += ['elif', 'else']
250 elif type_ == 'try_stmt':
251 allowed_transitions += ['except', 'finally', 'else']
252 elif type_ == 'for_stmt':
253 allowed_transitions.append('else')
254
255 completion_names = []
256
257 kwargs_only = False
258 if any(t in allowed_transitions for t in (PythonTokenTypes.NAME,
259 PythonTokenTypes.INDENT)):
260 # This means that we actually have to do type inference.
261
262 nonterminals = [stack_node.nonterminal for stack_node in stack]
263
264 nodes = _gather_nodes(stack)
265 if nodes and nodes[-1] in ('as', 'def', 'class'):
266 # No completions for ``with x as foo`` and ``import x as foo``.
267 # Also true for defining names as a class or function.
268 return cached_name, list(self._complete_inherited(is_function=True))
269 elif "import_stmt" in nonterminals:
270 level, names = parse_dotted_names(nodes, "import_from" in nonterminals)
271
272 only_modules = not ("import_from" in nonterminals and 'import' in nodes)
273 completion_names += self._get_importer_names(
274 names,
275 level,
276 only_modules=only_modules,
277 )
278 elif nonterminals[-1] in ('trailer', 'dotted_name') and nodes[-1] == '.':
279 dot = self._module_node.get_leaf_for_position(self._position)
280 if dot.type == "endmarker":
281 # This is a bit of a weird edge case, maybe we can somehow
282 # generalize this.
283 dot = leaf.get_previous_leaf()
284 cached_name, n = self._complete_trailer(dot.get_previous_leaf())
285 completion_names += n
286 elif self._is_parameter_completion():
287 completion_names += self._complete_params(leaf)
288 else:
289 # Apparently this looks like it's good enough to filter most cases
290 # so that signature completions don't randomly appear.
291 # To understand why this works, three things are important:
292 # 1. trailer with a `,` in it is either a subscript or an arglist.
293 # 2. If there's no `,`, it's at the start and only signatures start
294 # with `(`. Other trailers could start with `.` or `[`.
295 # 3. Decorators are very primitive and have an optional `(` with
296 # optional arglist in them.
297 if nodes[-1] in ['(', ','] \
298 and nonterminals[-1] in ('trailer', 'arglist', 'decorator'):
299 signatures = self._signatures_callback(*self._position)
300 if signatures:
301 call_details = signatures[0]._call_details
302 used_kwargs = list(call_details.iter_used_keyword_arguments())
303 positional_count = call_details.count_positional_arguments()
304
305 completion_names += _get_signature_param_names(
306 signatures,
307 positional_count,
308 used_kwargs,
309 )
310
311 kwargs_only = _must_be_kwarg(signatures, positional_count, used_kwargs)
312
313 if not kwargs_only:
314 completion_names += self._complete_global_scope()
315 completion_names += self._complete_inherited(is_function=False)
316
317 if not kwargs_only:
318 current_line = self._code_lines[self._position[0] - 1][:self._position[1]]
319 completion_names += self._complete_keywords(
320 allowed_transitions,
321 only_values=not (not current_line or current_line[-1] in ' \t.;'
322 and current_line[-3:] != '...')
323 )
324
325 return cached_name, completion_names
326
327 def _is_parameter_completion(self):
328 tos = self.stack[-1]
329 if tos.nonterminal == 'lambdef' and len(tos.nodes) == 1:
330 # We are at the position `lambda `, where basically the next node
331 # is a param.
332 return True
333 if tos.nonterminal in 'parameters':
334 # Basically we are at the position `foo(`, there's nothing there
335 # yet, so we have no `typedargslist`.
336 return True
337 # var args is for lambdas and typed args for normal functions
338 return tos.nonterminal in ('typedargslist', 'varargslist') and tos.nodes[-1] == ','
339
340 def _complete_params(self, leaf):
341 stack_node = self.stack[-2]
342 if stack_node.nonterminal == 'parameters':
343 stack_node = self.stack[-3]
344 if stack_node.nonterminal == 'funcdef':
345 context = get_user_context(self._module_context, self._position)
346 node = search_ancestor(leaf, 'error_node', 'funcdef')
347 if node is not None:
348 if node.type == 'error_node':
349 n = node.children[0]
350 if n.type == 'decorators':
351 decorators = n.children
352 elif n.type == 'decorator':
353 decorators = [n]
354 else:
355 decorators = []
356 else:
357 decorators = node.get_decorators()
358 function_name = stack_node.nodes[1]
359
360 return complete_param_names(context, function_name.value, decorators)
361 return []
362
363 def _complete_keywords(self, allowed_transitions, only_values):
364 for k in allowed_transitions:
365 if isinstance(k, str) and k.isalpha():
366 if not only_values or k in ('True', 'False', 'None'):
367 yield keywords.KeywordName(self._inference_state, k)
368
369 def _complete_global_scope(self):
370 context = get_user_context(self._module_context, self._position)
371 debug.dbg('global completion scope: %s', context)
372 flow_scope_node = get_flow_scope_node(self._module_node, self._position)
373 filters = get_global_filters(
374 context,
375 self._position,
376 flow_scope_node
377 )
378 completion_names = []
379 for filter in filters:
380 completion_names += filter.values()
381 return completion_names
382
383 def _complete_trailer(self, previous_leaf):
384 inferred_context = self._module_context.create_context(previous_leaf)
385 values = infer_call_of_leaf(inferred_context, previous_leaf)
386 debug.dbg('trailer completion values: %s', values, color='MAGENTA')
387
388 # The cached name simply exists to make speed optimizations for certain
389 # modules.
390 cached_name = None
391 if len(values) == 1:
392 v, = values
393 if v.is_module():
394 if len(v.string_names) == 1:
395 module_name = v.string_names[0]
396 if module_name in ('numpy', 'tensorflow', 'matplotlib', 'pandas'):
397 cached_name = module_name
398
399 return cached_name, self._complete_trailer_for_values(values)
400
401 def _complete_trailer_for_values(self, values):
402 user_context = get_user_context(self._module_context, self._position)
403
404 return complete_trailer(user_context, values)
405
406 def _get_importer_names(self, names, level=0, only_modules=True):
407 names = [n.value for n in names]
408 i = imports.Importer(self._inference_state, names, self._module_context, level)
409 return i.completion_names(self._inference_state, only_modules=only_modules)
410
411 def _complete_inherited(self, is_function=True):
412 """
413 Autocomplete inherited methods when overriding in child class.
414 """
415 leaf = self._module_node.get_leaf_for_position(self._position, include_prefixes=True)
416 cls = tree.search_ancestor(leaf, 'classdef')
417 if cls is None:
418 return
419
420 # Complete the methods that are defined in the super classes.
421 class_value = self._module_context.create_value(cls)
422
423 if cls.start_pos[1] >= leaf.start_pos[1]:
424 return
425
426 filters = class_value.get_filters(is_instance=True)
427 # The first dict is the dictionary of class itself.
428 next(filters)
429 for filter in filters:
430 for name in filter.values():
431 # TODO we should probably check here for properties
432 if (name.api_type == 'function') == is_function:
433 yield name
434
435 def _complete_in_string(self, start_leaf, string):
436 """
437 To make it possible for people to have completions in doctests or
438 generally in "Python" code in docstrings, we use the following
439 heuristic:
440
441 - Having an indented block of code
442 - Having some doctest code that starts with `>>>`
443 - Having backticks that doesn't have whitespace inside it
444 """
445 def iter_relevant_lines(lines):
446 include_next_line = False
447 for l in code_lines:
448 if include_next_line or l.startswith('>>>') or l.startswith(' '):
449 yield re.sub(r'^( *>>> ?| +)', '', l)
450 else:
451 yield None
452
453 include_next_line = bool(re.match(' *>>>', l))
454
455 string = dedent(string)
456 code_lines = split_lines(string, keepends=True)
457 relevant_code_lines = list(iter_relevant_lines(code_lines))
458 if relevant_code_lines[-1] is not None:
459 # Some code lines might be None, therefore get rid of that.
460 relevant_code_lines = ['\n' if c is None else c for c in relevant_code_lines]
461 return self._complete_code_lines(relevant_code_lines)
462 match = re.search(r'`([^`\s]+)', code_lines[-1])
463 if match:
464 return self._complete_code_lines([match.group(1)])
465 return []
466
467 def _complete_code_lines(self, code_lines):
468 module_node = self._inference_state.grammar.parse(''.join(code_lines))
469 module_value = DocstringModule(
470 in_module_context=self._module_context,
471 inference_state=self._inference_state,
472 module_node=module_node,
473 code_lines=code_lines,
474 )
475 return Completion(
476 self._inference_state,
477 module_value.as_context(),
478 code_lines=code_lines,
479 position=module_node.end_pos,
480 signatures_callback=lambda *args, **kwargs: [],
481 fuzzy=self._fuzzy
482 ).complete()
483
484
485def _gather_nodes(stack):
486 nodes = []
487 for stack_node in stack:
488 if stack_node.dfa.from_rule == 'small_stmt':
489 nodes = []
490 else:
491 nodes += stack_node.nodes
492 return nodes
493
494
495_string_start = re.compile(r'^\w*(\'{3}|"{3}|\'|")')
496
497
498def _extract_string_while_in_string(leaf, position):
499 def return_part_of_leaf(leaf):
500 kwargs = {}
501 if leaf.line == position[0]:
502 kwargs['endpos'] = position[1] - leaf.column
503 match = _string_start.match(leaf.value, **kwargs)
504 if not match:
505 return None, None, None
506 start = match.group(0)
507 if leaf.line == position[0] and position[1] < leaf.column + match.end():
508 return None, None, None
509 return cut_value_at_position(leaf, position)[match.end():], leaf, start
510
511 if position < leaf.start_pos:
512 return None, None, None
513
514 if leaf.type == 'string':
515 return return_part_of_leaf(leaf)
516
517 leaves = []
518 while leaf is not None:
519 if leaf.type == 'error_leaf' and ('"' in leaf.value or "'" in leaf.value):
520 if len(leaf.value) > 1:
521 return return_part_of_leaf(leaf)
522 prefix_leaf = None
523 if not leaf.prefix:
524 prefix_leaf = leaf.get_previous_leaf()
525 if prefix_leaf is None or prefix_leaf.type != 'name' \
526 or not all(c in 'rubf' for c in prefix_leaf.value.lower()):
527 prefix_leaf = None
528
529 return (
530 ''.join(cut_value_at_position(l, position) for l in leaves),
531 prefix_leaf or leaf,
532 ('' if prefix_leaf is None else prefix_leaf.value)
533 + cut_value_at_position(leaf, position),
534 )
535 if leaf.line != position[0]:
536 # Multi line strings are always simple error leaves and contain the
537 # whole string, single line error leaves are atherefore important
538 # now and since the line is different, it's not really a single
539 # line string anymore.
540 break
541 leaves.insert(0, leaf)
542 leaf = leaf.get_previous_leaf()
543 return None, None, None
544
545
546def complete_trailer(user_context, values):
547 completion_names = []
548 for value in values:
549 for filter in value.get_filters(origin_scope=user_context.tree_node):
550 completion_names += filter.values()
551
552 if not value.is_stub() and isinstance(value, TreeInstance):
553 completion_names += _complete_getattr(user_context, value)
554
555 python_values = convert_values(values)
556 for c in python_values:
557 if c not in values:
558 for filter in c.get_filters(origin_scope=user_context.tree_node):
559 completion_names += filter.values()
560 return completion_names
561
562
563def _complete_getattr(user_context, instance):
564 """
565 A heuristic to make completion for proxy objects work. This is not
566 intended to work in all cases. It works exactly in this case:
567
568 def __getattr__(self, name):
569 ...
570 return getattr(any_object, name)
571
572 It is important that the return contains getattr directly, otherwise it
573 won't work anymore. It's really just a stupid heuristic. It will not
574 work if you write e.g. `return (getatr(o, name))`, because of the
575 additional parentheses. It will also not work if you move the getattr
576 to some other place that is not the return statement itself.
577
578 It is intentional that it doesn't work in all cases. Generally it's
579 really hard to do even this case (as you can see below). Most people
580 will write it like this anyway and the other ones, well they are just
581 out of luck I guess :) ~dave.
582 """
583 names = (instance.get_function_slot_names('__getattr__')
584 or instance.get_function_slot_names('__getattribute__'))
585 functions = ValueSet.from_sets(
586 name.infer()
587 for name in names
588 )
589 for func in functions:
590 tree_node = func.tree_node
591 if tree_node is None or tree_node.type != 'funcdef':
592 continue
593
594 for return_stmt in tree_node.iter_return_stmts():
595 # Basically until the next comment we just try to find out if a
596 # return statement looks exactly like `return getattr(x, name)`.
597 if return_stmt.type != 'return_stmt':
598 continue
599 atom_expr = return_stmt.children[1]
600 if atom_expr.type != 'atom_expr':
601 continue
602 atom = atom_expr.children[0]
603 trailer = atom_expr.children[1]
604 if len(atom_expr.children) != 2 or atom.type != 'name' \
605 or atom.value != 'getattr':
606 continue
607 arglist = trailer.children[1]
608 if arglist.type != 'arglist' or len(arglist.children) < 3:
609 continue
610 context = func.as_context()
611 object_node = arglist.children[0]
612
613 # Make sure it's a param: foo in __getattr__(self, foo)
614 name_node = arglist.children[2]
615 name_list = context.goto(name_node, name_node.start_pos)
616 if not any(n.api_type == 'param' for n in name_list):
617 continue
618
619 # Now that we know that these are most probably completion
620 # objects, we just infer the object and return them as
621 # completions.
622 objects = context.infer_node(object_node)
623 return complete_trailer(user_context, objects)
624 return []
625
626
627def search_in_module(inference_state, module_context, names, wanted_names,
628 wanted_type, complete=False, fuzzy=False,
629 ignore_imports=False, convert=False):
630 for s in wanted_names[:-1]:
631 new_names = []
632 for n in names:
633 if s == n.string_name:
634 if n.tree_name is not None and n.api_type in ('module', 'namespace') \
635 and ignore_imports:
636 continue
637 new_names += complete_trailer(
638 module_context,
639 n.infer()
640 )
641 debug.dbg('dot lookup on search %s from %s', new_names, names[:10])
642 names = new_names
643
644 last_name = wanted_names[-1].lower()
645 for n in names:
646 string = n.string_name.lower()
647 if complete and helpers.match(string, last_name, fuzzy=fuzzy) \
648 or not complete and string == last_name:
649 if isinstance(n, SubModuleName):
650 names = [v.name for v in n.infer()]
651 else:
652 names = [n]
653 if convert:
654 names = convert_names(names)
655 for n2 in names:
656 if complete:
657 def_ = classes.Completion(
658 inference_state, n2,
659 stack=None,
660 like_name_length=len(last_name),
661 is_fuzzy=fuzzy,
662 )
663 else:
664 def_ = classes.Name(inference_state, n2)
665 if not wanted_type or wanted_type == def_.type:
666 yield def_