Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/jedi-0.20.1-py3.11.egg/jedi/inference/compiled/value.py: 33%

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

393 statements  

1""" 

2Imitate the parser representation. 

3""" 

4import re 

5from functools import partial 

6from inspect import Parameter 

7from pathlib import Path 

8from typing import Optional 

9 

10from jedi import debug 

11from jedi.inference.utils import to_list 

12from jedi.cache import memoize_method 

13from jedi.inference.filters import AbstractFilter 

14from jedi.inference.names import AbstractNameDefinition, ValueNameMixin, \ 

15 ParamNameInterface 

16from jedi.inference.base_value import Value, ValueSet, NO_VALUES 

17from jedi.inference.lazy_value import LazyKnownValue 

18from jedi.inference.compiled.access import _sentinel 

19from jedi.inference.cache import inference_state_function_cache 

20from jedi.inference.helpers import reraise_getitem_errors 

21from jedi.inference.signature import BuiltinSignature 

22from jedi.inference.context import CompiledContext, CompiledModuleContext 

23 

24 

25class CheckAttribute: 

26 """Raises :exc:`AttributeError` if the attribute X is not available.""" 

27 def __init__(self, check_name=None): 

28 # Remove the py in front of e.g. py__call__. 

29 self.check_name = check_name 

30 

31 def __call__(self, func): 

32 self.func = func 

33 if self.check_name is None: 

34 self.check_name = func.__name__[2:] 

35 return self 

36 

37 def __get__(self, instance, owner): 

38 if instance is None: 

39 return self 

40 

41 # This might raise an AttributeError. That's wanted. 

42 instance.access_handle.getattr_paths(self.check_name) 

43 return partial(self.func, instance) 

44 

45 

46class CompiledValue(Value): 

47 def __init__(self, inference_state, access_handle, parent_context=None): 

48 super().__init__(inference_state, parent_context) 

49 self.access_handle = access_handle 

50 

51 def py__call__(self, arguments): 

52 return_annotation = self.access_handle.get_return_annotation() 

53 if return_annotation is not None: 

54 return create_from_access_path( 

55 self.inference_state, 

56 return_annotation 

57 ).execute_annotation(arguments.context) 

58 

59 try: 

60 self.access_handle.getattr_paths('__call__') 

61 except AttributeError: 

62 return super().py__call__(arguments) 

63 else: 

64 if self.access_handle.is_class(): 

65 from jedi.inference.value import CompiledInstance 

66 return ValueSet([ 

67 CompiledInstance(self.inference_state, self.parent_context, self, arguments) 

68 ]) 

69 else: 

70 return ValueSet(self._execute_function(arguments)) 

71 

72 @CheckAttribute() 

73 def py__class__(self): 

74 return create_from_access_path(self.inference_state, self.access_handle.py__class__()) 

75 

76 @CheckAttribute() 

77 def py__mro__(self): 

78 return (self,) + tuple( 

79 create_from_access_path(self.inference_state, access) 

80 for access in self.access_handle.py__mro__accesses() 

81 ) 

82 

83 @CheckAttribute() 

84 def py__bases__(self): 

85 return tuple( 

86 create_from_access_path(self.inference_state, access) 

87 for access in self.access_handle.py__bases__() 

88 ) 

89 

90 def get_qualified_names(self): 

91 return self.access_handle.get_qualified_names() 

92 

93 def py__bool__(self): 

94 return self.access_handle.py__bool__() 

95 

96 def is_class(self): 

97 return self.access_handle.is_class() 

98 

99 def is_function(self): 

100 return self.access_handle.is_function() 

101 

102 def is_module(self): 

103 return self.access_handle.is_module() 

104 

105 def is_compiled(self): 

106 return True 

107 

108 def is_stub(self): 

109 return False 

110 

111 def is_instance(self): 

112 return self.access_handle.is_instance() 

113 

114 def py__doc__(self): 

115 return self.access_handle.py__doc__() 

116 

117 @to_list 

118 def get_param_names(self): 

119 try: 

120 signature_params = self.access_handle.get_signature_params() 

121 except ValueError: # Has no signature 

122 params_str, ret = self._parse_function_doc() 

123 if not params_str: 

124 tokens = [] 

125 else: 

126 tokens = params_str.split(',') 

127 if self.access_handle.ismethoddescriptor(): 

128 tokens.insert(0, 'self') 

129 for p in tokens: 

130 name, _, default = p.strip().partition('=') 

131 yield UnresolvableParamName(self, name, default) 

132 else: 

133 for signature_param in signature_params: 

134 yield SignatureParamName(self, signature_param) 

135 

136 def get_signatures(self): 

137 _, return_string = self._parse_function_doc() 

138 return [BuiltinSignature(self, return_string)] 

139 

140 def __repr__(self): 

141 return '<%s: %s>' % (self.__class__.__name__, self.access_handle.get_repr()) 

142 

143 @memoize_method 

144 def _parse_function_doc(self): 

145 doc = self.py__doc__() 

146 if doc is None: 

147 return '', '' 

148 

149 return _parse_function_doc(doc) 

150 

151 @property 

152 def api_type(self): 

153 return self.access_handle.get_api_type() 

154 

155 def get_filters(self, is_instance=False, origin_scope=None): 

156 yield self._ensure_one_filter(is_instance) 

157 

158 @memoize_method 

159 def _ensure_one_filter(self, is_instance): 

160 return CompiledValueFilter(self.inference_state, self, is_instance) 

161 

162 def py__simple_getitem__(self, index): 

163 with reraise_getitem_errors(IndexError, KeyError, TypeError): 

164 try: 

165 access = self.access_handle.py__simple_getitem__( 

166 index, 

167 safe=not self.inference_state.allow_unsafe_executions 

168 ) 

169 except AttributeError: 

170 return super().py__simple_getitem__(index) 

171 if access is None: 

172 return super().py__simple_getitem__(index) 

173 

174 return ValueSet([create_from_access_path(self.inference_state, access)]) 

175 

176 def py__getitem__(self, index_value_set, contextualized_node): 

177 all_access_paths = self.access_handle.py__getitem__all_values() 

178 if all_access_paths is None: 

179 # This means basically that no __getitem__ has been defined on this 

180 # object. 

181 return super().py__getitem__(index_value_set, contextualized_node) 

182 return ValueSet( 

183 create_from_access_path(self.inference_state, access) 

184 for access in all_access_paths 

185 ) 

186 

187 def py__iter__(self, contextualized_node=None): 

188 if not self.access_handle.has_iter(): 

189 yield from super().py__iter__(contextualized_node) 

190 

191 access_path_list = self.access_handle.py__iter__list() 

192 if access_path_list is None: 

193 # There is no __iter__ method on this object. 

194 return 

195 

196 for access in access_path_list: 

197 yield LazyKnownValue(create_from_access_path(self.inference_state, access)) 

198 

199 def py__name__(self): 

200 return self.access_handle.py__name__() 

201 

202 @property 

203 def name(self): 

204 name = self.py__name__() 

205 if name is None: 

206 name = self.access_handle.get_repr() 

207 return CompiledValueName(self, name) 

208 

209 def _execute_function(self, params): 

210 from jedi.inference import docstrings 

211 from jedi.inference.compiled import builtin_from_name 

212 if self.api_type != 'function': 

213 return 

214 

215 for name in self._parse_function_doc()[1].split(): 

216 try: 

217 # TODO wtf is this? this is exactly the same as the thing 

218 # below. It uses getattr as well. 

219 self.inference_state.builtins_module.access_handle.getattr_paths(name) 

220 except AttributeError: 

221 continue 

222 else: 

223 bltn_obj = builtin_from_name(self.inference_state, name) 

224 yield from self.inference_state.execute(bltn_obj, params) 

225 yield from docstrings.infer_return_types(self) 

226 

227 def get_safe_value(self, default=_sentinel): 

228 try: 

229 return self.access_handle.get_safe_value() 

230 except ValueError: 

231 if default == _sentinel: 

232 raise 

233 return default 

234 

235 def execute_operation(self, other, operator): 

236 try: 

237 return ValueSet([create_from_access_path( 

238 self.inference_state, 

239 self.access_handle.execute_operation(other.access_handle, operator) 

240 )]) 

241 except TypeError: 

242 return NO_VALUES 

243 

244 def execute_annotation(self, context): 

245 if self.access_handle.get_repr() == 'None': 

246 # None as an annotation doesn't need to be executed. 

247 return ValueSet([self]) 

248 

249 name, args = self.access_handle.get_annotation_name_and_args() 

250 arguments = [ 

251 ValueSet([create_from_access_path(self.inference_state, path)]) 

252 for path in args 

253 ] 

254 if name == 'Union': 

255 return ValueSet.from_sets( 

256 arg.execute_annotation(context) 

257 for arg in arguments) 

258 elif name: 

259 # These are typically typing module objects. Try to use that to create generics. 

260 return ValueSet([ 

261 v.with_generics(arguments) 

262 for v in self.inference_state.typing_module.py__getattribute__(name) 

263 if hasattr(v, "with_generics") 

264 ]).execute_annotation(context) 

265 return super().execute_annotation(context) 

266 

267 def negate(self): 

268 return create_from_access_path(self.inference_state, self.access_handle.negate()) 

269 

270 def get_metaclasses(self): 

271 return NO_VALUES 

272 

273 def _as_context(self): 

274 return CompiledContext(self) 

275 

276 @property 

277 def array_type(self): 

278 return self.access_handle.get_array_type() 

279 

280 def get_key_values(self): 

281 return [ 

282 create_from_access_path(self.inference_state, k) 

283 for k in self.access_handle.get_key_paths() 

284 ] 

285 

286 def get_type_hint(self, add_class_info=True): 

287 if self.access_handle.get_repr() in ('None', "<class 'NoneType'>"): 

288 return 'None' 

289 return None 

290 

291 

292class CompiledModule(CompiledValue): 

293 file_io = None # For modules 

294 

295 def _as_context(self): 

296 return CompiledModuleContext(self) 

297 

298 def py__path__(self): 

299 return self.access_handle.py__path__() 

300 

301 def is_package(self): 

302 return self.py__path__() is not None 

303 

304 @property 

305 def string_names(self): 

306 # For modules 

307 name = self.py__name__() 

308 if name is None: 

309 return () 

310 return tuple(name.split('.')) 

311 

312 def py__file__(self) -> Optional[Path]: 

313 return self.access_handle.py__file__() # type: ignore[no-any-return] 

314 

315 

316class CompiledName(AbstractNameDefinition): 

317 def __init__(self, inference_state, parent_value, name, is_descriptor): 

318 self._inference_state = inference_state 

319 self.parent_context = parent_value.as_context() 

320 self._parent_value = parent_value 

321 self.string_name = name 

322 self.is_descriptor = is_descriptor 

323 

324 def py__doc__(self): 

325 return self.infer_compiled_value().py__doc__() 

326 

327 def _get_qualified_names(self): 

328 parent_qualified_names = self.parent_context.get_qualified_names() 

329 if parent_qualified_names is None: 

330 return None 

331 return parent_qualified_names + (self.string_name,) 

332 

333 def get_defining_qualified_value(self): 

334 context = self.parent_context 

335 if context.is_module() or context.is_class(): 

336 return self.parent_context.get_value() # Might be None 

337 

338 return None 

339 

340 def __repr__(self): 

341 try: 

342 name = self.parent_context.name # __name__ is not defined all the time 

343 except AttributeError: 

344 name = None 

345 return '<%s: (%s).%s>' % (self.__class__.__name__, name, self.string_name) 

346 

347 @property 

348 def api_type(self): 

349 if self.is_descriptor: 

350 # In case of properties we want to avoid executions as much as 

351 # possible. Since the api_type can be wrong for other reasons 

352 # anyway, we just return instance here. 

353 return "instance" 

354 return self.infer_compiled_value().api_type 

355 

356 def infer(self): 

357 return ValueSet([self.infer_compiled_value()]) 

358 

359 @memoize_method 

360 def infer_compiled_value(self): 

361 return create_from_name(self._inference_state, self._parent_value, self.string_name) 

362 

363 

364class SignatureParamName(ParamNameInterface, AbstractNameDefinition): 

365 def __init__(self, compiled_value, signature_param): 

366 self.parent_context = compiled_value.parent_context 

367 self._signature_param = signature_param 

368 

369 @property 

370 def string_name(self): 

371 return self._signature_param.name 

372 

373 def to_string(self): 

374 s = self._kind_string() + self.string_name 

375 if self._signature_param.has_annotation: 

376 s += ': ' + self._signature_param.annotation_string 

377 if self._signature_param.has_default: 

378 s += '=' + self._signature_param.default_string 

379 return s 

380 

381 def get_kind(self): 

382 return getattr(Parameter, self._signature_param.kind_name) 

383 

384 def infer(self): 

385 p = self._signature_param 

386 inference_state = self.parent_context.inference_state 

387 values = NO_VALUES 

388 if p.has_default: 

389 values = ValueSet([create_from_access_path(inference_state, p.default)]) 

390 if p.has_annotation: 

391 annotation = create_from_access_path(inference_state, p.annotation) 

392 values |= annotation.execute_with_values() 

393 return values 

394 

395 

396class UnresolvableParamName(ParamNameInterface, AbstractNameDefinition): 

397 def __init__(self, compiled_value, name, default): 

398 self.parent_context = compiled_value.parent_context 

399 self.string_name = name 

400 self._default = default 

401 

402 def get_kind(self): 

403 return Parameter.POSITIONAL_ONLY 

404 

405 def to_string(self): 

406 string = self.string_name 

407 if self._default: 

408 string += '=' + self._default 

409 return string 

410 

411 def infer(self): 

412 return NO_VALUES 

413 

414 

415class CompiledValueName(ValueNameMixin, AbstractNameDefinition): 

416 def __init__(self, value, name): 

417 self.string_name = name 

418 self._value = value 

419 self.parent_context = value.parent_context 

420 

421 

422class EmptyCompiledName(AbstractNameDefinition): 

423 """ 

424 Accessing some names will raise an exception. To avoid not having any 

425 completions, just give Jedi the option to return this object. It infers to 

426 nothing. 

427 """ 

428 def __init__(self, inference_state, name): 

429 self.parent_context = inference_state.builtins_module 

430 self.string_name = name 

431 

432 def infer(self): 

433 return NO_VALUES 

434 

435 

436class CompiledValueFilter(AbstractFilter): 

437 def __init__(self, inference_state, compiled_value, is_instance=False): 

438 self._inference_state = inference_state 

439 self.compiled_value = compiled_value 

440 self.is_instance = is_instance 

441 

442 def get(self, name): 

443 access_handle = self.compiled_value.access_handle 

444 safe = not self._inference_state.allow_unsafe_executions 

445 return self._get( 

446 name, 

447 lambda name: access_handle.is_allowed_getattr(name, safe=safe), 

448 lambda name: name in access_handle.dir(), 

449 check_has_attribute=True 

450 ) 

451 

452 def _get(self, name, allowed_getattr_callback, in_dir_callback, check_has_attribute=False): 

453 """ 

454 To remove quite a few access calls we introduced the callback here. 

455 """ 

456 has_attribute, is_descriptor, property_return_annotation = allowed_getattr_callback( 

457 name, 

458 ) 

459 if property_return_annotation is not None: 

460 values = create_from_access_path( 

461 self._inference_state, 

462 property_return_annotation 

463 ).execute_annotation(None) 

464 if values: 

465 return [CompiledValueName(v, name) for v in values] 

466 

467 if check_has_attribute and not has_attribute: 

468 return [] 

469 

470 if (is_descriptor or not has_attribute) \ 

471 and not self._inference_state.allow_unsafe_executions: 

472 return [self._get_cached_name(name, is_empty=True)] 

473 

474 if self.is_instance and not in_dir_callback(name): 

475 return [] 

476 return [self._get_cached_name(name, is_descriptor=is_descriptor)] 

477 

478 @memoize_method 

479 def _get_cached_name(self, name, is_empty=False, *, is_descriptor=False): 

480 if is_empty: 

481 return EmptyCompiledName(self._inference_state, name) 

482 else: 

483 return self._create_name(name, is_descriptor=is_descriptor) 

484 

485 def values(self): 

486 from jedi.inference.compiled import builtin_from_name 

487 names = [] 

488 needs_type_completions, dir_infos = self.compiled_value.access_handle.get_dir_infos() 

489 # We could use `safe=False` here as well, especially as a parameter to 

490 # get_dir_infos. But this would lead to a lot of property executions 

491 # that are probably not wanted. The drawback for this is that we 

492 # have a different name for `get` and `values`. For `get` we always 

493 # execute. 

494 for name in dir_infos: 

495 names += self._get( 

496 name, 

497 lambda name: dir_infos[name], 

498 lambda name: name in dir_infos, 

499 ) 

500 

501 # ``dir`` doesn't include the type names. 

502 if not self.is_instance and needs_type_completions: 

503 for filter in builtin_from_name(self._inference_state, 'type').get_filters(): 

504 names += filter.values() 

505 return names 

506 

507 def _create_name(self, name, is_descriptor): 

508 return CompiledName( 

509 self._inference_state, 

510 self.compiled_value, 

511 name, 

512 is_descriptor, 

513 ) 

514 

515 def __repr__(self): 

516 return "<%s: %s>" % (self.__class__.__name__, self.compiled_value) 

517 

518 

519docstr_defaults = { 

520 'floating point number': 'float', 

521 'character': 'str', 

522 'integer': 'int', 

523 'dictionary': 'dict', 

524 'string': 'str', 

525} 

526 

527 

528def _parse_function_doc(doc): 

529 """ 

530 Takes a function and returns the params and return value as a tuple. 

531 This is nothing more than a docstring parser. 

532 

533 TODO docstrings like utime(path, (atime, mtime)) and a(b [, b]) -> None 

534 TODO docstrings like 'tuple of integers' 

535 """ 

536 # parse round parentheses: def func(a, (b,c)) 

537 try: 

538 count = 0 

539 start = doc.index('(') 

540 for i, s in enumerate(doc[start:]): 

541 if s == '(': 

542 count += 1 

543 elif s == ')': 

544 count -= 1 

545 if count == 0: 

546 end = start + i 

547 break 

548 param_str = doc[start + 1:end] 

549 except (ValueError, UnboundLocalError): 

550 # ValueError for doc.index 

551 # UnboundLocalError for undefined end in last line 

552 debug.dbg('no brackets found - no param') 

553 end = 0 

554 param_str = '' 

555 else: 

556 # remove square brackets, that show an optional param ( = None) 

557 def change_options(m): 

558 args = m.group(1).split(',') 

559 for i, a in enumerate(args): 

560 if a and '=' not in a: 

561 args[i] += '=None' 

562 return ','.join(args) 

563 

564 while True: 

565 param_str, changes = re.subn(r' ?\[([^\[\]]+)\]', 

566 change_options, param_str) 

567 if changes == 0: 

568 break 

569 param_str = param_str.replace('-', '_') # see: isinstance.__doc__ 

570 

571 # parse return value 

572 r = re.search('-[>-]* ', doc[end:end + 7]) 

573 if r is None: 

574 ret = '' 

575 else: 

576 index = end + r.end() 

577 # get result type, which can contain newlines 

578 pattern = re.compile(r'(,\n|[^\n-])+') 

579 ret_str = pattern.match(doc, index).group(0).strip() 

580 # New object -> object() 

581 ret_str = re.sub(r'[nN]ew (.*)', r'\1()', ret_str) 

582 

583 ret = docstr_defaults.get(ret_str, ret_str) 

584 

585 return param_str, ret 

586 

587 

588def create_from_name(inference_state, compiled_value, name): 

589 access_paths = compiled_value.access_handle.getattr_paths(name, default=None) 

590 

591 value = None 

592 for access_path in access_paths: 

593 value = create_cached_compiled_value( 

594 inference_state, 

595 access_path, 

596 parent_context=None if value is None else value.as_context(), # type: ignore # TODO 

597 ) 

598 return value 

599 

600 

601def _normalize_create_args(func): 

602 """The cache doesn't care about keyword vs. normal args.""" 

603 def wrapper(inference_state, obj, parent_context=None): 

604 return func(inference_state, obj, parent_context) 

605 return wrapper 

606 

607 

608def create_from_access_path(inference_state, access_path): 

609 value = None 

610 for name, access in access_path.accesses: 

611 value = create_cached_compiled_value( 

612 inference_state, 

613 access, 

614 parent_context=None if value is None else value.as_context() # type: ignore # TODO 

615 ) 

616 return value 

617 

618 

619@_normalize_create_args 

620@inference_state_function_cache() 

621def create_cached_compiled_value(inference_state, access_handle, parent_context): 

622 assert not isinstance(parent_context, CompiledValue) 

623 if parent_context is None: 

624 cls = CompiledModule 

625 else: 

626 cls = CompiledValue 

627 return cls(inference_state, access_handle, parent_context)