Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/jedi-0.20.0-py3.11.egg/jedi/inference/names.py: 32%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

469 statements  

1from abc import abstractmethod 

2from inspect import Parameter 

3from typing import Optional, Tuple, Any 

4 

5from jedi.parser_utils import find_statement_documentation, clean_scope_docstring 

6from jedi.inference.base_value import ValueSet, NO_VALUES 

7from jedi.inference.cache import inference_state_method_cache 

8from jedi.inference import docstrings 

9from jedi.cache import memoize_method 

10from jedi.inference.helpers import deep_ast_copy, infer_call_of_leaf 

11from jedi.plugins import plugin_manager 

12 

13 

14def _merge_name_docs(names): 

15 doc = '' 

16 for name in names: 

17 if doc: 

18 # In case we have multiple values, just return all of them 

19 # separated by a few dashes. 

20 doc += '\n' + '-' * 30 + '\n' 

21 doc += name.py__doc__() 

22 return doc 

23 

24 

25class AbstractNameDefinition: 

26 start_pos: Optional[Tuple[int, int]] = None 

27 string_name: str 

28 parent_context = None 

29 tree_name = None 

30 is_value_name = True 

31 """ 

32 Used for the Jedi API to know if it's a keyword or an actual name. 

33 """ 

34 

35 @abstractmethod 

36 def infer(self): 

37 raise NotImplementedError 

38 

39 def goto(self): 

40 # Typically names are already definitions and therefore a goto on that 

41 # name will always result on itself. 

42 return {self} 

43 

44 def get_qualified_names(self, include_module_names=False): 

45 qualified_names = self._get_qualified_names() 

46 if qualified_names is None or not include_module_names: 

47 return qualified_names 

48 

49 module_names = self.get_root_context().string_names 

50 if module_names is None: 

51 return None 

52 return module_names + qualified_names 

53 

54 def _get_qualified_names(self): 

55 # By default, a name has no qualified names. 

56 return None 

57 

58 def get_root_context(self): 

59 return self.parent_context.get_root_context() 

60 

61 def get_public_name(self): 

62 return self.string_name 

63 

64 def __repr__(self): 

65 if self.start_pos is None: 

66 return '<%s: string_name=%s>' % (self.__class__.__name__, self.string_name) 

67 return '<%s: string_name=%s start_pos=%s>' % (self.__class__.__name__, 

68 self.string_name, self.start_pos) 

69 

70 def is_import(self): 

71 return False 

72 

73 def py__doc__(self): 

74 return '' 

75 

76 @property 

77 def api_type(self): 

78 return self.parent_context.api_type 

79 

80 def get_defining_qualified_value(self): 

81 """ 

82 Returns either None or the value that is public and qualified. Won't 

83 return a function, because a name in a function is never public. 

84 """ 

85 return None 

86 

87 

88class AbstractArbitraryName(AbstractNameDefinition): 

89 """ 

90 When you e.g. want to complete dicts keys, you probably want to complete 

91 string literals, which is not really a name, but for Jedi we use this 

92 concept of Name for completions as well. 

93 """ 

94 is_value_name = False 

95 

96 def __init__(self, inference_state, string): 

97 self.inference_state = inference_state 

98 self.string_name = string 

99 self.parent_context = inference_state.builtins_module 

100 

101 def infer(self): 

102 return NO_VALUES 

103 

104 

105class AbstractTreeName(AbstractNameDefinition): 

106 tree_name: Any 

107 parent_context: Any 

108 

109 def __init__(self, parent_context, tree_name): 

110 self.parent_context = parent_context 

111 self.tree_name = tree_name 

112 

113 def get_qualified_names(self, include_module_names=False): 

114 import_node = self.tree_name.search_ancestor('import_name', 'import_from') 

115 # For import nodes we cannot just have names, because it's very unclear 

116 # how they would look like. For now we just ignore them in most cases. 

117 # In case of level == 1, it works always, because it's like a submodule 

118 # lookup. 

119 if import_node is not None and not (import_node.level == 1 

120 and self.get_root_context().get_value().is_package()): 

121 # TODO improve the situation for when level is present. 

122 if include_module_names and not import_node.level: 

123 return tuple(n.value for n in import_node.get_path_for_name(self.tree_name)) 

124 else: 

125 return None 

126 

127 return super().get_qualified_names(include_module_names) 

128 

129 def _get_qualified_names(self): 

130 parent_names = self.parent_context.get_qualified_names() 

131 if parent_names is None: 

132 return None 

133 return parent_names + (self.tree_name.value,) 

134 

135 def get_defining_qualified_value(self): 

136 if self.is_import(): 

137 raise NotImplementedError("Shouldn't really happen, please report") 

138 elif self.parent_context: 

139 return self.parent_context.get_value() # Might be None 

140 return None 

141 

142 def goto(self): 

143 context = self.parent_context 

144 name = self.tree_name 

145 definition = name.get_definition(import_name_always=True) 

146 if definition is not None: 

147 type_ = definition.type 

148 if type_ == 'expr_stmt': 

149 # Only take the parent, because if it's more complicated than just 

150 # a name it's something you can "goto" again. 

151 is_simple_name = name.parent.type not in ('power', 'trailer') 

152 if is_simple_name: 

153 return [self] 

154 elif type_ in ('import_from', 'import_name'): 

155 from jedi.inference.imports import goto_import 

156 module_names = goto_import(context, name) 

157 return module_names 

158 else: 

159 return [self] 

160 else: 

161 from jedi.inference.imports import follow_error_node_imports_if_possible 

162 values = follow_error_node_imports_if_possible(context, name) 

163 if values is not None: 

164 return [value.name for value in values] 

165 

166 par = name.parent 

167 node_type = par.type 

168 if node_type == 'argument' and par.children[1] == '=' and par.children[0] == name: 

169 # Named param goto. 

170 trailer = par.parent 

171 if trailer.type == 'arglist': 

172 trailer = trailer.parent 

173 if trailer.type != 'classdef': 

174 if trailer.type == 'decorator': 

175 value_set = context.infer_node(trailer.children[1]) 

176 else: 

177 i = trailer.parent.children.index(trailer) 

178 to_infer = trailer.parent.children[:i] 

179 if to_infer[0] == 'await': 

180 to_infer.pop(0) 

181 value_set = context.infer_node(to_infer[0]) 

182 from jedi.inference.syntax_tree import infer_trailer 

183 for trailer in to_infer[1:]: 

184 value_set = infer_trailer(context, value_set, trailer) 

185 param_names = [] 

186 for value in value_set: 

187 for signature in value.get_signatures(): 

188 for param_name in signature.get_param_names(): 

189 if param_name.string_name == name.value: 

190 param_names.append(param_name) 

191 return param_names 

192 elif node_type == 'dotted_name': # Is a decorator. 

193 index = par.children.index(name) 

194 if index > 0: 

195 new_dotted = deep_ast_copy(par) 

196 new_dotted.children[index - 1:] = [] 

197 values = context.infer_node(new_dotted) 

198 return [ 

199 n 

200 for value in values 

201 for n in value.goto(name, name_context=context) 

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 = name.search_ancestor('expr_stmt', 'lambdef') or name 

209 if stmt.type == 'lambdef': 

210 stmt = name 

211 return context.goto(name, position=stmt.start_pos) 

212 

213 def is_import(self): 

214 imp = self.tree_name.search_ancestor('import_from', 'import_name') 

215 return imp is not None 

216 

217 @property 

218 def string_name(self): 

219 return self.tree_name.value 

220 

221 @property 

222 def start_pos(self): 

223 return self.tree_name.start_pos 

224 

225 

226class ValueNameMixin: 

227 _value: Any 

228 parent_context: Any 

229 

230 def infer(self): 

231 return ValueSet([self._value]) 

232 

233 def py__doc__(self): 

234 doc = self._value.py__doc__() 

235 if not doc and self._value.is_stub(): 

236 from jedi.inference.gradual.conversion import convert_names 

237 names = convert_names([self], prefer_stub_to_compiled=False) 

238 if self not in names: 

239 return _merge_name_docs(names) 

240 return doc 

241 

242 def _get_qualified_names(self): 

243 return self._value.get_qualified_names() 

244 

245 def get_root_context(self): 

246 if self.parent_context is None: # A module 

247 return self._value.as_context() 

248 return super().get_root_context() # type: ignore 

249 

250 def get_defining_qualified_value(self): 

251 context = self.parent_context 

252 if context is not None and (context.is_module() or context.is_class()): 

253 return self.parent_context.get_value() # Might be None 

254 return None 

255 

256 @property 

257 def api_type(self): 

258 return self._value.api_type 

259 

260 

261class ValueName(ValueNameMixin, AbstractTreeName): 

262 def __init__(self, value, tree_name): 

263 super().__init__(value.parent_context, tree_name) 

264 self._value = value 

265 

266 def goto(self): 

267 return ValueSet([self._value.name]) 

268 

269 

270class TreeNameDefinition(AbstractTreeName): 

271 _API_TYPES = dict( 

272 import_name='module', 

273 import_from='module', 

274 funcdef='function', 

275 param='param', 

276 classdef='class', 

277 ) 

278 

279 def infer(self): 

280 # Refactor this, should probably be here. 

281 from jedi.inference.syntax_tree import tree_name_to_values 

282 return tree_name_to_values( 

283 self.parent_context.inference_state, 

284 self.parent_context, 

285 self.tree_name 

286 ) 

287 

288 @property 

289 def api_type(self): 

290 definition = self.tree_name.get_definition(import_name_always=True) 

291 if definition is None: 

292 return 'statement' 

293 return self._API_TYPES.get(definition.type, 'statement') 

294 

295 def assignment_indexes(self): 

296 """ 

297 Returns an array of tuple(int, node) of the indexes that are used in 

298 tuple assignments. 

299 

300 For example if the name is ``y`` in the following code:: 

301 

302 x, (y, z) = 2, '' 

303 

304 would result in ``[(1, xyz_node), (0, yz_node)]``. 

305 

306 When searching for b in the case ``a, *b, c = [...]`` it will return:: 

307 

308 [(slice(1, -1), abc_node)] 

309 """ 

310 indexes = [] 

311 is_star_expr = False 

312 node = self.tree_name.parent 

313 compare = self.tree_name 

314 while node is not None: 

315 if node.type in ('testlist', 'testlist_comp', 'testlist_star_expr', 'exprlist'): 

316 for i, child in enumerate(node.children): 

317 if child == compare: 

318 index = int(i / 2) 

319 if is_star_expr: 

320 from_end = int((len(node.children) - i) / 2) 

321 index = slice(index, -from_end) 

322 indexes.insert(0, (index, node)) 

323 break 

324 else: 

325 raise LookupError("Couldn't find the assignment.") 

326 is_star_expr = False 

327 elif node.type == 'star_expr': 

328 is_star_expr = True 

329 elif node.type in ('expr_stmt', 'sync_comp_for'): 

330 break 

331 

332 compare = node 

333 node = node.parent 

334 return indexes 

335 

336 @property 

337 def inference_state(self): 

338 # Used by the cache function below 

339 return self.parent_context.inference_state 

340 

341 @inference_state_method_cache(default='') 

342 def py__doc__(self): 

343 api_type = self.api_type 

344 if api_type in ('function', 'class', 'property'): 

345 if self.parent_context.get_root_context().is_stub(): 

346 from jedi.inference.gradual.conversion import convert_names 

347 names = convert_names([self], prefer_stub_to_compiled=False) 

348 if self not in names: 

349 return _merge_name_docs(names) 

350 

351 # Make sure the names are not TreeNameDefinitions anymore. 

352 return clean_scope_docstring(self.tree_name.get_definition()) 

353 

354 if api_type == 'module': 

355 names = self.goto() 

356 if self not in names: 

357 return _merge_name_docs(names) 

358 

359 if api_type == 'statement' and self.tree_name.is_definition(): 

360 return find_statement_documentation(self.tree_name.get_definition()) 

361 return '' 

362 

363 

364class _ParamMixin: 

365 get_kind: Any 

366 

367 def maybe_positional_argument(self, include_star=True): 

368 options: list[int] = [Parameter.POSITIONAL_ONLY, Parameter.POSITIONAL_OR_KEYWORD] 

369 if include_star: 

370 options.append(Parameter.VAR_POSITIONAL) 

371 return self.get_kind() in options 

372 

373 def maybe_keyword_argument(self, include_stars=True): 

374 options: list[int] = [Parameter.KEYWORD_ONLY, Parameter.POSITIONAL_OR_KEYWORD] 

375 if include_stars: 

376 options.append(Parameter.VAR_KEYWORD) 

377 return self.get_kind() in options 

378 

379 def _kind_string(self): 

380 kind = self.get_kind() 

381 if kind == Parameter.VAR_POSITIONAL: # *args 

382 return '*' 

383 if kind == Parameter.VAR_KEYWORD: # **kwargs 

384 return '**' 

385 return '' 

386 

387 def get_qualified_names(self, include_module_names=False): 

388 return None 

389 

390 

391class ParamNameInterface(_ParamMixin): 

392 api_type = 'param' 

393 

394 def get_kind(self): 

395 raise NotImplementedError 

396 

397 def to_string(self): 

398 raise NotImplementedError 

399 

400 def get_executed_param_name(self): 

401 """ 

402 For dealing with type inference and working around the graph, we 

403 sometimes want to have the param name of the execution. This feels a 

404 bit strange and we might have to refactor at some point. 

405 

406 For now however it exists to avoid infering params when we don't really 

407 need them (e.g. when we can just instead use annotations. 

408 """ 

409 return None 

410 

411 @property 

412 def star_count(self): 

413 kind = self.get_kind() 

414 if kind == Parameter.VAR_POSITIONAL: 

415 return 1 

416 if kind == Parameter.VAR_KEYWORD: 

417 return 2 

418 return 0 

419 

420 def infer_default(self): 

421 return NO_VALUES 

422 

423 

424class BaseTreeParamName(ParamNameInterface, AbstractTreeName): 

425 annotation_node = None 

426 default_node = None 

427 

428 def to_string(self): 

429 output = self._kind_string() + self.get_public_name() 

430 annotation = self.annotation_node 

431 default = self.default_node 

432 if annotation is not None: 

433 output += ': ' + annotation.get_code(include_prefix=False) 

434 if default is not None: 

435 output += '=' + default.get_code(include_prefix=False) 

436 return output 

437 

438 def get_public_name(self): 

439 name = self.string_name 

440 if name.startswith('__'): 

441 # Params starting with __ are an equivalent to positional only 

442 # variables in typeshed. 

443 name = name[2:] 

444 return name 

445 

446 def goto(self, **kwargs): 

447 return [self] 

448 

449 

450class _ActualTreeParamName(BaseTreeParamName): 

451 def __init__(self, function_value, tree_name): 

452 super().__init__( 

453 function_value.get_default_param_context(), tree_name) 

454 self.function_value = function_value 

455 

456 def _get_param_node(self): 

457 return self.tree_name.search_ancestor('param') 

458 

459 @property 

460 def annotation_node(self): 

461 return self._get_param_node().annotation 

462 

463 def infer_annotation(self, execute_annotation=True, ignore_stars=False): 

464 from jedi.inference.gradual.annotation import infer_param 

465 values = infer_param( 

466 self.function_value, self._get_param_node(), 

467 ignore_stars=ignore_stars) 

468 if execute_annotation: 

469 values = values.execute_annotation(self.function_value.get_default_param_context()) 

470 return values 

471 

472 def infer_default(self): 

473 node = self.default_node 

474 if node is None: 

475 return NO_VALUES 

476 return self.parent_context.infer_node(node) 

477 

478 @property 

479 def default_node(self): 

480 return self._get_param_node().default 

481 

482 def get_kind(self): 

483 tree_param = self._get_param_node() 

484 if tree_param.star_count == 1: # *args 

485 return Parameter.VAR_POSITIONAL 

486 if tree_param.star_count == 2: # **kwargs 

487 return Parameter.VAR_KEYWORD 

488 

489 # Params starting with __ are an equivalent to positional only 

490 # variables in typeshed. 

491 if tree_param.name.value.startswith('__'): 

492 return Parameter.POSITIONAL_ONLY 

493 

494 parent = tree_param.parent 

495 param_appeared = False 

496 for p in parent.children: 

497 if param_appeared: 

498 if p == '/': 

499 return Parameter.POSITIONAL_ONLY 

500 else: 

501 if p == '*': 

502 return Parameter.KEYWORD_ONLY 

503 if p.type == 'param': 

504 if p.star_count: 

505 return Parameter.KEYWORD_ONLY 

506 if p == tree_param: 

507 param_appeared = True 

508 return Parameter.POSITIONAL_OR_KEYWORD 

509 

510 def infer(self): 

511 values = self.infer_annotation() 

512 if values: 

513 return values 

514 

515 doc_params = docstrings.infer_param(self.function_value, self._get_param_node()) 

516 return doc_params 

517 

518 

519class AnonymousParamName(_ActualTreeParamName): 

520 @plugin_manager.decorate(name='goto_anonymous_param') 

521 def goto(self): 

522 return super().goto() 

523 

524 @plugin_manager.decorate(name='infer_anonymous_param') 

525 def infer(self): 

526 values = super().infer() 

527 if values: 

528 return values 

529 from jedi.inference.dynamic_params import dynamic_param_lookup 

530 param = self._get_param_node() 

531 values = dynamic_param_lookup(self.function_value, param.position_index) 

532 if values: 

533 return values 

534 

535 if param.star_count == 1: 

536 from jedi.inference.value.iterable import FakeTuple 

537 value = FakeTuple(self.function_value.inference_state, []) 

538 elif param.star_count == 2: 

539 from jedi.inference.value.iterable import FakeDict 

540 value = FakeDict(self.function_value.inference_state, {}) 

541 elif param.default is None: 

542 return NO_VALUES 

543 else: 

544 return self.function_value.parent_context.infer_node(param.default) 

545 return ValueSet({value}) 

546 

547 

548class ParamName(_ActualTreeParamName): 

549 def __init__(self, function_value, tree_name, arguments): 

550 super().__init__(function_value, tree_name) 

551 self.arguments = arguments 

552 

553 def infer(self): 

554 values = super().infer() 

555 if values: 

556 return values 

557 

558 return self.get_executed_param_name().infer() 

559 

560 def get_executed_param_name(self): 

561 from jedi.inference.param import get_executed_param_names 

562 params_names = get_executed_param_names(self.function_value, self.arguments) 

563 return params_names[self._get_param_node().position_index] 

564 

565 

566class ParamNameWrapper(_ParamMixin): 

567 def __init__(self, param_name): 

568 self._wrapped_param_name = param_name 

569 

570 def __getattr__(self, name): 

571 return getattr(self._wrapped_param_name, name) 

572 

573 def __repr__(self): 

574 return '<%s: %s>' % (self.__class__.__name__, self._wrapped_param_name) 

575 

576 

577class ImportName(AbstractNameDefinition): 

578 start_pos = (1, 0) 

579 _level = 0 

580 

581 def __init__(self, parent_context, string_name): 

582 self._from_module_context = parent_context 

583 self.string_name = string_name 

584 

585 def get_qualified_names(self, include_module_names=False): 

586 if include_module_names: 

587 if self._level: 

588 assert self._level == 1, "Everything else is not supported for now" 

589 module_names = self._from_module_context.string_names 

590 if module_names is None: 

591 return module_names 

592 return module_names + (self.string_name,) 

593 return (self.string_name,) 

594 return () 

595 

596 @property 

597 def parent_context(self): 

598 m = self._from_module_context 

599 import_values = self.infer() 

600 if not import_values: 

601 return m 

602 # It's almost always possible to find the import or to not find it. The 

603 # importing returns only one value, pretty much always. 

604 return next(iter(import_values)).as_context() 

605 

606 @memoize_method 

607 def infer(self): 

608 from jedi.inference.imports import Importer 

609 m = self._from_module_context 

610 return Importer(m.inference_state, [self.string_name], m, level=self._level).follow() 

611 

612 def goto(self): 

613 return [m.name for m in self.infer()] 

614 

615 @property 

616 def api_type(self): 

617 return 'module' 

618 

619 def py__doc__(self): 

620 return _merge_name_docs(self.goto()) 

621 

622 

623class SubModuleName(ImportName): 

624 _level = 1 

625 

626 

627class NameWrapper: 

628 def __init__(self, wrapped_name): 

629 self._wrapped_name = wrapped_name 

630 

631 def __getattr__(self, name): 

632 return getattr(self._wrapped_name, name) 

633 

634 def __repr__(self): 

635 return '%s(%s)' % (self.__class__.__name__, self._wrapped_name) 

636 

637 

638class StubNameMixin: 

639 api_type: str 

640 tree_name: Any 

641 infer: Any 

642 

643 def py__doc__(self): 

644 from jedi.inference.gradual.conversion import convert_names 

645 # Stubs are not complicated and we can just follow simple statements 

646 # that have an equals in them, because they typically make something 

647 # else public. See e.g. stubs for `requests`. 

648 names = [self] 

649 if self.api_type == 'statement' and '=' in self.tree_name.get_definition().children: 

650 names = [v.name for v in self.infer()] 

651 

652 names = convert_names(names, prefer_stub_to_compiled=False) 

653 if self in names: 

654 return super().py__doc__() # type: ignore 

655 else: 

656 # We have signatures ourselves in stubs, so don't use signatures 

657 # from the implementation. 

658 return _merge_name_docs(names) 

659 

660 

661# From here on down we make looking up the sys.version_info fast. 

662class StubName(StubNameMixin, TreeNameDefinition): 

663 def infer(self): 

664 inferred = super().infer() 

665 if self.string_name == 'version_info' and self.get_root_context().py__name__() == 'sys': 

666 from jedi.inference.gradual.stub_value import VersionInfo 

667 return ValueSet(VersionInfo(c) for c in inferred) 

668 return inferred 

669 

670 

671class ModuleName(ValueNameMixin, AbstractNameDefinition): 

672 start_pos = 1, 0 

673 

674 def __init__(self, value, name): 

675 self._value = value 

676 self._name = name 

677 

678 @property 

679 def string_name(self): 

680 return self._name 

681 

682 

683class StubModuleName(StubNameMixin, ModuleName): 

684 pass