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

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

263 statements  

1""" 

2We need to somehow work with the typing objects. Since the typing objects are 

3pretty bare we need to add all the Jedi customizations to make them work as 

4values. 

5 

6This file deals with all the typing.py cases. 

7""" 

8import itertools 

9from typing import Any 

10 

11from jedi import debug 

12from jedi.inference.compiled import builtin_from_name, create_simple_object 

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

14 LazyValueWrapper, ValueWrapper 

15from jedi.inference.lazy_value import LazyKnownValues 

16from jedi.inference.arguments import repack_with_argument_clinic 

17from jedi.inference.filters import FilterWrapper 

18from jedi.inference.names import NameWrapper, ValueName 

19from jedi.inference.value.klass import ClassMixin 

20from jedi.inference.gradual.base import BaseTypingValue, \ 

21 BaseTypingClassWithGenerics, BaseTypingInstance 

22from jedi.inference.gradual.type_var import TypeVarClass 

23from jedi.inference.gradual.generics import LazyGenericManager, TupleGenericManager 

24 

25_PROXY_CLASS_TYPES = 'Tuple Generic Protocol Callable Type'.split() 

26_TYPE_ALIAS_TYPES = { 

27 'List': 'builtins.list', 

28 'Dict': 'builtins.dict', 

29 'Set': 'builtins.set', 

30 'FrozenSet': 'builtins.frozenset', 

31 'ChainMap': 'collections.ChainMap', 

32 'Counter': 'collections.Counter', 

33 'DefaultDict': 'collections.defaultdict', 

34 'Deque': 'collections.deque', 

35} 

36_PROXY_TYPES = ['Optional', 'Union', 'ClassVar', 'Annotated', 'Final'] 

37IGNORE_ANNOTATION_PARTS = ['ClassVar', 'Annotated', 'Final'] 

38 

39 

40class TypingModuleName(NameWrapper): 

41 def infer(self): 

42 return ValueSet(self._remap()) 

43 

44 def _remap(self): 

45 name = self.string_name 

46 inference_state = self.parent_context.inference_state 

47 try: 

48 actual = _TYPE_ALIAS_TYPES[name] 

49 except KeyError: 

50 pass 

51 else: 

52 yield TypeAlias.create_cached( 

53 inference_state, self.parent_context, self.tree_name, actual) 

54 return 

55 

56 if name in _PROXY_CLASS_TYPES: 

57 yield ProxyTypingClassValue.create_cached( 

58 inference_state, self.parent_context, self.tree_name) 

59 elif name in _PROXY_TYPES: 

60 yield ProxyTypingValue.create_cached( 

61 inference_state, self.parent_context, self.tree_name) 

62 elif name == 'runtime': 

63 # We don't want anything here, not sure what this function is 

64 # supposed to do, since it just appears in the stubs and shouldn't 

65 # have any effects there (because it's never executed). 

66 return 

67 elif name == 'TypeVar': 

68 cls, = self._wrapped_name.infer() 

69 yield TypeVarClass.create_cached(inference_state, cls) 

70 elif name == 'Any': 

71 yield AnyClass.create_cached( 

72 inference_state, self.parent_context, self.tree_name) 

73 elif name == 'TYPE_CHECKING': 

74 # This is needed for e.g. imports that are only available for type 

75 # checking or are in cycles. The user can then check this variable. 

76 yield builtin_from_name(inference_state, 'True') 

77 elif name == 'overload': 

78 yield OverloadFunction.create_cached( 

79 inference_state, self.parent_context, self.tree_name) 

80 elif name == 'NewType': 

81 v, = self._wrapped_name.infer() 

82 yield NewTypeFunction.create_cached(inference_state, v) 

83 elif name == 'cast': 

84 cast_fn, = self._wrapped_name.infer() 

85 yield CastFunction.create_cached(inference_state, cast_fn) 

86 elif name == 'Self': 

87 yield SelfClass.create_cached( 

88 inference_state, self.parent_context, self.tree_name) 

89 elif name == 'TypedDict': 

90 # TODO doesn't even exist in typeshed/typing.py, yet. But will be 

91 # added soon. 

92 yield TypedDictClass.create_cached( 

93 inference_state, self.parent_context, self.tree_name) 

94 else: 

95 # Not necessary, as long as we are not doing type checking: 

96 # no_type_check & no_type_check_decorator 

97 # Everything else shouldn't be relevant... 

98 yield from self._wrapped_name.infer() 

99 

100 

101class TypingModuleFilterWrapper(FilterWrapper): 

102 name_wrapper_class = TypingModuleName 

103 

104 

105class ProxyWithGenerics(BaseTypingClassWithGenerics): 

106 def execute_annotation(self, context): 

107 string_name = self._tree_name.value 

108 

109 if string_name == 'Union': 

110 # This is kind of a special case, because we have Unions (in Jedi 

111 # ValueSets). 

112 return self.gather_annotation_classes().execute_annotation(context) 

113 elif string_name == 'Optional': 

114 # Optional is basically just saying it's either None or the actual 

115 # type. 

116 return self.gather_annotation_classes().execute_annotation(context) \ 

117 | ValueSet([builtin_from_name(self.inference_state, 'None')]) 

118 elif string_name == 'Type': 

119 # The type is actually already given in the index_value 

120 return self._generics_manager[0] 

121 elif string_name in IGNORE_ANNOTATION_PARTS: 

122 # For now don't do anything here, ClassVars are always used. 

123 return self._generics_manager[0].execute_annotation(context) 

124 

125 mapped = { 

126 'Tuple': Tuple, 

127 'Generic': Generic, 

128 'Protocol': Protocol, 

129 'Callable': Callable, 

130 } 

131 cls = mapped[string_name] 

132 return ValueSet([cls( 

133 self.parent_context, 

134 self, 

135 self._tree_name, 

136 generics_manager=self._generics_manager, 

137 )]) 

138 

139 def gather_annotation_classes(self): 

140 return ValueSet.from_sets(self._generics_manager.to_tuple()) 

141 

142 def _create_instance_with_generics(self, generics_manager): 

143 return ProxyWithGenerics( 

144 self.parent_context, 

145 self._tree_name, 

146 generics_manager 

147 ) 

148 

149 def infer_type_vars(self, value_set): 

150 annotation_generics = self.get_generics() 

151 

152 if not annotation_generics: 

153 return {} 

154 

155 annotation_name = self.py__name__() 

156 if annotation_name == 'Optional': 

157 # Optional[T] is equivalent to Union[T, None]. In Jedi unions 

158 # are represented by members within a ValueSet, so we extract 

159 # the T from the Optional[T] by removing the None value. 

160 none = builtin_from_name(self.inference_state, 'None') 

161 return annotation_generics[0].infer_type_vars( 

162 value_set.filter(lambda x: x != none), 

163 ) 

164 

165 return {} 

166 

167 

168class ProxyTypingValue(BaseTypingValue): 

169 index_class = ProxyWithGenerics 

170 

171 def with_generics(self, generics_tuple): 

172 return self.index_class.create_cached( 

173 self.inference_state, 

174 self.parent_context, 

175 self._tree_name, 

176 generics_manager=TupleGenericManager(generics_tuple) 

177 ) 

178 

179 def py__getitem__(self, index_value_set, contextualized_node): 

180 return ValueSet( 

181 self.index_class.create_cached( 

182 self.inference_state, 

183 self.parent_context, 

184 self._tree_name, 

185 generics_manager=LazyGenericManager( 

186 context_of_index=contextualized_node.context, 

187 index_value=index_value, 

188 ) 

189 ) for index_value in index_value_set 

190 ) 

191 

192 

193class _TypingClassMixin(ClassMixin): 

194 _tree_name: Any 

195 

196 def py__bases__(self): 

197 return [LazyKnownValues( 

198 self.inference_state.builtins_module.py__getattribute__('object') 

199 )] 

200 

201 def get_metaclasses(self): 

202 return [] 

203 

204 @property 

205 def name(self): 

206 return ValueName(self, self._tree_name) 

207 

208 

209class TypingClassWithGenerics(ProxyWithGenerics, _TypingClassMixin): 

210 def infer_type_vars(self, value_set): 

211 type_var_dict = {} 

212 annotation_generics = self.get_generics() 

213 

214 if not annotation_generics: 

215 return type_var_dict 

216 

217 annotation_name = self.py__name__() 

218 if annotation_name == 'Type': 

219 return annotation_generics[0].infer_type_vars( 

220 # This is basically a trick to avoid extra code: We execute the 

221 # incoming classes to be able to use the normal code for type 

222 # var inference. 

223 value_set.execute_annotation(None), 

224 ) 

225 

226 elif annotation_name == 'Callable': 

227 if len(annotation_generics) == 2: 

228 return annotation_generics[1].infer_type_vars( 

229 value_set.execute_annotation(None), 

230 ) 

231 

232 elif annotation_name == 'Tuple': 

233 tuple_annotation, = self.execute_annotation(None) 

234 return tuple_annotation.infer_type_vars(value_set) 

235 

236 return type_var_dict 

237 

238 def _create_instance_with_generics(self, generics_manager): 

239 return TypingClassWithGenerics( 

240 self.parent_context, 

241 self._tree_name, 

242 generics_manager 

243 ) 

244 

245 

246class ProxyTypingClassValue(ProxyTypingValue, _TypingClassMixin): 

247 index_class = TypingClassWithGenerics 

248 

249 

250class TypeAlias(LazyValueWrapper): 

251 def __init__(self, parent_context, origin_tree_name, actual): 

252 self.inference_state = parent_context.inference_state 

253 self.parent_context = parent_context 

254 self._origin_tree_name = origin_tree_name 

255 self._actual = actual # e.g. builtins.list 

256 

257 @property 

258 def name(self): 

259 return ValueName(self, self._origin_tree_name) 

260 

261 def py__name__(self): 

262 return self.name.string_name 

263 

264 def __repr__(self): 

265 return '<%s: %s>' % (self.__class__.__name__, self._actual) 

266 

267 def _get_wrapped_value(self): 

268 module_name, class_name = self._actual.split('.') 

269 

270 # TODO use inference_state.import_module? 

271 from jedi.inference.imports import Importer 

272 module, = Importer( 

273 self.inference_state, [module_name], self.inference_state.builtins_module 

274 ).follow() 

275 classes = module.py__getattribute__(class_name) 

276 # There should only be one, because it's code that we control. 

277 assert len(classes) == 1, classes 

278 cls = next(iter(classes)) 

279 return cls 

280 

281 def gather_annotation_classes(self): 

282 return ValueSet([self._get_wrapped_value()]) 

283 

284 def get_signatures(self): 

285 return [] 

286 

287 

288class Callable(BaseTypingInstance): 

289 def py__call__(self, arguments): 

290 """ 

291 def x() -> Callable[[Callable[..., _T]], _T]: ... 

292 """ 

293 # The 0th index are the arguments. 

294 try: 

295 param_values = self._generics_manager[0] 

296 result_values = self._generics_manager[1] 

297 except IndexError: 

298 debug.warning('Callable[...] defined without two arguments') 

299 return NO_VALUES 

300 else: 

301 from jedi.inference.gradual.annotation import infer_return_for_callable 

302 return infer_return_for_callable(arguments, param_values, result_values) 

303 

304 def py__get__(self, instance, class_value): 

305 return ValueSet([self]) 

306 

307 

308class Tuple(BaseTypingInstance): 

309 def _is_homogenous(self): 

310 # To specify a variable-length tuple of homogeneous type, Tuple[T, ...] 

311 # is used. 

312 return self._generics_manager.is_homogenous_tuple() 

313 

314 def py__simple_getitem__(self, index): 

315 if self._is_homogenous(): 

316 return self._generics_manager.get_index_and_execute(0) 

317 else: 

318 if isinstance(index, int): 

319 return self._generics_manager.get_index_and_execute(index) 

320 

321 debug.dbg('The getitem type on Tuple was %s' % index) 

322 return NO_VALUES 

323 

324 def py__iter__(self, contextualized_node=None): 

325 if self._is_homogenous(): 

326 yield LazyKnownValues(self._generics_manager.get_index_and_execute(0)) 

327 else: 

328 for v in self._generics_manager.to_tuple(): 

329 yield LazyKnownValues(v.execute_annotation(None)) 

330 

331 def py__getitem__(self, index_value_set, contextualized_node): 

332 if self._is_homogenous(): 

333 return self._generics_manager.get_index_and_execute(0) 

334 

335 return ValueSet.from_sets( 

336 self._generics_manager.to_tuple() 

337 ).execute_annotation(None) 

338 

339 def _get_wrapped_value(self): 

340 tuple_, = self.inference_state.builtins_module \ 

341 .py__getattribute__('tuple').execute_annotation(None) 

342 return tuple_ 

343 

344 @property 

345 def name(self): 

346 return self._wrapped_value.name 

347 

348 def infer_type_vars(self, value_set): 

349 # Circular 

350 from jedi.inference.gradual.annotation import merge_pairwise_generics, merge_type_var_dicts 

351 

352 value_set = value_set.filter( 

353 lambda x: x.py__name__().lower() == 'tuple', 

354 ) 

355 

356 if self._is_homogenous(): 

357 # The parameter annotation is of the form `Tuple[T, ...]`, 

358 # so we treat the incoming tuple like a iterable sequence 

359 # rather than a positional container of elements. 

360 return self._class_value.get_generics()[0].infer_type_vars( 

361 value_set.merge_types_of_iterate(), 

362 ) 

363 

364 else: 

365 # The parameter annotation has only explicit type parameters 

366 # (e.g: `Tuple[T]`, `Tuple[T, U]`, `Tuple[T, U, V]`, etc.) so we 

367 # treat the incoming values as needing to match the annotation 

368 # exactly, just as we would for non-tuple annotations. 

369 

370 type_var_dict = {} 

371 for element in value_set: 

372 try: 

373 method = element.get_annotated_class_object 

374 except AttributeError: 

375 # This might still happen, because the tuple name matching 

376 # above is not 100% correct, so just catch the remaining 

377 # cases here. 

378 continue 

379 

380 py_class = method() 

381 merge_type_var_dicts( 

382 type_var_dict, 

383 merge_pairwise_generics(self._class_value, py_class), 

384 ) 

385 

386 return type_var_dict 

387 

388 

389class Generic(BaseTypingInstance): 

390 pass 

391 

392 

393class Protocol(BaseTypingInstance): 

394 pass 

395 

396 

397class AnyClass(BaseTypingValue): 

398 def execute_annotation(self, context): 

399 debug.warning('Used Any - returned no results') 

400 return NO_VALUES 

401 

402 

403class SelfClass(BaseTypingValue): 

404 def execute_annotation(self, context): 

405 debug.warning('Used Self') 

406 if context is not None: 

407 # Execute the class of Self 

408 return context.get_value().execute_annotation(None) 

409 return NO_VALUES 

410 

411 

412class OverloadFunction(BaseTypingValue): 

413 @repack_with_argument_clinic('func, /') 

414 def py__call__(self, func_value_set): 

415 # Just pass arguments through. 

416 return func_value_set 

417 

418 

419class NewTypeFunction(ValueWrapper): 

420 def py__call__(self, arguments): 

421 ordered_args = arguments.unpack() 

422 next(ordered_args, (None, None)) 

423 _, second_arg = next(ordered_args, (None, None)) 

424 if second_arg is None: 

425 return NO_VALUES 

426 return ValueSet( 

427 NewType( 

428 self.inference_state, 

429 contextualized_node.context, 

430 contextualized_node.node, 

431 second_arg.infer(), 

432 ) for contextualized_node in arguments.get_calling_nodes()) 

433 

434 

435class NewType(Value): 

436 def __init__(self, inference_state, parent_context, tree_node, type_value_set): 

437 super().__init__(inference_state, parent_context) 

438 self._type_value_set = type_value_set 

439 self.tree_node = tree_node 

440 

441 def py__class__(self): 

442 c, = self._type_value_set.py__class__() 

443 return c 

444 

445 def py__call__(self, arguments): 

446 return self._type_value_set.execute_annotation(arguments.context) 

447 

448 @property 

449 def name(self): 

450 from jedi.inference.compiled.value import CompiledValueName 

451 return CompiledValueName(self, 'NewType') 

452 

453 def __repr__(self) -> str: 

454 return '<NewType: %s>%s' % (self.tree_node, self._type_value_set) 

455 

456 

457class CastFunction(ValueWrapper): 

458 @repack_with_argument_clinic('type, object, /') 

459 def py__call__(self, type_value_set, object_value_set): 

460 return type_value_set.execute_annotation(None) 

461 

462 

463class TypedDictClass(BaseTypingValue): 

464 """ 

465 This class has no responsibilities and is just here to make sure that typed 

466 dicts can be identified. 

467 """ 

468 

469 

470class TypedDict(LazyValueWrapper): 

471 """Represents the instance version of ``TypedDictClass``.""" 

472 def __init__(self, definition_class): 

473 self.inference_state = definition_class.inference_state 

474 self.parent_context = definition_class.parent_context 

475 self.tree_node = definition_class.tree_node 

476 self._definition_class = definition_class 

477 

478 @property 

479 def name(self): 

480 return ValueName(self, self.tree_node.name) 

481 

482 def py__simple_getitem__(self, index): 

483 if isinstance(index, str): 

484 return ValueSet.from_sets( 

485 name.infer() 

486 for filter in self._definition_class.get_filters(is_instance=True) 

487 for name in filter.get(index) 

488 ) 

489 return NO_VALUES 

490 

491 def get_key_values(self): 

492 filtered_values = itertools.chain.from_iterable(( 

493 f.values() 

494 for f in self._definition_class.get_filters(is_instance=True) 

495 )) 

496 return ValueSet({ 

497 create_simple_object(self.inference_state, v.string_name) 

498 for v in filtered_values 

499 }) 

500 

501 def _get_wrapped_value(self): 

502 d, = self.inference_state.builtins_module.py__getattribute__('dict') 

503 result, = d.execute_with_values() 

504 return result