Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/jedi/inference/gradual/typing.py: 48%

251 statements  

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

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 

9 

10from jedi import debug 

11from jedi.inference.compiled import builtin_from_name, create_simple_object 

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

13 LazyValueWrapper, ValueWrapper 

14from jedi.inference.lazy_value import LazyKnownValues 

15from jedi.inference.arguments import repack_with_argument_clinic 

16from jedi.inference.filters import FilterWrapper 

17from jedi.inference.names import NameWrapper, ValueName 

18from jedi.inference.value.klass import ClassMixin 

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

20 BaseTypingClassWithGenerics, BaseTypingInstance 

21from jedi.inference.gradual.type_var import TypeVarClass 

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

23 

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

25_TYPE_ALIAS_TYPES = { 

26 'List': 'builtins.list', 

27 'Dict': 'builtins.dict', 

28 'Set': 'builtins.set', 

29 'FrozenSet': 'builtins.frozenset', 

30 'ChainMap': 'collections.ChainMap', 

31 'Counter': 'collections.Counter', 

32 'DefaultDict': 'collections.defaultdict', 

33 'Deque': 'collections.deque', 

34} 

35_PROXY_TYPES = 'Optional Union ClassVar Annotated'.split() 

36 

37 

38class TypingModuleName(NameWrapper): 

39 def infer(self): 

40 return ValueSet(self._remap()) 

41 

42 def _remap(self): 

43 name = self.string_name 

44 inference_state = self.parent_context.inference_state 

45 try: 

46 actual = _TYPE_ALIAS_TYPES[name] 

47 except KeyError: 

48 pass 

49 else: 

50 yield TypeAlias.create_cached( 

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

52 return 

53 

54 if name in _PROXY_CLASS_TYPES: 

55 yield ProxyTypingClassValue.create_cached( 

56 inference_state, self.parent_context, self.tree_name) 

57 elif name in _PROXY_TYPES: 

58 yield ProxyTypingValue.create_cached( 

59 inference_state, self.parent_context, self.tree_name) 

60 elif name == 'runtime': 

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

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

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

64 return 

65 elif name == 'TypeVar': 

66 cls, = self._wrapped_name.infer() 

67 yield TypeVarClass.create_cached(inference_state, cls) 

68 elif name == 'Any': 

69 yield AnyClass.create_cached( 

70 inference_state, self.parent_context, self.tree_name) 

71 elif name == 'TYPE_CHECKING': 

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

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

74 yield builtin_from_name(inference_state, 'True') 

75 elif name == 'overload': 

76 yield OverloadFunction.create_cached( 

77 inference_state, self.parent_context, self.tree_name) 

78 elif name == 'NewType': 

79 v, = self._wrapped_name.infer() 

80 yield NewTypeFunction.create_cached(inference_state, v) 

81 elif name == 'cast': 

82 cast_fn, = self._wrapped_name.infer() 

83 yield CastFunction.create_cached(inference_state, cast_fn) 

84 elif name == 'TypedDict': 

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

86 # added soon. 

87 yield TypedDictClass.create_cached( 

88 inference_state, self.parent_context, self.tree_name) 

89 else: 

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

91 # no_type_check & no_type_check_decorator 

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

93 yield from self._wrapped_name.infer() 

94 

95 

96class TypingModuleFilterWrapper(FilterWrapper): 

97 name_wrapper_class = TypingModuleName 

98 

99 

100class ProxyWithGenerics(BaseTypingClassWithGenerics): 

101 def execute_annotation(self): 

102 string_name = self._tree_name.value 

103 

104 if string_name == 'Union': 

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

106 # ValueSets). 

107 return self.gather_annotation_classes().execute_annotation() 

108 elif string_name == 'Optional': 

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

110 # type. 

111 return self.gather_annotation_classes().execute_annotation() \ 

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

113 elif string_name == 'Type': 

114 # The type is actually already given in the index_value 

115 return self._generics_manager[0] 

116 elif string_name in ['ClassVar', 'Annotated']: 

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

118 return self._generics_manager[0].execute_annotation() 

119 

120 mapped = { 

121 'Tuple': Tuple, 

122 'Generic': Generic, 

123 'Protocol': Protocol, 

124 'Callable': Callable, 

125 } 

126 cls = mapped[string_name] 

127 return ValueSet([cls( 

128 self.parent_context, 

129 self, 

130 self._tree_name, 

131 generics_manager=self._generics_manager, 

132 )]) 

133 

134 def gather_annotation_classes(self): 

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

136 

137 def _create_instance_with_generics(self, generics_manager): 

138 return ProxyWithGenerics( 

139 self.parent_context, 

140 self._tree_name, 

141 generics_manager 

142 ) 

143 

144 def infer_type_vars(self, value_set): 

145 annotation_generics = self.get_generics() 

146 

147 if not annotation_generics: 

148 return {} 

149 

150 annotation_name = self.py__name__() 

151 if annotation_name == 'Optional': 

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

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

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

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

156 return annotation_generics[0].infer_type_vars( 

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

158 ) 

159 

160 return {} 

161 

162 

163class ProxyTypingValue(BaseTypingValue): 

164 index_class = ProxyWithGenerics 

165 

166 def with_generics(self, generics_tuple): 

167 return self.index_class.create_cached( 

168 self.inference_state, 

169 self.parent_context, 

170 self._tree_name, 

171 generics_manager=TupleGenericManager(generics_tuple) 

172 ) 

173 

174 def py__getitem__(self, index_value_set, contextualized_node): 

175 return ValueSet( 

176 self.index_class.create_cached( 

177 self.inference_state, 

178 self.parent_context, 

179 self._tree_name, 

180 generics_manager=LazyGenericManager( 

181 context_of_index=contextualized_node.context, 

182 index_value=index_value, 

183 ) 

184 ) for index_value in index_value_set 

185 ) 

186 

187 

188class _TypingClassMixin(ClassMixin): 

189 def py__bases__(self): 

190 return [LazyKnownValues( 

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

192 )] 

193 

194 def get_metaclasses(self): 

195 return [] 

196 

197 @property 

198 def name(self): 

199 return ValueName(self, self._tree_name) 

200 

201 

202class TypingClassWithGenerics(ProxyWithGenerics, _TypingClassMixin): 

203 def infer_type_vars(self, value_set): 

204 type_var_dict = {} 

205 annotation_generics = self.get_generics() 

206 

207 if not annotation_generics: 

208 return type_var_dict 

209 

210 annotation_name = self.py__name__() 

211 if annotation_name == 'Type': 

212 return annotation_generics[0].infer_type_vars( 

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

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

215 # var inference. 

216 value_set.execute_annotation(), 

217 ) 

218 

219 elif annotation_name == 'Callable': 

220 if len(annotation_generics) == 2: 

221 return annotation_generics[1].infer_type_vars( 

222 value_set.execute_annotation(), 

223 ) 

224 

225 elif annotation_name == 'Tuple': 

226 tuple_annotation, = self.execute_annotation() 

227 return tuple_annotation.infer_type_vars(value_set) 

228 

229 return type_var_dict 

230 

231 def _create_instance_with_generics(self, generics_manager): 

232 return TypingClassWithGenerics( 

233 self.parent_context, 

234 self._tree_name, 

235 generics_manager 

236 ) 

237 

238 

239class ProxyTypingClassValue(ProxyTypingValue, _TypingClassMixin): 

240 index_class = TypingClassWithGenerics 

241 

242 

243class TypeAlias(LazyValueWrapper): 

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

245 self.inference_state = parent_context.inference_state 

246 self.parent_context = parent_context 

247 self._origin_tree_name = origin_tree_name 

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

249 

250 @property 

251 def name(self): 

252 return ValueName(self, self._origin_tree_name) 

253 

254 def py__name__(self): 

255 return self.name.string_name 

256 

257 def __repr__(self): 

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

259 

260 def _get_wrapped_value(self): 

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

262 

263 # TODO use inference_state.import_module? 

264 from jedi.inference.imports import Importer 

265 module, = Importer( 

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

267 ).follow() 

268 classes = module.py__getattribute__(class_name) 

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

270 assert len(classes) == 1, classes 

271 cls = next(iter(classes)) 

272 return cls 

273 

274 def gather_annotation_classes(self): 

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

276 

277 def get_signatures(self): 

278 return [] 

279 

280 

281class Callable(BaseTypingInstance): 

282 def py__call__(self, arguments): 

283 """ 

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

285 """ 

286 # The 0th index are the arguments. 

287 try: 

288 param_values = self._generics_manager[0] 

289 result_values = self._generics_manager[1] 

290 except IndexError: 

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

292 return NO_VALUES 

293 else: 

294 from jedi.inference.gradual.annotation import infer_return_for_callable 

295 return infer_return_for_callable(arguments, param_values, result_values) 

296 

297 def py__get__(self, instance, class_value): 

298 return ValueSet([self]) 

299 

300 

301class Tuple(BaseTypingInstance): 

302 def _is_homogenous(self): 

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

304 # is used. 

305 return self._generics_manager.is_homogenous_tuple() 

306 

307 def py__simple_getitem__(self, index): 

308 if self._is_homogenous(): 

309 return self._generics_manager.get_index_and_execute(0) 

310 else: 

311 if isinstance(index, int): 

312 return self._generics_manager.get_index_and_execute(index) 

313 

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

315 return NO_VALUES 

316 

317 def py__iter__(self, contextualized_node=None): 

318 if self._is_homogenous(): 

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

320 else: 

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

322 yield LazyKnownValues(v.execute_annotation()) 

323 

324 def py__getitem__(self, index_value_set, contextualized_node): 

325 if self._is_homogenous(): 

326 return self._generics_manager.get_index_and_execute(0) 

327 

328 return ValueSet.from_sets( 

329 self._generics_manager.to_tuple() 

330 ).execute_annotation() 

331 

332 def _get_wrapped_value(self): 

333 tuple_, = self.inference_state.builtins_module \ 

334 .py__getattribute__('tuple').execute_annotation() 

335 return tuple_ 

336 

337 @property 

338 def name(self): 

339 return self._wrapped_value.name 

340 

341 def infer_type_vars(self, value_set): 

342 # Circular 

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

344 

345 value_set = value_set.filter( 

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

347 ) 

348 

349 if self._is_homogenous(): 

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

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

352 # rather than a positional container of elements. 

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

354 value_set.merge_types_of_iterate(), 

355 ) 

356 

357 else: 

358 # The parameter annotation has only explicit type parameters 

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

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

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

362 

363 type_var_dict = {} 

364 for element in value_set: 

365 try: 

366 method = element.get_annotated_class_object 

367 except AttributeError: 

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

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

370 # cases here. 

371 continue 

372 

373 py_class = method() 

374 merge_type_var_dicts( 

375 type_var_dict, 

376 merge_pairwise_generics(self._class_value, py_class), 

377 ) 

378 

379 return type_var_dict 

380 

381 

382class Generic(BaseTypingInstance): 

383 pass 

384 

385 

386class Protocol(BaseTypingInstance): 

387 pass 

388 

389 

390class AnyClass(BaseTypingValue): 

391 def execute_annotation(self): 

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

393 return NO_VALUES 

394 

395 

396class OverloadFunction(BaseTypingValue): 

397 @repack_with_argument_clinic('func, /') 

398 def py__call__(self, func_value_set): 

399 # Just pass arguments through. 

400 return func_value_set 

401 

402 

403class NewTypeFunction(ValueWrapper): 

404 def py__call__(self, arguments): 

405 ordered_args = arguments.unpack() 

406 next(ordered_args, (None, None)) 

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

408 if second_arg is None: 

409 return NO_VALUES 

410 return ValueSet( 

411 NewType( 

412 self.inference_state, 

413 contextualized_node.context, 

414 contextualized_node.node, 

415 second_arg.infer(), 

416 ) for contextualized_node in arguments.get_calling_nodes()) 

417 

418 

419class NewType(Value): 

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

421 super().__init__(inference_state, parent_context) 

422 self._type_value_set = type_value_set 

423 self.tree_node = tree_node 

424 

425 def py__class__(self): 

426 c, = self._type_value_set.py__class__() 

427 return c 

428 

429 def py__call__(self, arguments): 

430 return self._type_value_set.execute_annotation() 

431 

432 @property 

433 def name(self): 

434 from jedi.inference.compiled.value import CompiledValueName 

435 return CompiledValueName(self, 'NewType') 

436 

437 def __repr__(self) -> str: 

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

439 

440 

441class CastFunction(ValueWrapper): 

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

443 def py__call__(self, type_value_set, object_value_set): 

444 return type_value_set.execute_annotation() 

445 

446 

447class TypedDictClass(BaseTypingValue): 

448 """ 

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

450 dicts can be identified. 

451 """ 

452 

453 

454class TypedDict(LazyValueWrapper): 

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

456 def __init__(self, definition_class): 

457 self.inference_state = definition_class.inference_state 

458 self.parent_context = definition_class.parent_context 

459 self.tree_node = definition_class.tree_node 

460 self._definition_class = definition_class 

461 

462 @property 

463 def name(self): 

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

465 

466 def py__simple_getitem__(self, index): 

467 if isinstance(index, str): 

468 return ValueSet.from_sets( 

469 name.infer() 

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

471 for name in filter.get(index) 

472 ) 

473 return NO_VALUES 

474 

475 def get_key_values(self): 

476 filtered_values = itertools.chain.from_iterable(( 

477 f.values() 

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

479 )) 

480 return ValueSet({ 

481 create_simple_object(self.inference_state, v.string_name) 

482 for v in filtered_values 

483 }) 

484 

485 def _get_wrapped_value(self): 

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

487 result, = d.execute_with_values() 

488 return result