Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/jedi/inference/value/instance.py: 36%

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

355 statements  

1from abc import abstractproperty 

2from typing import Any 

3 

4from jedi import debug 

5from jedi import settings 

6from jedi.inference import compiled 

7from jedi.inference.compiled.value import CompiledValueFilter 

8from jedi.inference.helpers import values_from_qualified_names, is_big_annoying_library 

9from jedi.inference.filters import AbstractFilter, AnonymousFunctionExecutionFilter 

10from jedi.inference.names import ValueName, TreeNameDefinition, ParamName, \ 

11 NameWrapper 

12from jedi.inference.base_value import Value, NO_VALUES, ValueSet, \ 

13 iterator_to_value_set, ValueWrapper 

14from jedi.inference.lazy_value import LazyKnownValue, LazyKnownValues 

15from jedi.inference.cache import inference_state_method_cache 

16from jedi.inference.arguments import ValuesArguments, TreeArgumentsWrapper 

17from jedi.inference.value.function import \ 

18 FunctionValue, FunctionMixin, OverloadedFunctionValue, \ 

19 BaseFunctionExecutionContext, FunctionExecutionContext, FunctionNameInClass 

20from jedi.inference.value.klass import ClassFilter, init_or_new_func 

21from jedi.inference.value.dynamic_arrays import get_dynamic_array_instance 

22from jedi.parser_utils import function_is_staticmethod, function_is_classmethod 

23 

24 

25class InstanceExecutedParamName(ParamName): 

26 def __init__(self, instance, function_value, tree_name): 

27 super().__init__( 

28 function_value, tree_name, arguments=None) 

29 self._instance = instance 

30 

31 def infer(self): 

32 return ValueSet([self._instance]) 

33 

34 def matches_signature(self): 

35 return True 

36 

37 

38class AnonymousMethodExecutionFilter(AnonymousFunctionExecutionFilter): 

39 def __init__(self, instance, *args, **kwargs): 

40 super().__init__(*args, **kwargs) 

41 self._instance = instance 

42 

43 def _convert_param(self, param, name): 

44 if param.position_index == 0: 

45 if function_is_classmethod(self._function_value.tree_node): 

46 return InstanceExecutedParamName( 

47 self._instance.py__class__(), 

48 self._function_value, 

49 name 

50 ) 

51 elif not function_is_staticmethod(self._function_value.tree_node): 

52 return InstanceExecutedParamName( 

53 self._instance, 

54 self._function_value, 

55 name 

56 ) 

57 return super()._convert_param(param, name) 

58 

59 

60class AnonymousMethodExecutionContext(BaseFunctionExecutionContext): 

61 def __init__(self, instance, value): 

62 super().__init__(value) 

63 self.instance = instance 

64 

65 def get_filters(self, until_position=None, origin_scope=None): 

66 yield AnonymousMethodExecutionFilter( 

67 self.instance, self, self._value, 

68 until_position=until_position, 

69 origin_scope=origin_scope, 

70 ) 

71 

72 def get_param_names(self): 

73 param_names = list(self._value.get_param_names()) 

74 # set the self name 

75 param_names[0] = InstanceExecutedParamName( 

76 self.instance, 

77 self._value, 

78 param_names[0].tree_name 

79 ) 

80 return param_names 

81 

82 

83class MethodExecutionContext(FunctionExecutionContext): 

84 def __init__(self, instance, *args, **kwargs): 

85 super().__init__(*args, **kwargs) 

86 self.instance = instance 

87 

88 

89class AbstractInstanceValue(Value): 

90 api_type = 'instance' 

91 

92 def __init__(self, inference_state, parent_context, class_value): 

93 super().__init__(inference_state, parent_context) 

94 # Generated instances are classes that are just generated by self 

95 # (No arguments) used. 

96 self.class_value = class_value 

97 

98 def is_instance(self): 

99 return True 

100 

101 def get_qualified_names(self): 

102 return self.class_value.get_qualified_names() 

103 

104 def get_annotated_class_object(self): 

105 return self.class_value # This is the default. 

106 

107 def py__class__(self): 

108 return self.class_value 

109 

110 def py__bool__(self): 

111 # Signalize that we don't know about the bool type. 

112 return None 

113 

114 @abstractproperty 

115 def name(self): 

116 raise NotImplementedError 

117 

118 def get_signatures(self): 

119 call_funcs = self.py__getattribute__('__call__').py__get__(self, self.class_value) 

120 return [s.bind(self) for s in call_funcs.get_signatures()] 

121 

122 def get_function_slot_names(self, name): 

123 # Python classes don't look at the dictionary of the instance when 

124 # looking up `__call__`. This is something that has to do with Python's 

125 # internal slot system (note: not __slots__, but C slots). 

126 for filter in self.get_filters(include_self_names=False): 

127 names = filter.get(name) 

128 if names: 

129 return names 

130 return [] 

131 

132 def execute_function_slots(self, names, *inferred_args): 

133 return ValueSet.from_sets( 

134 name.infer().execute_with_values(*inferred_args) 

135 for name in names 

136 ) 

137 

138 def get_type_hint(self, add_class_info=True): 

139 return self.py__name__() 

140 

141 def py__getitem__(self, index_value_set, contextualized_node): 

142 names = self.get_function_slot_names('__getitem__') 

143 if not names: 

144 return super().py__getitem__( 

145 index_value_set, 

146 contextualized_node, 

147 ) 

148 

149 args = ValuesArguments([index_value_set]) 

150 return ValueSet.from_sets(name.infer().execute(args) for name in names) 

151 

152 def py__iter__(self, contextualized_node=None): 

153 iter_slot_names = self.get_function_slot_names('__iter__') 

154 if not iter_slot_names: 

155 return super().py__iter__(contextualized_node) 

156 

157 def iterate(): 

158 yield LazyKnownValues( 

159 self.execute_function_slots(iter_slot_names).py__next__(contextualized_node).infer() 

160 ) 

161 return iterate() 

162 

163 def __repr__(self): 

164 return "<%s of %s>" % (self.__class__.__name__, self.class_value) 

165 

166 

167class CompiledInstance(AbstractInstanceValue): 

168 # This is not really a compiled class, it's just an instance from a 

169 # compiled class. 

170 def __init__(self, inference_state, parent_context, class_value, arguments): 

171 super().__init__(inference_state, parent_context, class_value) 

172 self._arguments = arguments 

173 

174 def get_filters(self, origin_scope=None, include_self_names=True): 

175 class_value = self.get_annotated_class_object() 

176 class_filters = class_value.get_filters( 

177 origin_scope=origin_scope, 

178 is_instance=True, 

179 ) 

180 for f in class_filters: 

181 yield CompiledInstanceClassFilter(self, f) 

182 

183 @property 

184 def name(self): 

185 return compiled.CompiledValueName(self, self.class_value.name.string_name) 

186 

187 def is_stub(self): 

188 return False 

189 

190 

191class _BaseTreeInstance(AbstractInstanceValue): 

192 get_defined_names: Any 

193 _arguments: Any 

194 

195 @property 

196 def array_type(self): 

197 name = self.class_value.py__name__() 

198 if name in ['list', 'set', 'dict'] \ 

199 and self.parent_context.get_root_context().is_builtins_module(): 

200 return name 

201 return None 

202 

203 @property 

204 def name(self): 

205 return ValueName(self, self.class_value.name.tree_name) 

206 

207 def get_filters(self, origin_scope=None, include_self_names=True): 

208 class_value = self.get_annotated_class_object() 

209 if include_self_names: 

210 for cls in class_value.py__mro__(): 

211 if not cls.is_compiled(): 

212 # In this case we're excluding compiled objects that are 

213 # not fake objects. It doesn't make sense for normal 

214 # compiled objects to search for self variables. 

215 yield SelfAttributeFilter(self, class_value, cls.as_context(), origin_scope) 

216 

217 class_filters = class_value.get_filters( 

218 origin_scope=origin_scope, 

219 is_instance=True, 

220 ) 

221 for f in class_filters: 

222 if isinstance(f, ClassFilter): 

223 yield InstanceClassFilter(self, f) 

224 elif isinstance(f, CompiledValueFilter): 

225 yield CompiledInstanceClassFilter(self, f) 

226 else: 

227 # Propably from the metaclass. 

228 yield f 

229 

230 @inference_state_method_cache() 

231 def create_instance_context(self, class_context, node): 

232 new = node 

233 while True: 

234 func_node = new 

235 new = new.search_ancestor('funcdef', 'classdef') 

236 if class_context.tree_node is new: 

237 func = FunctionValue.from_context(class_context, func_node) 

238 bound_method = BoundMethod(self, class_context, func) 

239 if func_node.name.value == '__init__': 

240 context = bound_method.as_context(self._arguments) 

241 else: 

242 context = bound_method.as_context() 

243 break 

244 return context.create_context(node) 

245 

246 def py__getattribute__alternatives(self, string_name): 

247 ''' 

248 Since nothing was inferred, now check the __getattr__ and 

249 __getattribute__ methods. Stubs don't need to be checked, because 

250 they don't contain any logic. 

251 ''' 

252 if self.is_stub(): 

253 return NO_VALUES 

254 

255 name = compiled.create_simple_object(self.inference_state, string_name) 

256 

257 # This is a little bit special. `__getattribute__` is in Python 

258 # executed before `__getattr__`. But: I know no use case, where 

259 # this could be practical and where Jedi would return wrong types. 

260 # If you ever find something, let me know! 

261 # We are inversing this, because a hand-crafted `__getattribute__` 

262 # could still call another hand-crafted `__getattr__`, but not the 

263 # other way around. 

264 if is_big_annoying_library(self.parent_context): 

265 return NO_VALUES 

266 names = (self.get_function_slot_names('__getattr__') 

267 or self.get_function_slot_names('__getattribute__')) 

268 return self.execute_function_slots(names, name) 

269 

270 def py__next__(self, contextualized_node=None): 

271 name = u'__next__' 

272 next_slot_names = self.get_function_slot_names(name) 

273 if next_slot_names: 

274 yield LazyKnownValues( 

275 self.execute_function_slots(next_slot_names) 

276 ) 

277 else: 

278 debug.warning('Instance has no __next__ function in %s.', self) 

279 

280 def py__call__(self, arguments): 

281 names = self.get_function_slot_names('__call__') 

282 if not names: 

283 # Means the Instance is not callable. 

284 return super().py__call__(arguments) 

285 

286 return ValueSet.from_sets(name.infer().execute(arguments) for name in names) 

287 

288 def py__get__(self, instance, class_value): 

289 """ 

290 obj may be None. 

291 """ 

292 # Arguments in __get__ descriptors are obj, class. 

293 # `method` is the new parent of the array, don't know if that's good. 

294 for cls in self.class_value.py__mro__(): 

295 result = cls.py__get__on_class(self, instance, class_value) 

296 if result is not NotImplemented: 

297 return result 

298 

299 names = self.get_function_slot_names('__get__') 

300 if names: 

301 if instance is None: 

302 instance = compiled.builtin_from_name(self.inference_state, 'None') 

303 return self.execute_function_slots(names, instance, class_value) 

304 else: 

305 return ValueSet([self]) 

306 

307 

308class TreeInstance(_BaseTreeInstance): 

309 def __init__(self, inference_state, parent_context, class_value, arguments): 

310 # I don't think that dynamic append lookups should happen here. That 

311 # sounds more like something that should go to py__iter__. 

312 if class_value.py__name__() in ['list', 'set'] \ 

313 and parent_context.get_root_context().is_builtins_module(): 

314 # compare the module path with the builtin name. 

315 if settings.dynamic_array_additions: 

316 arguments = get_dynamic_array_instance(self, arguments) 

317 

318 super().__init__(inference_state, parent_context, class_value) 

319 self._arguments = arguments 

320 self.tree_node = class_value.tree_node 

321 

322 # This can recurse, if the initialization of the class includes a reference 

323 # to itself. 

324 @inference_state_method_cache(default=None) 

325 def _get_annotated_class_object(self): 

326 from jedi.inference.gradual.annotation import py__annotations__, \ 

327 infer_type_vars_for_execution 

328 

329 args = InstanceArguments(self, self._arguments) 

330 for signature in init_or_new_func(self.class_value).get_signatures(): 

331 # Just take the first result, it should always be one, because we 

332 # control the typeshed code. 

333 funcdef = signature.value.tree_node 

334 if funcdef is None or funcdef.type != 'funcdef' \ 

335 or not signature.matches_signature(args): 

336 # First check if the signature even matches, if not we don't 

337 # need to infer anything. 

338 continue 

339 bound_method = BoundMethod(self, self.class_value.as_context(), signature.value) 

340 all_annotations = py__annotations__(funcdef) 

341 type_var_dict = infer_type_vars_for_execution(bound_method, args, all_annotations) 

342 if type_var_dict: 

343 defined, = self.class_value.define_generics( 

344 infer_type_vars_for_execution(signature.value, args, all_annotations), 

345 ) 

346 debug.dbg('Inferred instance value as %s', defined, color='BLUE') 

347 return defined 

348 return None 

349 

350 def get_annotated_class_object(self): 

351 return self._get_annotated_class_object() or self.class_value 

352 

353 def get_key_values(self): 

354 values = NO_VALUES 

355 if self.array_type == 'dict': 

356 for i, (key, instance) in enumerate(self._arguments.unpack()): 

357 if key is None and i == 0: 

358 values |= ValueSet.from_sets( 

359 v.get_key_values() 

360 for v in instance.infer() 

361 if v.array_type == 'dict' 

362 ) 

363 if key: 

364 values |= ValueSet([compiled.create_simple_object( 

365 self.inference_state, 

366 key, 

367 )]) 

368 

369 return values 

370 

371 def py__simple_getitem__(self, index): 

372 if self.array_type == 'dict': 

373 # Logic for dict({'foo': bar}) and dict(foo=bar) 

374 # reversed, because: 

375 # >>> dict({'a': 1}, a=3) 

376 # {'a': 3} 

377 # TODO tuple initializations 

378 # >>> dict([('a', 4)]) 

379 # {'a': 4} 

380 for key, lazy_context in reversed(list(self._arguments.unpack())): 

381 if key is None: 

382 values = ValueSet.from_sets( 

383 dct_value.py__simple_getitem__(index) 

384 for dct_value in lazy_context.infer() 

385 if dct_value.array_type == 'dict' 

386 ) 

387 if values: 

388 return values 

389 else: 

390 if key == index: 

391 return lazy_context.infer() 

392 return super().py__simple_getitem__(index) 

393 

394 def __repr__(self): 

395 return "<%s of %s(%s)>" % (self.__class__.__name__, self.class_value, 

396 self._arguments) 

397 

398 

399class AnonymousInstance(_BaseTreeInstance): 

400 _arguments = None 

401 

402 

403class CompiledInstanceName(NameWrapper): 

404 @iterator_to_value_set 

405 def infer(self): 

406 for result_value in self._wrapped_name.infer(): 

407 if result_value.api_type == 'function': 

408 yield CompiledBoundMethod(result_value) 

409 else: 

410 yield result_value 

411 

412 

413class CompiledInstanceClassFilter(AbstractFilter): 

414 def __init__(self, instance, f): 

415 self._instance = instance 

416 self._class_filter = f 

417 

418 def get(self, name): 

419 return self._convert(self._class_filter.get(name)) 

420 

421 def values(self): 

422 return self._convert(self._class_filter.values()) 

423 

424 def _convert(self, names): 

425 return [CompiledInstanceName(n) for n in names] 

426 

427 

428class BoundMethod(FunctionMixin, ValueWrapper): 

429 def __init__(self, instance, class_context, function): 

430 super().__init__(function) 

431 self.instance = instance 

432 self._class_context = class_context 

433 

434 def is_bound_method(self): 

435 return True 

436 

437 @property 

438 def name(self): 

439 return FunctionNameInClass( 

440 self._class_context, 

441 super().name 

442 ) 

443 

444 def py__class__(self): 

445 c, = values_from_qualified_names(self.inference_state, 'types', 'MethodType') 

446 return c 

447 

448 def _get_arguments(self, arguments): 

449 assert arguments is not None 

450 return InstanceArguments(self.instance, arguments) 

451 

452 def _as_context(self, arguments=None): 

453 if arguments is None: 

454 return AnonymousMethodExecutionContext(self.instance, self) 

455 

456 arguments = self._get_arguments(arguments) 

457 return MethodExecutionContext(self.instance, self, arguments) 

458 

459 def py__call__(self, arguments): 

460 if isinstance(self._wrapped_value, OverloadedFunctionValue): 

461 return self._wrapped_value.py__call__(self._get_arguments(arguments)) 

462 

463 function_execution = self.as_context(arguments) 

464 return function_execution.infer() 

465 

466 def get_signature_functions(self): 

467 return [ 

468 BoundMethod(self.instance, self._class_context, f) 

469 for f in self._wrapped_value.get_signature_functions() 

470 ] 

471 

472 def get_signatures(self): 

473 return [sig.bind(self) for sig in super().get_signatures()] 

474 

475 def __repr__(self): 

476 return '<%s: %s>' % (self.__class__.__name__, self._wrapped_value) 

477 

478 

479class CompiledBoundMethod(ValueWrapper): 

480 def is_bound_method(self): 

481 return True 

482 

483 def get_signatures(self): 

484 return [sig.bind(self) for sig in self._wrapped_value.get_signatures()] 

485 

486 

487class SelfName(TreeNameDefinition): 

488 """ 

489 This name calculates the parent_context lazily. 

490 """ 

491 def __init__(self, instance, class_context, tree_name): 

492 self._instance = instance 

493 self.class_context = class_context 

494 self.tree_name = tree_name 

495 

496 @property 

497 def parent_context(self): 

498 return self._instance.create_instance_context(self.class_context, self.tree_name) 

499 

500 def get_defining_qualified_value(self): 

501 return self._instance 

502 

503 def infer(self): 

504 stmt = self.tree_name.search_ancestor('expr_stmt') 

505 if stmt is not None: 

506 if stmt.children[1].type == "annassign": 

507 from jedi.inference.gradual.annotation import infer_annotation 

508 values = infer_annotation( 

509 self.parent_context, stmt.children[1].children[1] 

510 ).execute_annotation(None) 

511 if values: 

512 return values 

513 return super().infer() 

514 

515 

516class LazyInstanceClassName(NameWrapper): 

517 def __init__(self, instance, class_member_name): 

518 super().__init__(class_member_name) 

519 self._instance = instance 

520 

521 @iterator_to_value_set 

522 def infer(self): 

523 for result_value in self._wrapped_name.infer(): 

524 yield from result_value.py__get__(self._instance, self._instance.py__class__()) 

525 

526 def get_signatures(self): 

527 return self.infer().get_signatures() 

528 

529 def get_defining_qualified_value(self): 

530 return self._instance 

531 

532 

533class InstanceClassFilter(AbstractFilter): 

534 """ 

535 This filter is special in that it uses the class filter and wraps the 

536 resulting names in LazyInstanceClassName. The idea is that the class name 

537 filtering can be very flexible and always be reflected in instances. 

538 """ 

539 def __init__(self, instance, class_filter): 

540 self._instance = instance 

541 self._class_filter = class_filter 

542 

543 def get(self, name): 

544 return self._convert(self._class_filter.get(name)) 

545 

546 def values(self): 

547 return self._convert(self._class_filter.values()) 

548 

549 def _convert(self, names): 

550 return [ 

551 LazyInstanceClassName(self._instance, n) 

552 for n in names 

553 ] 

554 

555 def __repr__(self): 

556 return '<%s for %s>' % (self.__class__.__name__, self._class_filter) 

557 

558 

559class SelfAttributeFilter(ClassFilter): 

560 """ 

561 This class basically filters all the use cases where `self.*` was assigned. 

562 """ 

563 def __init__(self, instance, instance_class, node_context, origin_scope): 

564 super().__init__( 

565 class_value=instance_class, 

566 node_context=node_context, 

567 origin_scope=origin_scope, 

568 is_instance=True, 

569 ) 

570 self._instance = instance 

571 

572 def _filter(self, names): 

573 start, end = self._parser_scope.start_pos, self._parser_scope.end_pos 

574 names = [n for n in names if start < n.start_pos < end] 

575 return self._filter_self_names(names) 

576 

577 def _filter_self_names(self, names): 

578 for name in names: 

579 trailer = name.parent 

580 if trailer.type == 'trailer' \ 

581 and len(trailer.parent.children) == 2 \ 

582 and trailer.children[0] == '.': 

583 if name.is_definition() and self._access_possible(name): 

584 # TODO filter non-self assignments instead of this bad 

585 # filter. 

586 if self._is_in_right_scope(trailer.parent.children[0], name): 

587 yield name 

588 

589 def _is_in_right_scope(self, self_name, name): 

590 self_context = self._node_context.create_context(self_name) 

591 names = self_context.goto(self_name, position=self_name.start_pos) 

592 return any( 

593 n.api_type == 'param' 

594 and n.tree_name.get_definition().position_index == 0 

595 and n.parent_context.tree_node is self._parser_scope 

596 for n in names 

597 ) 

598 

599 def _convert_names(self, names): 

600 return [SelfName(self._instance, self._node_context, name) for name in names] 

601 

602 def _check_flows(self, names): 

603 return names 

604 

605 

606class InstanceArguments(TreeArgumentsWrapper): 

607 def __init__(self, instance, arguments): 

608 super().__init__(arguments) 

609 self.instance = instance 

610 

611 def unpack(self, func=None): 

612 yield None, LazyKnownValue(self.instance) 

613 yield from self._wrapped_arguments.unpack(func)