1 from abc import abstractmethod 2 from inspect import Parameter 3 from typing import Optional, Tuple 4 5 from parso.tree import search_ancestor 6 7 from jedi.parser_utils import find_statement_documentation, clean_scope_docstring 8 from jedi.inference.utils import unite 9 from jedi.inference.base_value import ValueSet, NO_VALUES 10 from jedi.inference.cache import inference_state_method_cache 11 from jedi.inference import docstrings 12 from jedi.cache import memoize_method 13 from jedi.inference.helpers import deep_ast_copy, infer_call_of_leaf 14 from jedi.plugins import plugin_manager 15 16 17 def _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 28 class 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 92 class 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 109 class 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 228 class 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 260 class 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 269 class 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 363 class _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 388 class 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 421 class 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 447 class _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 516 class 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 545 class 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 563 class 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 574 class 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 620 class SubModuleName(ImportName): 621 _level = 1 622 623 624 class 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 635 class 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. 655 class 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 664 class 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 676 class StubModuleName(StubNameMixin, ModuleName): 677 pass 678