Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/jedi-0.20.0-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 # While with_generics only exists on very specific objects, we 

260 # should probably be fine, because we control all the typing 

261 # objects. 

262 return ValueSet([ 

263 v.with_generics(arguments) 

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

265 ]).execute_annotation(context) 

266 return super().execute_annotation(context) 

267 

268 def negate(self): 

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

270 

271 def get_metaclasses(self): 

272 return NO_VALUES 

273 

274 def _as_context(self): 

275 return CompiledContext(self) 

276 

277 @property 

278 def array_type(self): 

279 return self.access_handle.get_array_type() 

280 

281 def get_key_values(self): 

282 return [ 

283 create_from_access_path(self.inference_state, k) 

284 for k in self.access_handle.get_key_paths() 

285 ] 

286 

287 def get_type_hint(self, add_class_info=True): 

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

289 return 'None' 

290 return None 

291 

292 

293class CompiledModule(CompiledValue): 

294 file_io = None # For modules 

295 

296 def _as_context(self): 

297 return CompiledModuleContext(self) 

298 

299 def py__path__(self): 

300 return self.access_handle.py__path__() 

301 

302 def is_package(self): 

303 return self.py__path__() is not None 

304 

305 @property 

306 def string_names(self): 

307 # For modules 

308 name = self.py__name__() 

309 if name is None: 

310 return () 

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

312 

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

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

315 

316 

317class CompiledName(AbstractNameDefinition): 

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

319 self._inference_state = inference_state 

320 self.parent_context = parent_value.as_context() 

321 self._parent_value = parent_value 

322 self.string_name = name 

323 self.is_descriptor = is_descriptor 

324 

325 def py__doc__(self): 

326 return self.infer_compiled_value().py__doc__() 

327 

328 def _get_qualified_names(self): 

329 parent_qualified_names = self.parent_context.get_qualified_names() 

330 if parent_qualified_names is None: 

331 return None 

332 return parent_qualified_names + (self.string_name,) 

333 

334 def get_defining_qualified_value(self): 

335 context = self.parent_context 

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

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

338 

339 return None 

340 

341 def __repr__(self): 

342 try: 

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

344 except AttributeError: 

345 name = None 

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

347 

348 @property 

349 def api_type(self): 

350 if self.is_descriptor: 

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

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

353 # anyway, we just return instance here. 

354 return "instance" 

355 return self.infer_compiled_value().api_type 

356 

357 def infer(self): 

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

359 

360 @memoize_method 

361 def infer_compiled_value(self): 

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

363 

364 

365class SignatureParamName(ParamNameInterface, AbstractNameDefinition): 

366 def __init__(self, compiled_value, signature_param): 

367 self.parent_context = compiled_value.parent_context 

368 self._signature_param = signature_param 

369 

370 @property 

371 def string_name(self): 

372 return self._signature_param.name 

373 

374 def to_string(self): 

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

376 if self._signature_param.has_annotation: 

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

378 if self._signature_param.has_default: 

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

380 return s 

381 

382 def get_kind(self): 

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

384 

385 def infer(self): 

386 p = self._signature_param 

387 inference_state = self.parent_context.inference_state 

388 values = NO_VALUES 

389 if p.has_default: 

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

391 if p.has_annotation: 

392 annotation = create_from_access_path(inference_state, p.annotation) 

393 values |= annotation.execute_with_values() 

394 return values 

395 

396 

397class UnresolvableParamName(ParamNameInterface, AbstractNameDefinition): 

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

399 self.parent_context = compiled_value.parent_context 

400 self.string_name = name 

401 self._default = default 

402 

403 def get_kind(self): 

404 return Parameter.POSITIONAL_ONLY 

405 

406 def to_string(self): 

407 string = self.string_name 

408 if self._default: 

409 string += '=' + self._default 

410 return string 

411 

412 def infer(self): 

413 return NO_VALUES 

414 

415 

416class CompiledValueName(ValueNameMixin, AbstractNameDefinition): 

417 def __init__(self, value, name): 

418 self.string_name = name 

419 self._value = value 

420 self.parent_context = value.parent_context 

421 

422 

423class EmptyCompiledName(AbstractNameDefinition): 

424 """ 

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

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

427 nothing. 

428 """ 

429 def __init__(self, inference_state, name): 

430 self.parent_context = inference_state.builtins_module 

431 self.string_name = name 

432 

433 def infer(self): 

434 return NO_VALUES 

435 

436 

437class CompiledValueFilter(AbstractFilter): 

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

439 self._inference_state = inference_state 

440 self.compiled_value = compiled_value 

441 self.is_instance = is_instance 

442 

443 def get(self, name): 

444 access_handle = self.compiled_value.access_handle 

445 safe = not self._inference_state.allow_unsafe_executions 

446 return self._get( 

447 name, 

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

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

450 check_has_attribute=True 

451 ) 

452 

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

454 """ 

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

456 """ 

457 has_attribute, is_descriptor, property_return_annotation = allowed_getattr_callback( 

458 name, 

459 ) 

460 if property_return_annotation is not None: 

461 values = create_from_access_path( 

462 self._inference_state, 

463 property_return_annotation 

464 ).execute_annotation(None) 

465 if values: 

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

467 

468 if check_has_attribute and not has_attribute: 

469 return [] 

470 

471 if (is_descriptor or not has_attribute) \ 

472 and not self._inference_state.allow_unsafe_executions: 

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

474 

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

476 return [] 

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

478 

479 @memoize_method 

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

481 if is_empty: 

482 return EmptyCompiledName(self._inference_state, name) 

483 else: 

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

485 

486 def values(self): 

487 from jedi.inference.compiled import builtin_from_name 

488 names = [] 

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

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

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

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

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

494 # execute. 

495 for name in dir_infos: 

496 names += self._get( 

497 name, 

498 lambda name: dir_infos[name], 

499 lambda name: name in dir_infos, 

500 ) 

501 

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

503 if not self.is_instance and needs_type_completions: 

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

505 names += filter.values() 

506 return names 

507 

508 def _create_name(self, name, is_descriptor): 

509 return CompiledName( 

510 self._inference_state, 

511 self.compiled_value, 

512 name, 

513 is_descriptor, 

514 ) 

515 

516 def __repr__(self): 

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

518 

519 

520docstr_defaults = { 

521 'floating point number': 'float', 

522 'character': 'str', 

523 'integer': 'int', 

524 'dictionary': 'dict', 

525 'string': 'str', 

526} 

527 

528 

529def _parse_function_doc(doc): 

530 """ 

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

532 This is nothing more than a docstring parser. 

533 

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

535 TODO docstrings like 'tuple of integers' 

536 """ 

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

538 try: 

539 count = 0 

540 start = doc.index('(') 

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

542 if s == '(': 

543 count += 1 

544 elif s == ')': 

545 count -= 1 

546 if count == 0: 

547 end = start + i 

548 break 

549 param_str = doc[start + 1:end] 

550 except (ValueError, UnboundLocalError): 

551 # ValueError for doc.index 

552 # UnboundLocalError for undefined end in last line 

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

554 end = 0 

555 param_str = '' 

556 else: 

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

558 def change_options(m): 

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

560 for i, a in enumerate(args): 

561 if a and '=' not in a: 

562 args[i] += '=None' 

563 return ','.join(args) 

564 

565 while True: 

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

567 change_options, param_str) 

568 if changes == 0: 

569 break 

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

571 

572 # parse return value 

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

574 if r is None: 

575 ret = '' 

576 else: 

577 index = end + r.end() 

578 # get result type, which can contain newlines 

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

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

581 # New object -> object() 

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

583 

584 ret = docstr_defaults.get(ret_str, ret_str) 

585 

586 return param_str, ret 

587 

588 

589def create_from_name(inference_state, compiled_value, name): 

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

591 

592 value = None 

593 for access_path in access_paths: 

594 value = create_cached_compiled_value( 

595 inference_state, 

596 access_path, 

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

598 ) 

599 return value 

600 

601 

602def _normalize_create_args(func): 

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

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

605 return func(inference_state, obj, parent_context) 

606 return wrapper 

607 

608 

609def create_from_access_path(inference_state, access_path): 

610 value = None 

611 for name, access in access_path.accesses: 

612 value = create_cached_compiled_value( 

613 inference_state, 

614 access, 

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

616 ) 

617 return value 

618 

619 

620@_normalize_create_args 

621@inference_state_function_cache() 

622def create_cached_compiled_value(inference_state, access_handle, parent_context): 

623 assert not isinstance(parent_context, CompiledValue) 

624 if parent_context is None: 

625 cls = CompiledModule 

626 else: 

627 cls = CompiledValue 

628 return cls(inference_state, access_handle, parent_context)