Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/jedi/inference/base_value.py: 40%

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

351 statements  

1""" 

2Values are the "values" that Python would return. However Values are at the 

3same time also the "values" that a user is currently sitting in. 

4 

5A ValueSet is typically used to specify the return of a function or any other 

6static analysis operation. In jedi there are always multiple returns and not 

7just one. 

8""" 

9from functools import reduce 

10from operator import add 

11from itertools import zip_longest 

12from typing import TYPE_CHECKING, Any 

13 

14from parso.python.tree import Name 

15 

16from jedi import debug 

17from jedi.parser_utils import clean_scope_docstring 

18from jedi.inference.helpers import SimpleGetItemNotFound 

19from jedi.inference.utils import safe_property 

20from jedi.inference.cache import inference_state_as_method_param_cache 

21from jedi.cache import memoize_method 

22 

23sentinel = object() 

24 

25if TYPE_CHECKING: 

26 from jedi.inference import InferenceState 

27 

28 

29class HasNoContext(Exception): 

30 pass 

31 

32 

33class HelperValueMixin: 

34 parent_context: Any 

35 inference_state: "InferenceState" 

36 name: Any 

37 get_filters: Any 

38 is_stub: Any 

39 py__getattribute__alternatives: Any 

40 py__iter__: Any 

41 py__mro__: Any 

42 _as_context: Any 

43 

44 def get_root_context(self): 

45 value = self 

46 if value.parent_context is None: 

47 return value.as_context() 

48 

49 while True: 

50 if value.parent_context is None: 

51 return value 

52 value = value.parent_context 

53 

54 def execute(self, arguments): 

55 return self.inference_state.execute(self, arguments=arguments) 

56 

57 def execute_with_values(self, *value_list): 

58 from jedi.inference.arguments import ValuesArguments 

59 arguments = ValuesArguments([ValueSet([value]) for value in value_list]) 

60 return self.inference_state.execute(self, arguments) 

61 

62 def execute_annotation(self, context): 

63 return self.execute_with_values() 

64 

65 def gather_annotation_classes(self): 

66 return ValueSet([self]) 

67 

68 def merge_types_of_iterate(self, contextualized_node=None, is_async=False): 

69 return ValueSet.from_sets( 

70 lazy_value.infer() 

71 for lazy_value in self.iterate(contextualized_node, is_async) 

72 ) 

73 

74 def _get_value_filters(self, name_or_str): 

75 origin_scope = name_or_str if isinstance(name_or_str, Name) else None 

76 yield from self.get_filters(origin_scope=origin_scope) 

77 # This covers the case where a stub files are incomplete. 

78 if self.is_stub(): 

79 from jedi.inference.gradual.conversion import convert_values 

80 for c in convert_values(ValueSet({self})): 

81 yield from c.get_filters() 

82 

83 def goto(self, name_or_str, name_context=None, analysis_errors=True): 

84 from jedi.inference import finder 

85 filters = self._get_value_filters(name_or_str) 

86 names = finder.filter_name(filters, name_or_str) 

87 debug.dbg('context.goto %s in (%s): %s', name_or_str, self, names) 

88 return names 

89 

90 def py__getattribute__(self, name_or_str, name_context=None, position=None, 

91 analysis_errors=True): 

92 """ 

93 :param position: Position of the last statement -> tuple of line, column 

94 """ 

95 if name_context is None: 

96 name_context = self 

97 names = self.goto(name_or_str, name_context, analysis_errors) 

98 values = ValueSet.from_sets(name.infer() for name in names) 

99 if not values: 

100 n = name_or_str.value if isinstance(name_or_str, Name) else name_or_str 

101 values = self.py__getattribute__alternatives(n) 

102 

103 if not names and not values and analysis_errors: 

104 if isinstance(name_or_str, Name): 

105 from jedi.inference import analysis 

106 analysis.add_attribute_error( 

107 name_context, self, name_or_str) 

108 debug.dbg('context.names_to_types: %s -> %s', names, values) 

109 return values 

110 

111 def py__await__(self): 

112 await_value_set = self.py__getattribute__("__await__") 

113 if not await_value_set: 

114 debug.warning('Tried to run __await__ on value %s', self) 

115 return await_value_set.execute_with_values() 

116 

117 def py__name__(self): 

118 return self.name.string_name 

119 

120 def iterate(self, contextualized_node=None, is_async=False): 

121 debug.dbg('iterate %s', self) 

122 if is_async: 

123 from jedi.inference.lazy_value import LazyKnownValues 

124 # TODO if no __aiter__ values are there, error should be: 

125 # TypeError: 'async for' requires an object with __aiter__ method, got int 

126 return iter([ 

127 LazyKnownValues( 

128 self.py__getattribute__('__aiter__').execute_with_values() 

129 .py__getattribute__('__anext__').execute_with_values() 

130 .py__getattribute__('__await__').execute_with_values() 

131 .py__stop_iteration_returns() 

132 ) # noqa: E124 

133 ]) 

134 return self.py__iter__(contextualized_node) 

135 

136 def is_sub_class_of(self, class_value): 

137 with debug.increase_indent_cm('subclass matching of %s <=> %s' % (self, class_value), 

138 color='BLUE'): 

139 for cls in self.py__mro__(): 

140 if cls.is_same_class(class_value): 

141 debug.dbg('matched subclass True', color='BLUE') 

142 return True 

143 debug.dbg('matched subclass False', color='BLUE') 

144 return False 

145 

146 def is_same_class(self, class2): 

147 # Class matching should prefer comparisons that are not this function. 

148 if type(class2).is_same_class != HelperValueMixin.is_same_class: 

149 return class2.is_same_class(self) 

150 return self == class2 

151 

152 @memoize_method 

153 def as_context(self, *args, **kwargs): 

154 return self._as_context(*args, **kwargs) 

155 

156 

157class Value(HelperValueMixin): 

158 """ 

159 To be implemented by subclasses. 

160 """ 

161 tree_node = None 

162 # Possible values: None, tuple, list, dict and set. Here to deal with these 

163 # very important containers. 

164 array_type = None 

165 api_type = 'not_defined_please_report_bug' 

166 

167 def __init__(self, inference_state, parent_context=None): 

168 self.inference_state = inference_state 

169 self.parent_context = parent_context 

170 

171 def py__getitem__(self, index_value_set, contextualized_node): 

172 from jedi.inference import analysis 

173 # TODO this value is probably not right. 

174 analysis.add( 

175 contextualized_node.context, 

176 'type-error-not-subscriptable', 

177 contextualized_node.node, 

178 message="TypeError: '%s' object is not subscriptable" % self 

179 ) 

180 return NO_VALUES 

181 

182 def py__simple_getitem__(self, index): 

183 raise SimpleGetItemNotFound 

184 

185 def py__iter__(self, contextualized_node=None): 

186 if contextualized_node is not None: 

187 from jedi.inference import analysis 

188 analysis.add( 

189 contextualized_node.context, 

190 'type-error-not-iterable', 

191 contextualized_node.node, 

192 message="TypeError: '%s' object is not iterable" % self) 

193 return iter([]) 

194 

195 def py__next__(self, contextualized_node=None): 

196 return self.py__iter__(contextualized_node) 

197 

198 def get_signatures(self): 

199 return [] 

200 

201 def is_class(self): 

202 return False 

203 

204 def is_class_mixin(self): 

205 return False 

206 

207 def is_instance(self): 

208 return False 

209 

210 def is_function(self): 

211 return False 

212 

213 def is_module(self): 

214 return False 

215 

216 def is_namespace(self): 

217 return False 

218 

219 def is_compiled(self): 

220 return False 

221 

222 def is_bound_method(self): 

223 return False 

224 

225 def is_builtins_module(self): 

226 return False 

227 

228 def py__bool__(self): 

229 """ 

230 Since Wrapper is a super class for classes, functions and modules, 

231 the return value will always be true. 

232 """ 

233 return True 

234 

235 def py__doc__(self): 

236 try: 

237 self.tree_node.get_doc_node 

238 except AttributeError: 

239 return '' 

240 else: 

241 return clean_scope_docstring(self.tree_node) 

242 

243 def get_safe_value(self, default=sentinel): 

244 if default is sentinel: 

245 raise ValueError("There exists no safe value for value %s" % self) 

246 return default 

247 

248 def execute_operation(self, other, operator): 

249 debug.warning("%s not possible between %s and %s", operator, self, other) 

250 return NO_VALUES 

251 

252 def py__call__(self, arguments): 

253 debug.warning("no execution possible %s", self) 

254 return NO_VALUES 

255 

256 def py__stop_iteration_returns(self): 

257 debug.warning("Not possible to return the stop iterations of %s", self) 

258 return NO_VALUES 

259 

260 def py__getattribute__alternatives(self, name_or_str): 

261 """ 

262 For now a way to add values in cases like __getattr__. 

263 """ 

264 return NO_VALUES 

265 

266 def py__get__(self, instance, class_value): 

267 debug.warning("No __get__ defined on %s", self) 

268 return ValueSet([self]) 

269 

270 def py__get__on_class(self, calling_instance, instance, class_value): 

271 return NotImplemented 

272 

273 def get_qualified_names(self): 

274 # Returns Optional[Tuple[str, ...]] 

275 return None 

276 

277 def is_stub(self): 

278 # The root value knows if it's a stub or not. 

279 return self.parent_context.is_stub() 

280 

281 def _as_context(self): 

282 raise HasNoContext 

283 

284 @property 

285 def name(self): 

286 raise NotImplementedError 

287 

288 def get_type_hint(self, add_class_info=True): 

289 return None 

290 

291 def infer_type_vars(self, value_set): 

292 """ 

293 When the current instance represents a type annotation, this method 

294 tries to find information about undefined type vars and returns a dict 

295 from type var name to value set. 

296 

297 This is for example important to understand what `iter([1])` returns. 

298 According to typeshed, `iter` returns an `Iterator[_T]`: 

299 

300 def iter(iterable: Iterable[_T]) -> Iterator[_T]: ... 

301 

302 This functions would generate `int` for `_T` in this case, because it 

303 unpacks the `Iterable`. 

304 

305 Parameters 

306 ---------- 

307 

308 `self`: represents the annotation of the current parameter to infer the 

309 value for. In the above example, this would initially be the 

310 `Iterable[_T]` of the `iterable` parameter and then, when recursing, 

311 just the `_T` generic parameter. 

312 

313 `value_set`: represents the actual argument passed to the parameter 

314 we're inferred for, or (for recursive calls) their types. In the 

315 above example this would first be the representation of the list 

316 `[1]` and then, when recursing, just of `1`. 

317 """ 

318 return {} 

319 

320 

321def iterate_values(values, contextualized_node=None, is_async=False): 

322 """ 

323 Calls `iterate`, on all values but ignores the ordering and just returns 

324 all values that the iterate functions yield. 

325 """ 

326 return ValueSet.from_sets( 

327 lazy_value.infer() 

328 for lazy_value in values.iterate(contextualized_node, is_async=is_async) 

329 ) 

330 

331 

332class _ValueWrapperBase(HelperValueMixin): 

333 @safe_property 

334 def name(self): 

335 from jedi.inference.names import ValueName 

336 wrapped_name = self._wrapped_value.name 

337 if wrapped_name.tree_name is not None: 

338 return ValueName(self, wrapped_name.tree_name) 

339 else: 

340 from jedi.inference.compiled import CompiledValueName 

341 return CompiledValueName(self, wrapped_name.string_name) 

342 

343 @classmethod 

344 @inference_state_as_method_param_cache() 

345 def create_cached(cls, inference_state, *args, **kwargs): 

346 return cls(*args, **kwargs) 

347 

348 def __getattr__(self, name): 

349 assert name != '_wrapped_value', 'Problem with _get_wrapped_value' 

350 return getattr(self._wrapped_value, name) 

351 

352 

353class LazyValueWrapper(_ValueWrapperBase): 

354 if TYPE_CHECKING: 

355 @property 

356 def _wrapped_value(self) -> Any: 

357 return 

358 else: 

359 @safe_property 

360 @memoize_method 

361 def _wrapped_value(self): 

362 with debug.increase_indent_cm('Resolve lazy value wrapper'): 

363 return self._get_wrapped_value() 

364 

365 def __repr__(self): 

366 return '<%s>' % (self.__class__.__name__) 

367 

368 def _get_wrapped_value(self): 

369 raise NotImplementedError 

370 

371 

372class ValueWrapper(_ValueWrapperBase): 

373 def __init__(self, wrapped_value): 

374 self._wrapped_value = wrapped_value 

375 

376 def __repr__(self): 

377 return '%s(%s)' % (self.__class__.__name__, self._wrapped_value) 

378 

379 

380class TreeValue(Value): 

381 def __init__(self, inference_state, parent_context, tree_node): 

382 super().__init__(inference_state, parent_context) 

383 self.tree_node = tree_node 

384 

385 def __repr__(self): 

386 return '<%s: %s>' % (self.__class__.__name__, self.tree_node) 

387 

388 

389class ContextualizedNode: 

390 def __init__(self, context, node): 

391 self.context = context 

392 self.node = node 

393 

394 def get_root_context(self): 

395 return self.context.get_root_context() 

396 

397 def infer(self): 

398 return self.context.infer_node(self.node) 

399 

400 def __repr__(self): 

401 return '<%s: %s in %s>' % (self.__class__.__name__, self.node, self.context) 

402 

403 

404def _getitem(value, index_values, contextualized_node): 

405 # The actual getitem call. 

406 result = NO_VALUES 

407 unused_values = set() 

408 for index_value in index_values: 

409 index = index_value.get_safe_value(default=None) 

410 if type(index) in (float, int, str, slice, bytes): 

411 try: 

412 result |= value.py__simple_getitem__(index) 

413 continue 

414 except SimpleGetItemNotFound: 

415 pass 

416 

417 unused_values.add(index_value) 

418 

419 # The index was somehow not good enough or simply a wrong type. 

420 # Therefore we now iterate through all the values and just take 

421 # all results. 

422 if unused_values or not index_values: 

423 result |= value.py__getitem__( 

424 ValueSet(unused_values), 

425 contextualized_node 

426 ) 

427 debug.dbg('py__getitem__ result: %s', result) 

428 return result 

429 

430 

431class ValueSet: 

432 def __init__(self, iterable): 

433 self._set = frozenset(iterable) 

434 for value in iterable: 

435 assert not isinstance(value, ValueSet) 

436 

437 @classmethod 

438 def _from_frozen_set(cls, frozenset_): 

439 self = cls.__new__(cls) 

440 self._set = frozenset_ 

441 return self 

442 

443 @classmethod 

444 def from_sets(cls, sets): 

445 """ 

446 Used to work with an iterable of set. 

447 """ 

448 aggregated = set() 

449 for set_ in sets: 

450 if isinstance(set_, ValueSet): 

451 aggregated |= set_._set 

452 else: 

453 aggregated |= frozenset(set_) 

454 return cls._from_frozen_set(frozenset(aggregated)) 

455 

456 def __or__(self, other): 

457 return self._from_frozen_set(self._set | other._set) 

458 

459 def __and__(self, other): 

460 return self._from_frozen_set(self._set & other._set) 

461 

462 def __iter__(self): 

463 return iter(self._set) 

464 

465 def __bool__(self): 

466 return bool(self._set) 

467 

468 def __len__(self): 

469 return len(self._set) 

470 

471 def __repr__(self): 

472 return 'S{%s}' % (', '.join(str(s) for s in self._set)) 

473 

474 def filter(self, filter_func): 

475 return self.__class__(filter(filter_func, self._set)) 

476 

477 def __getattr__(self, name): 

478 def mapper(*args, **kwargs): 

479 return self.from_sets( 

480 getattr(value, name)(*args, **kwargs) 

481 for value in self._set 

482 ) 

483 return mapper 

484 

485 def __eq__(self, other): 

486 return self._set == other._set 

487 

488 def __ne__(self, other): 

489 return not self.__eq__(other) 

490 

491 def __hash__(self): 

492 return hash(self._set) 

493 

494 def py__class__(self): 

495 return ValueSet(c.py__class__() for c in self._set) 

496 

497 def iterate(self, contextualized_node=None, is_async=False): 

498 from jedi.inference.lazy_value import get_merged_lazy_value 

499 type_iters = [c.iterate(contextualized_node, is_async=is_async) for c in self._set] 

500 for lazy_values in zip_longest(*type_iters): 

501 yield get_merged_lazy_value( 

502 [l for l in lazy_values if l is not None] 

503 ) 

504 

505 def execute(self, arguments): 

506 return ValueSet.from_sets(c.inference_state.execute(c, arguments) for c in self._set) 

507 

508 def execute_with_values(self, *args, **kwargs): 

509 return ValueSet.from_sets(c.execute_with_values(*args, **kwargs) for c in self._set) 

510 

511 def goto(self, *args, **kwargs): 

512 return reduce(add, [c.goto(*args, **kwargs) for c in self._set], []) 

513 

514 def py__getattribute__(self, *args, **kwargs): 

515 return ValueSet.from_sets(c.py__getattribute__(*args, **kwargs) for c in self._set) 

516 

517 def get_item(self, *args, **kwargs): 

518 return ValueSet.from_sets(_getitem(c, *args, **kwargs) for c in self._set) 

519 

520 def try_merge(self, function_name): 

521 value_set = ValueSet([]) 

522 for c in self._set: 

523 try: 

524 method = getattr(c, function_name) 

525 except AttributeError: 

526 pass 

527 else: 

528 value_set |= method() 

529 return value_set 

530 

531 def gather_annotation_classes(self): 

532 return ValueSet.from_sets([c.gather_annotation_classes() for c in self._set]) 

533 

534 def get_signatures(self): 

535 return [sig for c in self._set for sig in c.get_signatures()] 

536 

537 def get_type_hint(self, add_class_info=True): 

538 t = [v.get_type_hint(add_class_info=add_class_info) for v in self._set] 

539 type_hints = sorted(filter(None, t)) 

540 if len(type_hints) == 1: 

541 return type_hints[0] 

542 

543 optional = 'None' in type_hints 

544 if optional: 

545 type_hints.remove('None') 

546 

547 if len(type_hints) == 0: 

548 return None 

549 elif len(type_hints) == 1: 

550 s = type_hints[0] 

551 else: 

552 s = 'Union[%s]' % ', '.join(type_hints) 

553 if optional: 

554 s = 'Optional[%s]' % s 

555 return s 

556 

557 def infer_type_vars(self, value_set): 

558 # Circular 

559 from jedi.inference.gradual.annotation import merge_type_var_dicts 

560 

561 type_var_dict = {} 

562 for value in self._set: 

563 merge_type_var_dicts( 

564 type_var_dict, 

565 value.infer_type_vars(value_set), 

566 ) 

567 return type_var_dict 

568 

569 

570NO_VALUES = ValueSet([]) 

571 

572 

573def iterator_to_value_set(func): 

574 def wrapper(*args, **kwargs): 

575 return ValueSet(func(*args, **kwargs)) 

576 

577 return wrapper