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

247 statements  

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

1from jedi.inference.cache import inference_state_method_cache 

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

3 iterator_to_value_set, LazyValueWrapper, ValueWrapper 

4from jedi.inference.compiled import builtin_from_name 

5from jedi.inference.value.klass import ClassFilter 

6from jedi.inference.value.klass import ClassMixin 

7from jedi.inference.utils import to_list 

8from jedi.inference.names import AbstractNameDefinition, ValueName 

9from jedi.inference.context import ClassContext 

10from jedi.inference.gradual.generics import TupleGenericManager 

11 

12 

13class _BoundTypeVarName(AbstractNameDefinition): 

14 """ 

15 This type var was bound to a certain type, e.g. int. 

16 """ 

17 def __init__(self, type_var, value_set): 

18 self._type_var = type_var 

19 self.parent_context = type_var.parent_context 

20 self._value_set = value_set 

21 

22 def infer(self): 

23 def iter_(): 

24 for value in self._value_set: 

25 # Replace any with the constraints if they are there. 

26 from jedi.inference.gradual.typing import AnyClass 

27 if isinstance(value, AnyClass): 

28 yield from self._type_var.constraints 

29 else: 

30 yield value 

31 return ValueSet(iter_()) 

32 

33 def py__name__(self): 

34 return self._type_var.py__name__() 

35 

36 def __repr__(self): 

37 return '<%s %s -> %s>' % (self.__class__.__name__, self.py__name__(), self._value_set) 

38 

39 

40class _TypeVarFilter: 

41 """ 

42 A filter for all given variables in a class. 

43 

44 A = TypeVar('A') 

45 B = TypeVar('B') 

46 class Foo(Mapping[A, B]): 

47 ... 

48 

49 In this example we would have two type vars given: A and B 

50 """ 

51 def __init__(self, generics, type_vars): 

52 self._generics = generics 

53 self._type_vars = type_vars 

54 

55 def get(self, name): 

56 for i, type_var in enumerate(self._type_vars): 

57 if type_var.py__name__() == name: 

58 try: 

59 return [_BoundTypeVarName(type_var, self._generics[i])] 

60 except IndexError: 

61 return [type_var.name] 

62 return [] 

63 

64 def values(self): 

65 # The values are not relevant. If it's not searched exactly, the type 

66 # vars are just global and should be looked up as that. 

67 return [] 

68 

69 

70class _AnnotatedClassContext(ClassContext): 

71 def get_filters(self, *args, **kwargs): 

72 filters = super().get_filters( 

73 *args, **kwargs 

74 ) 

75 yield from filters 

76 

77 # The type vars can only be looked up if it's a global search and 

78 # not a direct lookup on the class. 

79 yield self._value.get_type_var_filter() 

80 

81 

82class DefineGenericBaseClass(LazyValueWrapper): 

83 def __init__(self, generics_manager): 

84 self._generics_manager = generics_manager 

85 

86 def _create_instance_with_generics(self, generics_manager): 

87 raise NotImplementedError 

88 

89 @inference_state_method_cache() 

90 def get_generics(self): 

91 return self._generics_manager.to_tuple() 

92 

93 def define_generics(self, type_var_dict): 

94 from jedi.inference.gradual.type_var import TypeVar 

95 changed = False 

96 new_generics = [] 

97 for generic_set in self.get_generics(): 

98 values = NO_VALUES 

99 for generic in generic_set: 

100 if isinstance(generic, (DefineGenericBaseClass, TypeVar)): 

101 result = generic.define_generics(type_var_dict) 

102 values |= result 

103 if result != ValueSet({generic}): 

104 changed = True 

105 else: 

106 values |= ValueSet([generic]) 

107 new_generics.append(values) 

108 

109 if not changed: 

110 # There might not be any type vars that change. In that case just 

111 # return itself, because it does not make sense to potentially lose 

112 # cached results. 

113 return ValueSet([self]) 

114 

115 return ValueSet([self._create_instance_with_generics( 

116 TupleGenericManager(tuple(new_generics)) 

117 )]) 

118 

119 def is_same_class(self, other): 

120 if not isinstance(other, DefineGenericBaseClass): 

121 return False 

122 

123 if self.tree_node != other.tree_node: 

124 # TODO not sure if this is nice. 

125 return False 

126 given_params1 = self.get_generics() 

127 given_params2 = other.get_generics() 

128 

129 if len(given_params1) != len(given_params2): 

130 # If the amount of type vars doesn't match, the class doesn't 

131 # match. 

132 return False 

133 

134 # Now compare generics 

135 return all( 

136 any( 

137 # TODO why is this ordering the correct one? 

138 cls2.is_same_class(cls1) 

139 # TODO I'm still not sure gather_annotation_classes is a good 

140 # idea. They are essentially here to avoid comparing Tuple <=> 

141 # tuple and instead compare tuple <=> tuple, but at the moment 

142 # the whole `is_same_class` and `is_sub_class` matching is just 

143 # not in the best shape. 

144 for cls1 in class_set1.gather_annotation_classes() 

145 for cls2 in class_set2.gather_annotation_classes() 

146 ) for class_set1, class_set2 in zip(given_params1, given_params2) 

147 ) 

148 

149 def get_signatures(self): 

150 return [] 

151 

152 def __repr__(self): 

153 return '<%s: %s%s>' % ( 

154 self.__class__.__name__, 

155 self._wrapped_value, 

156 list(self.get_generics()), 

157 ) 

158 

159 

160class GenericClass(DefineGenericBaseClass, ClassMixin): 

161 """ 

162 A class that is defined with generics, might be something simple like: 

163 

164 class Foo(Generic[T]): ... 

165 my_foo_int_cls = Foo[int] 

166 """ 

167 def __init__(self, class_value, generics_manager): 

168 super().__init__(generics_manager) 

169 self._class_value = class_value 

170 

171 def _get_wrapped_value(self): 

172 return self._class_value 

173 

174 def get_type_hint(self, add_class_info=True): 

175 n = self.py__name__() 

176 # Not sure if this is the best way to do this, but all of these types 

177 # are a bit special in that they have type aliases and other ways to 

178 # become lower case. It's probably better to make them upper case, 

179 # because that's what you can use in annotations. 

180 n = dict(list="List", dict="Dict", set="Set", tuple="Tuple").get(n, n) 

181 s = n + self._generics_manager.get_type_hint() 

182 if add_class_info: 

183 return 'Type[%s]' % s 

184 return s 

185 

186 def get_type_var_filter(self): 

187 return _TypeVarFilter(self.get_generics(), self.list_type_vars()) 

188 

189 def py__call__(self, arguments): 

190 instance, = super().py__call__(arguments) 

191 return ValueSet([_GenericInstanceWrapper(instance)]) 

192 

193 def _as_context(self): 

194 return _AnnotatedClassContext(self) 

195 

196 @to_list 

197 def py__bases__(self): 

198 for base in self._wrapped_value.py__bases__(): 

199 yield _LazyGenericBaseClass(self, base, self._generics_manager) 

200 

201 def _create_instance_with_generics(self, generics_manager): 

202 return GenericClass(self._class_value, generics_manager) 

203 

204 def is_sub_class_of(self, class_value): 

205 if super().is_sub_class_of(class_value): 

206 return True 

207 return self._class_value.is_sub_class_of(class_value) 

208 

209 def with_generics(self, generics_tuple): 

210 return self._class_value.with_generics(generics_tuple) 

211 

212 def infer_type_vars(self, value_set): 

213 # Circular 

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

215 

216 annotation_name = self.py__name__() 

217 type_var_dict = {} 

218 if annotation_name == 'Iterable': 

219 annotation_generics = self.get_generics() 

220 if annotation_generics: 

221 return annotation_generics[0].infer_type_vars( 

222 value_set.merge_types_of_iterate(), 

223 ) 

224 else: 

225 # Note: we need to handle the MRO _in order_, so we need to extract 

226 # the elements from the set first, then handle them, even if we put 

227 # them back in a set afterwards. 

228 for py_class in value_set: 

229 if py_class.is_instance() and not py_class.is_compiled(): 

230 py_class = py_class.get_annotated_class_object() 

231 else: 

232 continue 

233 

234 if py_class.api_type != 'class': 

235 # Functions & modules don't have an MRO and we're not 

236 # expecting a Callable (those are handled separately within 

237 # TypingClassValueWithIndex). 

238 continue 

239 

240 for parent_class in py_class.py__mro__(): 

241 class_name = parent_class.py__name__() 

242 if annotation_name == class_name: 

243 merge_type_var_dicts( 

244 type_var_dict, 

245 merge_pairwise_generics(self, parent_class), 

246 ) 

247 break 

248 

249 return type_var_dict 

250 

251 

252class _LazyGenericBaseClass: 

253 def __init__(self, class_value, lazy_base_class, generics_manager): 

254 self._class_value = class_value 

255 self._lazy_base_class = lazy_base_class 

256 self._generics_manager = generics_manager 

257 

258 @iterator_to_value_set 

259 def infer(self): 

260 for base in self._lazy_base_class.infer(): 

261 if isinstance(base, GenericClass): 

262 # Here we have to recalculate the given types. 

263 yield GenericClass.create_cached( 

264 base.inference_state, 

265 base._wrapped_value, 

266 TupleGenericManager(tuple(self._remap_type_vars(base))), 

267 ) 

268 else: 

269 if base.is_class_mixin(): 

270 # This case basically allows classes like `class Foo(List)` 

271 # to be used like `Foo[int]`. The generics are not 

272 # necessary and can be used later. 

273 yield GenericClass.create_cached( 

274 base.inference_state, 

275 base, 

276 self._generics_manager, 

277 ) 

278 else: 

279 yield base 

280 

281 def _remap_type_vars(self, base): 

282 from jedi.inference.gradual.type_var import TypeVar 

283 filter = self._class_value.get_type_var_filter() 

284 for type_var_set in base.get_generics(): 

285 new = NO_VALUES 

286 for type_var in type_var_set: 

287 if isinstance(type_var, TypeVar): 

288 names = filter.get(type_var.py__name__()) 

289 new |= ValueSet.from_sets( 

290 name.infer() for name in names 

291 ) 

292 else: 

293 # Mostly will be type vars, except if in some cases 

294 # a concrete type will already be there. In that 

295 # case just add it to the value set. 

296 new |= ValueSet([type_var]) 

297 yield new 

298 

299 def __repr__(self): 

300 return '<%s: %s>' % (self.__class__.__name__, self._lazy_base_class) 

301 

302 

303class _GenericInstanceWrapper(ValueWrapper): 

304 def py__stop_iteration_returns(self): 

305 for cls in self._wrapped_value.class_value.py__mro__(): 

306 if cls.py__name__() == 'Generator': 

307 generics = cls.get_generics() 

308 try: 

309 return generics[2].execute_annotation() 

310 except IndexError: 

311 pass 

312 elif cls.py__name__() == 'Iterator': 

313 return ValueSet([builtin_from_name(self.inference_state, 'None')]) 

314 return self._wrapped_value.py__stop_iteration_returns() 

315 

316 def get_type_hint(self, add_class_info=True): 

317 return self._wrapped_value.class_value.get_type_hint(add_class_info=False) 

318 

319 

320class _PseudoTreeNameClass(Value): 

321 """ 

322 In typeshed, some classes are defined like this: 

323 

324 Tuple: _SpecialForm = ... 

325 

326 Now this is not a real class, therefore we have to do some workarounds like 

327 this class. Essentially this class makes it possible to goto that `Tuple` 

328 name, without affecting anything else negatively. 

329 """ 

330 api_type = 'class' 

331 

332 def __init__(self, parent_context, tree_name): 

333 super().__init__( 

334 parent_context.inference_state, 

335 parent_context 

336 ) 

337 self._tree_name = tree_name 

338 

339 @property 

340 def tree_node(self): 

341 return self._tree_name 

342 

343 def get_filters(self, *args, **kwargs): 

344 # TODO this is obviously wrong. Is it though? 

345 class EmptyFilter(ClassFilter): 

346 def __init__(self): 

347 pass 

348 

349 def get(self, name, **kwargs): 

350 return [] 

351 

352 def values(self, **kwargs): 

353 return [] 

354 

355 yield EmptyFilter() 

356 

357 def py__class__(self): 

358 # This might not be 100% correct, but it is good enough. The details of 

359 # the typing library are not really an issue for Jedi. 

360 return builtin_from_name(self.inference_state, 'type') 

361 

362 @property 

363 def name(self): 

364 return ValueName(self, self._tree_name) 

365 

366 def get_qualified_names(self): 

367 return (self._tree_name.value,) 

368 

369 def __repr__(self): 

370 return '%s(%s)' % (self.__class__.__name__, self._tree_name.value) 

371 

372 

373class BaseTypingValue(LazyValueWrapper): 

374 def __init__(self, parent_context, tree_name): 

375 self.inference_state = parent_context.inference_state 

376 self.parent_context = parent_context 

377 self._tree_name = tree_name 

378 

379 @property 

380 def name(self): 

381 return ValueName(self, self._tree_name) 

382 

383 def _get_wrapped_value(self): 

384 return _PseudoTreeNameClass(self.parent_context, self._tree_name) 

385 

386 def get_signatures(self): 

387 return self._wrapped_value.get_signatures() 

388 

389 def __repr__(self): 

390 return '%s(%s)' % (self.__class__.__name__, self._tree_name.value) 

391 

392 

393class BaseTypingClassWithGenerics(DefineGenericBaseClass): 

394 def __init__(self, parent_context, tree_name, generics_manager): 

395 super().__init__(generics_manager) 

396 self.inference_state = parent_context.inference_state 

397 self.parent_context = parent_context 

398 self._tree_name = tree_name 

399 

400 def _get_wrapped_value(self): 

401 return _PseudoTreeNameClass(self.parent_context, self._tree_name) 

402 

403 def __repr__(self): 

404 return '%s(%s%s)' % (self.__class__.__name__, self._tree_name.value, 

405 self._generics_manager) 

406 

407 

408class BaseTypingInstance(LazyValueWrapper): 

409 def __init__(self, parent_context, class_value, tree_name, generics_manager): 

410 self.inference_state = class_value.inference_state 

411 self.parent_context = parent_context 

412 self._class_value = class_value 

413 self._tree_name = tree_name 

414 self._generics_manager = generics_manager 

415 

416 def py__class__(self): 

417 return self._class_value 

418 

419 def get_annotated_class_object(self): 

420 return self._class_value 

421 

422 def get_qualified_names(self): 

423 return (self.py__name__(),) 

424 

425 @property 

426 def name(self): 

427 return ValueName(self, self._tree_name) 

428 

429 def _get_wrapped_value(self): 

430 object_, = builtin_from_name(self.inference_state, 'object').execute_annotation() 

431 return object_ 

432 

433 def __repr__(self): 

434 return '<%s: %s>' % (self.__class__.__name__, self._generics_manager)