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

384 statements  

« prev     ^ index     » next       coverage.py v7.2.2, created at 2023-03-26 07:16 +0000

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 # TODO the return annotation may also be a string. 

55 return create_from_access_path( 

56 self.inference_state, 

57 return_annotation 

58 ).execute_annotation() 

59 

60 try: 

61 self.access_handle.getattr_paths('__call__') 

62 except AttributeError: 

63 return super().py__call__(arguments) 

64 else: 

65 if self.access_handle.is_class(): 

66 from jedi.inference.value import CompiledInstance 

67 return ValueSet([ 

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

69 ]) 

70 else: 

71 return ValueSet(self._execute_function(arguments)) 

72 

73 @CheckAttribute() 

74 def py__class__(self): 

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

76 

77 @CheckAttribute() 

78 def py__mro__(self): 

79 return (self,) + tuple( 

80 create_from_access_path(self.inference_state, access) 

81 for access in self.access_handle.py__mro__accesses() 

82 ) 

83 

84 @CheckAttribute() 

85 def py__bases__(self): 

86 return tuple( 

87 create_from_access_path(self.inference_state, access) 

88 for access in self.access_handle.py__bases__() 

89 ) 

90 

91 def get_qualified_names(self): 

92 return self.access_handle.get_qualified_names() 

93 

94 def py__bool__(self): 

95 return self.access_handle.py__bool__() 

96 

97 def is_class(self): 

98 return self.access_handle.is_class() 

99 

100 def is_function(self): 

101 return self.access_handle.is_function() 

102 

103 def is_module(self): 

104 return self.access_handle.is_module() 

105 

106 def is_compiled(self): 

107 return True 

108 

109 def is_stub(self): 

110 return False 

111 

112 def is_instance(self): 

113 return self.access_handle.is_instance() 

114 

115 def py__doc__(self): 

116 return self.access_handle.py__doc__() 

117 

118 @to_list 

119 def get_param_names(self): 

120 try: 

121 signature_params = self.access_handle.get_signature_params() 

122 except ValueError: # Has no signature 

123 params_str, ret = self._parse_function_doc() 

124 if not params_str: 

125 tokens = [] 

126 else: 

127 tokens = params_str.split(',') 

128 if self.access_handle.ismethoddescriptor(): 

129 tokens.insert(0, 'self') 

130 for p in tokens: 

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

132 yield UnresolvableParamName(self, name, default) 

133 else: 

134 for signature_param in signature_params: 

135 yield SignatureParamName(self, signature_param) 

136 

137 def get_signatures(self): 

138 _, return_string = self._parse_function_doc() 

139 return [BuiltinSignature(self, return_string)] 

140 

141 def __repr__(self): 

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

143 

144 @memoize_method 

145 def _parse_function_doc(self): 

146 doc = self.py__doc__() 

147 if doc is None: 

148 return '', '' 

149 

150 return _parse_function_doc(doc) 

151 

152 @property 

153 def api_type(self): 

154 return self.access_handle.get_api_type() 

155 

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

157 yield self._ensure_one_filter(is_instance) 

158 

159 @memoize_method 

160 def _ensure_one_filter(self, is_instance): 

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

162 

163 def py__simple_getitem__(self, index): 

164 with reraise_getitem_errors(IndexError, KeyError, TypeError): 

165 try: 

166 access = self.access_handle.py__simple_getitem__(index) 

167 except AttributeError: 

168 return super().py__simple_getitem__(index) 

169 if access is None: 

170 return super().py__simple_getitem__(index) 

171 

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

173 

174 def py__getitem__(self, index_value_set, contextualized_node): 

175 all_access_paths = self.access_handle.py__getitem__all_values() 

176 if all_access_paths is None: 

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

178 # object. 

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

180 return ValueSet( 

181 create_from_access_path(self.inference_state, access) 

182 for access in all_access_paths 

183 ) 

184 

185 def py__iter__(self, contextualized_node=None): 

186 if not self.access_handle.has_iter(): 

187 yield from super().py__iter__(contextualized_node) 

188 

189 access_path_list = self.access_handle.py__iter__list() 

190 if access_path_list is None: 

191 # There is no __iter__ method on this object. 

192 return 

193 

194 for access in access_path_list: 

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

196 

197 def py__name__(self): 

198 return self.access_handle.py__name__() 

199 

200 @property 

201 def name(self): 

202 name = self.py__name__() 

203 if name is None: 

204 name = self.access_handle.get_repr() 

205 return CompiledValueName(self, name) 

206 

207 def _execute_function(self, params): 

208 from jedi.inference import docstrings 

209 from jedi.inference.compiled import builtin_from_name 

210 if self.api_type != 'function': 

211 return 

212 

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

214 try: 

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

216 # below. It uses getattr as well. 

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

218 except AttributeError: 

219 continue 

220 else: 

221 bltn_obj = builtin_from_name(self.inference_state, name) 

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

223 yield from docstrings.infer_return_types(self) 

224 

225 def get_safe_value(self, default=_sentinel): 

226 try: 

227 return self.access_handle.get_safe_value() 

228 except ValueError: 

229 if default == _sentinel: 

230 raise 

231 return default 

232 

233 def execute_operation(self, other, operator): 

234 try: 

235 return ValueSet([create_from_access_path( 

236 self.inference_state, 

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

238 )]) 

239 except TypeError: 

240 return NO_VALUES 

241 

242 def execute_annotation(self): 

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

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

245 return ValueSet([self]) 

246 

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

248 arguments = [ 

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

250 for path in args 

251 ] 

252 if name == 'Union': 

253 return ValueSet.from_sets(arg.execute_annotation() for arg in arguments) 

254 elif name: 

255 # While with_generics only exists on very specific objects, we 

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

257 # objects. 

258 return ValueSet([ 

259 v.with_generics(arguments) 

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

261 ]).execute_annotation() 

262 return super().execute_annotation() 

263 

264 def negate(self): 

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

266 

267 def get_metaclasses(self): 

268 return NO_VALUES 

269 

270 def _as_context(self): 

271 return CompiledContext(self) 

272 

273 @property 

274 def array_type(self): 

275 return self.access_handle.get_array_type() 

276 

277 def get_key_values(self): 

278 return [ 

279 create_from_access_path(self.inference_state, k) 

280 for k in self.access_handle.get_key_paths() 

281 ] 

282 

283 def get_type_hint(self, add_class_info=True): 

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

285 return 'None' 

286 return None 

287 

288 

289class CompiledModule(CompiledValue): 

290 file_io = None # For modules 

291 

292 def _as_context(self): 

293 return CompiledModuleContext(self) 

294 

295 def py__path__(self): 

296 return self.access_handle.py__path__() 

297 

298 def is_package(self): 

299 return self.py__path__() is not None 

300 

301 @property 

302 def string_names(self): 

303 # For modules 

304 name = self.py__name__() 

305 if name is None: 

306 return () 

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

308 

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

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

311 

312 

313class CompiledName(AbstractNameDefinition): 

314 def __init__(self, inference_state, parent_value, name): 

315 self._inference_state = inference_state 

316 self.parent_context = parent_value.as_context() 

317 self._parent_value = parent_value 

318 self.string_name = name 

319 

320 def py__doc__(self): 

321 return self.infer_compiled_value().py__doc__() 

322 

323 def _get_qualified_names(self): 

324 parent_qualified_names = self.parent_context.get_qualified_names() 

325 if parent_qualified_names is None: 

326 return None 

327 return parent_qualified_names + (self.string_name,) 

328 

329 def get_defining_qualified_value(self): 

330 context = self.parent_context 

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

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

333 

334 return None 

335 

336 def __repr__(self): 

337 try: 

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

339 except AttributeError: 

340 name = None 

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

342 

343 @property 

344 def api_type(self): 

345 return self.infer_compiled_value().api_type 

346 

347 def infer(self): 

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

349 

350 @memoize_method 

351 def infer_compiled_value(self): 

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

353 

354 

355class SignatureParamName(ParamNameInterface, AbstractNameDefinition): 

356 def __init__(self, compiled_value, signature_param): 

357 self.parent_context = compiled_value.parent_context 

358 self._signature_param = signature_param 

359 

360 @property 

361 def string_name(self): 

362 return self._signature_param.name 

363 

364 def to_string(self): 

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

366 if self._signature_param.has_annotation: 

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

368 if self._signature_param.has_default: 

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

370 return s 

371 

372 def get_kind(self): 

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

374 

375 def infer(self): 

376 p = self._signature_param 

377 inference_state = self.parent_context.inference_state 

378 values = NO_VALUES 

379 if p.has_default: 

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

381 if p.has_annotation: 

382 annotation = create_from_access_path(inference_state, p.annotation) 

383 values |= annotation.execute_with_values() 

384 return values 

385 

386 

387class UnresolvableParamName(ParamNameInterface, AbstractNameDefinition): 

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

389 self.parent_context = compiled_value.parent_context 

390 self.string_name = name 

391 self._default = default 

392 

393 def get_kind(self): 

394 return Parameter.POSITIONAL_ONLY 

395 

396 def to_string(self): 

397 string = self.string_name 

398 if self._default: 

399 string += '=' + self._default 

400 return string 

401 

402 def infer(self): 

403 return NO_VALUES 

404 

405 

406class CompiledValueName(ValueNameMixin, AbstractNameDefinition): 

407 def __init__(self, value, name): 

408 self.string_name = name 

409 self._value = value 

410 self.parent_context = value.parent_context 

411 

412 

413class EmptyCompiledName(AbstractNameDefinition): 

414 """ 

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

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

417 nothing. 

418 """ 

419 def __init__(self, inference_state, name): 

420 self.parent_context = inference_state.builtins_module 

421 self.string_name = name 

422 

423 def infer(self): 

424 return NO_VALUES 

425 

426 

427class CompiledValueFilter(AbstractFilter): 

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

429 self._inference_state = inference_state 

430 self.compiled_value = compiled_value 

431 self.is_instance = is_instance 

432 

433 def get(self, name): 

434 access_handle = self.compiled_value.access_handle 

435 return self._get( 

436 name, 

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

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

439 check_has_attribute=True 

440 ) 

441 

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

443 """ 

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

445 """ 

446 if self._inference_state.allow_descriptor_getattr: 

447 pass 

448 

449 has_attribute, is_descriptor = allowed_getattr_callback( 

450 name, 

451 safe=not self._inference_state.allow_descriptor_getattr 

452 ) 

453 if check_has_attribute and not has_attribute: 

454 return [] 

455 

456 if (is_descriptor or not has_attribute) \ 

457 and not self._inference_state.allow_descriptor_getattr: 

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

459 

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

461 return [] 

462 return [self._get_cached_name(name)] 

463 

464 @memoize_method 

465 def _get_cached_name(self, name, is_empty=False): 

466 if is_empty: 

467 return EmptyCompiledName(self._inference_state, name) 

468 else: 

469 return self._create_name(name) 

470 

471 def values(self): 

472 from jedi.inference.compiled import builtin_from_name 

473 names = [] 

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

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

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

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

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

479 # execute. 

480 for name in dir_infos: 

481 names += self._get( 

482 name, 

483 lambda name, safe: dir_infos[name], 

484 lambda name: name in dir_infos, 

485 ) 

486 

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

488 if not self.is_instance and needs_type_completions: 

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

490 names += filter.values() 

491 return names 

492 

493 def _create_name(self, name): 

494 return CompiledName( 

495 self._inference_state, 

496 self.compiled_value, 

497 name 

498 ) 

499 

500 def __repr__(self): 

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

502 

503 

504docstr_defaults = { 

505 'floating point number': 'float', 

506 'character': 'str', 

507 'integer': 'int', 

508 'dictionary': 'dict', 

509 'string': 'str', 

510} 

511 

512 

513def _parse_function_doc(doc): 

514 """ 

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

516 This is nothing more than a docstring parser. 

517 

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

519 TODO docstrings like 'tuple of integers' 

520 """ 

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

522 try: 

523 count = 0 

524 start = doc.index('(') 

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

526 if s == '(': 

527 count += 1 

528 elif s == ')': 

529 count -= 1 

530 if count == 0: 

531 end = start + i 

532 break 

533 param_str = doc[start + 1:end] 

534 except (ValueError, UnboundLocalError): 

535 # ValueError for doc.index 

536 # UnboundLocalError for undefined end in last line 

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

538 end = 0 

539 param_str = '' 

540 else: 

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

542 def change_options(m): 

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

544 for i, a in enumerate(args): 

545 if a and '=' not in a: 

546 args[i] += '=None' 

547 return ','.join(args) 

548 

549 while True: 

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

551 change_options, param_str) 

552 if changes == 0: 

553 break 

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

555 

556 # parse return value 

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

558 if r is None: 

559 ret = '' 

560 else: 

561 index = end + r.end() 

562 # get result type, which can contain newlines 

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

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

565 # New object -> object() 

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

567 

568 ret = docstr_defaults.get(ret_str, ret_str) 

569 

570 return param_str, ret 

571 

572 

573def create_from_name(inference_state, compiled_value, name): 

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

575 

576 value = None 

577 for access_path in access_paths: 

578 value = create_cached_compiled_value( 

579 inference_state, 

580 access_path, 

581 parent_context=None if value is None else value.as_context(), 

582 ) 

583 return value 

584 

585 

586def _normalize_create_args(func): 

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

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

589 return func(inference_state, obj, parent_context) 

590 return wrapper 

591 

592 

593def create_from_access_path(inference_state, access_path): 

594 value = None 

595 for name, access in access_path.accesses: 

596 value = create_cached_compiled_value( 

597 inference_state, 

598 access, 

599 parent_context=None if value is None else value.as_context() 

600 ) 

601 return value 

602 

603 

604@_normalize_create_args 

605@inference_state_function_cache() 

606def create_cached_compiled_value(inference_state, access_handle, parent_context): 

607 assert not isinstance(parent_context, CompiledValue) 

608 if parent_context is None: 

609 cls = CompiledModule 

610 else: 

611 cls = CompiledValue 

612 return cls(inference_state, access_handle, parent_context)