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

333 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-20 06:09 +0000

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 

12 

13from parso.python.tree import Name 

14 

15from jedi import debug 

16from jedi.parser_utils import clean_scope_docstring 

17from jedi.inference.helpers import SimpleGetItemNotFound 

18from jedi.inference.utils import safe_property 

19from jedi.inference.cache import inference_state_as_method_param_cache 

20from jedi.cache import memoize_method 

21 

22sentinel = object() 

23 

24 

25class HasNoContext(Exception): 

26 pass 

27 

28 

29class HelperValueMixin: 

30 def get_root_context(self): 

31 value = self 

32 if value.parent_context is None: 

33 return value.as_context() 

34 

35 while True: 

36 if value.parent_context is None: 

37 return value 

38 value = value.parent_context 

39 

40 def execute(self, arguments): 

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

42 

43 def execute_with_values(self, *value_list): 

44 from jedi.inference.arguments import ValuesArguments 

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

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

47 

48 def execute_annotation(self): 

49 return self.execute_with_values() 

50 

51 def gather_annotation_classes(self): 

52 return ValueSet([self]) 

53 

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

55 return ValueSet.from_sets( 

56 lazy_value.infer() 

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

58 ) 

59 

60 def _get_value_filters(self, name_or_str): 

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

62 yield from self.get_filters(origin_scope=origin_scope) 

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

64 if self.is_stub(): 

65 from jedi.inference.gradual.conversion import convert_values 

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

67 yield from c.get_filters() 

68 

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

70 from jedi.inference import finder 

71 filters = self._get_value_filters(name_or_str) 

72 names = finder.filter_name(filters, name_or_str) 

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

74 return names 

75 

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

77 analysis_errors=True): 

78 """ 

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

80 """ 

81 if name_context is None: 

82 name_context = self 

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

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

85 if not values: 

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

87 values = self.py__getattribute__alternatives(n) 

88 

89 if not names and not values and analysis_errors: 

90 if isinstance(name_or_str, Name): 

91 from jedi.inference import analysis 

92 analysis.add_attribute_error( 

93 name_context, self, name_or_str) 

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

95 return values 

96 

97 def py__await__(self): 

98 await_value_set = self.py__getattribute__("__await__") 

99 if not await_value_set: 

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

101 return await_value_set.execute_with_values() 

102 

103 def py__name__(self): 

104 return self.name.string_name 

105 

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

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

108 if is_async: 

109 from jedi.inference.lazy_value import LazyKnownValues 

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

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

112 return iter([ 

113 LazyKnownValues( 

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

115 .py__getattribute__('__anext__').execute_with_values() 

116 .py__getattribute__('__await__').execute_with_values() 

117 .py__stop_iteration_returns() 

118 ) # noqa: E124 

119 ]) 

120 return self.py__iter__(contextualized_node) 

121 

122 def is_sub_class_of(self, class_value): 

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

124 color='BLUE'): 

125 for cls in self.py__mro__(): 

126 if cls.is_same_class(class_value): 

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

128 return True 

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

130 return False 

131 

132 def is_same_class(self, class2): 

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

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

135 return class2.is_same_class(self) 

136 return self == class2 

137 

138 @memoize_method 

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

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

141 

142 

143class Value(HelperValueMixin): 

144 """ 

145 To be implemented by subclasses. 

146 """ 

147 tree_node = None 

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

149 # very important containers. 

150 array_type = None 

151 api_type = 'not_defined_please_report_bug' 

152 

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

154 self.inference_state = inference_state 

155 self.parent_context = parent_context 

156 

157 def py__getitem__(self, index_value_set, contextualized_node): 

158 from jedi.inference import analysis 

159 # TODO this value is probably not right. 

160 analysis.add( 

161 contextualized_node.context, 

162 'type-error-not-subscriptable', 

163 contextualized_node.node, 

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

165 ) 

166 return NO_VALUES 

167 

168 def py__simple_getitem__(self, index): 

169 raise SimpleGetItemNotFound 

170 

171 def py__iter__(self, contextualized_node=None): 

172 if contextualized_node is not None: 

173 from jedi.inference import analysis 

174 analysis.add( 

175 contextualized_node.context, 

176 'type-error-not-iterable', 

177 contextualized_node.node, 

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

179 return iter([]) 

180 

181 def py__next__(self, contextualized_node=None): 

182 return self.py__iter__(contextualized_node) 

183 

184 def get_signatures(self): 

185 return [] 

186 

187 def is_class(self): 

188 return False 

189 

190 def is_class_mixin(self): 

191 return False 

192 

193 def is_instance(self): 

194 return False 

195 

196 def is_function(self): 

197 return False 

198 

199 def is_module(self): 

200 return False 

201 

202 def is_namespace(self): 

203 return False 

204 

205 def is_compiled(self): 

206 return False 

207 

208 def is_bound_method(self): 

209 return False 

210 

211 def is_builtins_module(self): 

212 return False 

213 

214 def py__bool__(self): 

215 """ 

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

217 the return value will always be true. 

218 """ 

219 return True 

220 

221 def py__doc__(self): 

222 try: 

223 self.tree_node.get_doc_node 

224 except AttributeError: 

225 return '' 

226 else: 

227 return clean_scope_docstring(self.tree_node) 

228 

229 def get_safe_value(self, default=sentinel): 

230 if default is sentinel: 

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

232 return default 

233 

234 def execute_operation(self, other, operator): 

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

236 return NO_VALUES 

237 

238 def py__call__(self, arguments): 

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

240 return NO_VALUES 

241 

242 def py__stop_iteration_returns(self): 

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

244 return NO_VALUES 

245 

246 def py__getattribute__alternatives(self, name_or_str): 

247 """ 

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

249 """ 

250 return NO_VALUES 

251 

252 def py__get__(self, instance, class_value): 

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

254 return ValueSet([self]) 

255 

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

257 return NotImplemented 

258 

259 def get_qualified_names(self): 

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

261 return None 

262 

263 def is_stub(self): 

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

265 return self.parent_context.is_stub() 

266 

267 def _as_context(self): 

268 raise HasNoContext 

269 

270 @property 

271 def name(self): 

272 raise NotImplementedError 

273 

274 def get_type_hint(self, add_class_info=True): 

275 return None 

276 

277 def infer_type_vars(self, value_set): 

278 """ 

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

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

281 from type var name to value set. 

282 

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

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

285 

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

287 

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

289 unpacks the `Iterable`. 

290 

291 Parameters 

292 ---------- 

293 

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

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

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

297 just the `_T` generic parameter. 

298 

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

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

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

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

303 """ 

304 return {} 

305 

306 

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

308 """ 

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

310 all values that the iterate functions yield. 

311 """ 

312 return ValueSet.from_sets( 

313 lazy_value.infer() 

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

315 ) 

316 

317 

318class _ValueWrapperBase(HelperValueMixin): 

319 @safe_property 

320 def name(self): 

321 from jedi.inference.names import ValueName 

322 wrapped_name = self._wrapped_value.name 

323 if wrapped_name.tree_name is not None: 

324 return ValueName(self, wrapped_name.tree_name) 

325 else: 

326 from jedi.inference.compiled import CompiledValueName 

327 return CompiledValueName(self, wrapped_name.string_name) 

328 

329 @classmethod 

330 @inference_state_as_method_param_cache() 

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

332 return cls(*args, **kwargs) 

333 

334 def __getattr__(self, name): 

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

336 return getattr(self._wrapped_value, name) 

337 

338 

339class LazyValueWrapper(_ValueWrapperBase): 

340 @safe_property 

341 @memoize_method 

342 def _wrapped_value(self): 

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

344 return self._get_wrapped_value() 

345 

346 def __repr__(self): 

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

348 

349 def _get_wrapped_value(self): 

350 raise NotImplementedError 

351 

352 

353class ValueWrapper(_ValueWrapperBase): 

354 def __init__(self, wrapped_value): 

355 self._wrapped_value = wrapped_value 

356 

357 def __repr__(self): 

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

359 

360 

361class TreeValue(Value): 

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

363 super().__init__(inference_state, parent_context) 

364 self.tree_node = tree_node 

365 

366 def __repr__(self): 

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

368 

369 

370class ContextualizedNode: 

371 def __init__(self, context, node): 

372 self.context = context 

373 self.node = node 

374 

375 def get_root_context(self): 

376 return self.context.get_root_context() 

377 

378 def infer(self): 

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

380 

381 def __repr__(self): 

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

383 

384 

385def _getitem(value, index_values, contextualized_node): 

386 # The actual getitem call. 

387 result = NO_VALUES 

388 unused_values = set() 

389 for index_value in index_values: 

390 index = index_value.get_safe_value(default=None) 

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

392 try: 

393 result |= value.py__simple_getitem__(index) 

394 continue 

395 except SimpleGetItemNotFound: 

396 pass 

397 

398 unused_values.add(index_value) 

399 

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

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

402 # all results. 

403 if unused_values or not index_values: 

404 result |= value.py__getitem__( 

405 ValueSet(unused_values), 

406 contextualized_node 

407 ) 

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

409 return result 

410 

411 

412class ValueSet: 

413 def __init__(self, iterable): 

414 self._set = frozenset(iterable) 

415 for value in iterable: 

416 assert not isinstance(value, ValueSet) 

417 

418 @classmethod 

419 def _from_frozen_set(cls, frozenset_): 

420 self = cls.__new__(cls) 

421 self._set = frozenset_ 

422 return self 

423 

424 @classmethod 

425 def from_sets(cls, sets): 

426 """ 

427 Used to work with an iterable of set. 

428 """ 

429 aggregated = set() 

430 for set_ in sets: 

431 if isinstance(set_, ValueSet): 

432 aggregated |= set_._set 

433 else: 

434 aggregated |= frozenset(set_) 

435 return cls._from_frozen_set(frozenset(aggregated)) 

436 

437 def __or__(self, other): 

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

439 

440 def __and__(self, other): 

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

442 

443 def __iter__(self): 

444 return iter(self._set) 

445 

446 def __bool__(self): 

447 return bool(self._set) 

448 

449 def __len__(self): 

450 return len(self._set) 

451 

452 def __repr__(self): 

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

454 

455 def filter(self, filter_func): 

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

457 

458 def __getattr__(self, name): 

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

460 return self.from_sets( 

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

462 for value in self._set 

463 ) 

464 return mapper 

465 

466 def __eq__(self, other): 

467 return self._set == other._set 

468 

469 def __ne__(self, other): 

470 return not self.__eq__(other) 

471 

472 def __hash__(self): 

473 return hash(self._set) 

474 

475 def py__class__(self): 

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

477 

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

479 from jedi.inference.lazy_value import get_merged_lazy_value 

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

481 for lazy_values in zip_longest(*type_iters): 

482 yield get_merged_lazy_value( 

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

484 ) 

485 

486 def execute(self, arguments): 

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

488 

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

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

491 

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

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

494 

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

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

497 

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

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

500 

501 def try_merge(self, function_name): 

502 value_set = self.__class__([]) 

503 for c in self._set: 

504 try: 

505 method = getattr(c, function_name) 

506 except AttributeError: 

507 pass 

508 else: 

509 value_set |= method() 

510 return value_set 

511 

512 def gather_annotation_classes(self): 

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

514 

515 def get_signatures(self): 

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

517 

518 def get_type_hint(self, add_class_info=True): 

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

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

521 if len(type_hints) == 1: 

522 return type_hints[0] 

523 

524 optional = 'None' in type_hints 

525 if optional: 

526 type_hints.remove('None') 

527 

528 if len(type_hints) == 0: 

529 return None 

530 elif len(type_hints) == 1: 

531 s = type_hints[0] 

532 else: 

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

534 if optional: 

535 s = 'Optional[%s]' % s 

536 return s 

537 

538 def infer_type_vars(self, value_set): 

539 # Circular 

540 from jedi.inference.gradual.annotation import merge_type_var_dicts 

541 

542 type_var_dict = {} 

543 for value in self._set: 

544 merge_type_var_dicts( 

545 type_var_dict, 

546 value.infer_type_vars(value_set), 

547 ) 

548 return type_var_dict 

549 

550 

551NO_VALUES = ValueSet([]) 

552 

553 

554def iterator_to_value_set(func): 

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

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

557 

558 return wrapper