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

326 statements  

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

1import inspect 

2import types 

3import traceback 

4import sys 

5import operator as op 

6from collections import namedtuple 

7import warnings 

8import re 

9import builtins 

10import typing 

11from pathlib import Path 

12from typing import Optional 

13 

14from jedi.inference.compiled.getattr_static import getattr_static 

15 

16ALLOWED_GETITEM_TYPES = (str, list, tuple, bytes, bytearray, dict) 

17 

18MethodDescriptorType = type(str.replace) 

19# These are not considered classes and access is granted even though they have 

20# a __class__ attribute. 

21NOT_CLASS_TYPES = ( 

22 types.BuiltinFunctionType, 

23 types.CodeType, 

24 types.FrameType, 

25 types.FunctionType, 

26 types.GeneratorType, 

27 types.GetSetDescriptorType, 

28 types.LambdaType, 

29 types.MemberDescriptorType, 

30 types.MethodType, 

31 types.ModuleType, 

32 types.TracebackType, 

33 MethodDescriptorType, 

34 types.MappingProxyType, 

35 types.SimpleNamespace, 

36 types.DynamicClassAttribute, 

37) 

38 

39# Those types don't exist in typing. 

40MethodDescriptorType = type(str.replace) 

41WrapperDescriptorType = type(set.__iter__) 

42# `object.__subclasshook__` is an already executed descriptor. 

43object_class_dict = type.__dict__["__dict__"].__get__(object) # type: ignore[index] 

44ClassMethodDescriptorType = type(object_class_dict['__subclasshook__']) 

45 

46_sentinel = object() 

47 

48# Maps Python syntax to the operator module. 

49COMPARISON_OPERATORS = { 

50 '==': op.eq, 

51 '!=': op.ne, 

52 'is': op.is_, 

53 'is not': op.is_not, 

54 '<': op.lt, 

55 '<=': op.le, 

56 '>': op.gt, 

57 '>=': op.ge, 

58} 

59 

60_OPERATORS = { 

61 '+': op.add, 

62 '-': op.sub, 

63} 

64_OPERATORS.update(COMPARISON_OPERATORS) 

65 

66ALLOWED_DESCRIPTOR_ACCESS = ( 

67 types.FunctionType, 

68 types.GetSetDescriptorType, 

69 types.MemberDescriptorType, 

70 MethodDescriptorType, 

71 WrapperDescriptorType, 

72 ClassMethodDescriptorType, 

73 staticmethod, 

74 classmethod, 

75) 

76 

77 

78def safe_getattr(obj, name, default=_sentinel): 

79 try: 

80 attr, is_get_descriptor = getattr_static(obj, name) 

81 except AttributeError: 

82 if default is _sentinel: 

83 raise 

84 return default 

85 else: 

86 if isinstance(attr, ALLOWED_DESCRIPTOR_ACCESS): 

87 # In case of descriptors that have get methods we cannot return 

88 # it's value, because that would mean code execution. 

89 # Since it's an isinstance call, code execution is still possible, 

90 # but this is not really a security feature, but much more of a 

91 # safety feature. Code execution is basically always possible when 

92 # a module is imported. This is here so people don't shoot 

93 # themselves in the foot. 

94 return getattr(obj, name) 

95 return attr 

96 

97 

98SignatureParam = namedtuple( 

99 'SignatureParam', 

100 'name has_default default default_string has_annotation annotation annotation_string kind_name' 

101) 

102 

103 

104def shorten_repr(func): 

105 def wrapper(self): 

106 r = func(self) 

107 if len(r) > 50: 

108 r = r[:50] + '..' 

109 return r 

110 return wrapper 

111 

112 

113def create_access(inference_state, obj): 

114 return inference_state.compiled_subprocess.get_or_create_access_handle(obj) 

115 

116 

117def load_module(inference_state, dotted_name, sys_path): 

118 temp, sys.path = sys.path, sys_path 

119 try: 

120 __import__(dotted_name) 

121 except ImportError: 

122 # If a module is "corrupt" or not really a Python module or whatever. 

123 warnings.warn( 

124 "Module %s not importable in path %s." % (dotted_name, sys_path), 

125 UserWarning, 

126 stacklevel=2, 

127 ) 

128 return None 

129 except Exception: 

130 # Since __import__ pretty much makes code execution possible, just 

131 # catch any error here and print it. 

132 warnings.warn( 

133 "Cannot import:\n%s" % traceback.format_exc(), UserWarning, stacklevel=2 

134 ) 

135 return None 

136 finally: 

137 sys.path = temp 

138 

139 # Just access the cache after import, because of #59 as well as the very 

140 # complicated import structure of Python. 

141 module = sys.modules[dotted_name] 

142 return create_access_path(inference_state, module) 

143 

144 

145class AccessPath: 

146 def __init__(self, accesses): 

147 self.accesses = accesses 

148 

149 

150def create_access_path(inference_state, obj): 

151 access = create_access(inference_state, obj) 

152 return AccessPath(access.get_access_path_tuples()) 

153 

154 

155def get_api_type(obj): 

156 if inspect.isclass(obj): 

157 return 'class' 

158 elif inspect.ismodule(obj): 

159 return 'module' 

160 elif inspect.isbuiltin(obj) or inspect.ismethod(obj) \ 

161 or inspect.ismethoddescriptor(obj) or inspect.isfunction(obj): 

162 return 'function' 

163 # Everything else... 

164 return 'instance' 

165 

166 

167class DirectObjectAccess: 

168 def __init__(self, inference_state, obj): 

169 self._inference_state = inference_state 

170 self._obj = obj 

171 

172 def __repr__(self): 

173 return '%s(%s)' % (self.__class__.__name__, self.get_repr()) 

174 

175 def _create_access(self, obj): 

176 return create_access(self._inference_state, obj) 

177 

178 def _create_access_path(self, obj): 

179 return create_access_path(self._inference_state, obj) 

180 

181 def py__bool__(self): 

182 return bool(self._obj) 

183 

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

185 try: 

186 return Path(self._obj.__file__) 

187 except AttributeError: 

188 return None 

189 

190 def py__doc__(self): 

191 return inspect.getdoc(self._obj) or '' 

192 

193 def py__name__(self): 

194 if not _is_class_instance(self._obj) or \ 

195 inspect.ismethoddescriptor(self._obj): # slots 

196 cls = self._obj 

197 else: 

198 try: 

199 cls = self._obj.__class__ 

200 except AttributeError: 

201 # happens with numpy.core.umath._UFUNC_API (you get it 

202 # automatically by doing `import numpy`. 

203 return None 

204 

205 try: 

206 return cls.__name__ 

207 except AttributeError: 

208 return None 

209 

210 def py__mro__accesses(self): 

211 return tuple(self._create_access_path(cls) for cls in self._obj.__mro__[1:]) 

212 

213 def py__getitem__all_values(self): 

214 if isinstance(self._obj, dict): 

215 return [self._create_access_path(v) for v in self._obj.values()] 

216 if isinstance(self._obj, (list, tuple)): 

217 return [self._create_access_path(v) for v in self._obj] 

218 

219 if self.is_instance(): 

220 cls = DirectObjectAccess(self._inference_state, self._obj.__class__) 

221 return cls.py__getitem__all_values() 

222 

223 try: 

224 getitem = self._obj.__getitem__ 

225 except AttributeError: 

226 pass 

227 else: 

228 annotation = DirectObjectAccess(self._inference_state, getitem).get_return_annotation() 

229 if annotation is not None: 

230 return [annotation] 

231 return None 

232 

233 def py__simple_getitem__(self, index): 

234 if type(self._obj) not in ALLOWED_GETITEM_TYPES: 

235 # Get rid of side effects, we won't call custom `__getitem__`s. 

236 return None 

237 

238 return self._create_access_path(self._obj[index]) 

239 

240 def py__iter__list(self): 

241 try: 

242 iter_method = self._obj.__iter__ 

243 except AttributeError: 

244 return None 

245 else: 

246 p = DirectObjectAccess(self._inference_state, iter_method).get_return_annotation() 

247 if p is not None: 

248 return [p] 

249 

250 if type(self._obj) not in ALLOWED_GETITEM_TYPES: 

251 # Get rid of side effects, we won't call custom `__getitem__`s. 

252 return [] 

253 

254 lst = [] 

255 for i, part in enumerate(self._obj): 

256 if i > 20: 

257 # Should not go crazy with large iterators 

258 break 

259 lst.append(self._create_access_path(part)) 

260 return lst 

261 

262 def py__class__(self): 

263 return self._create_access_path(self._obj.__class__) 

264 

265 def py__bases__(self): 

266 return [self._create_access_path(base) for base in self._obj.__bases__] 

267 

268 def py__path__(self): 

269 paths = getattr(self._obj, '__path__', None) 

270 # Avoid some weird hacks that would just fail, because they cannot be 

271 # used by pickle. 

272 if not isinstance(paths, list) \ 

273 or not all(isinstance(p, str) for p in paths): 

274 return None 

275 return paths 

276 

277 @shorten_repr 

278 def get_repr(self): 

279 if inspect.ismodule(self._obj): 

280 return repr(self._obj) 

281 # Try to avoid execution of the property. 

282 if safe_getattr(self._obj, '__module__', default='') == 'builtins': 

283 return repr(self._obj) 

284 

285 type_ = type(self._obj) 

286 if type_ == type: 

287 return type.__repr__(self._obj) 

288 

289 if safe_getattr(type_, '__module__', default='') == 'builtins': 

290 # Allow direct execution of repr for builtins. 

291 return repr(self._obj) 

292 return object.__repr__(self._obj) 

293 

294 def is_class(self): 

295 return inspect.isclass(self._obj) 

296 

297 def is_function(self): 

298 return inspect.isfunction(self._obj) or inspect.ismethod(self._obj) 

299 

300 def is_module(self): 

301 return inspect.ismodule(self._obj) 

302 

303 def is_instance(self): 

304 return _is_class_instance(self._obj) 

305 

306 def ismethoddescriptor(self): 

307 return inspect.ismethoddescriptor(self._obj) 

308 

309 def get_qualified_names(self): 

310 def try_to_get_name(obj): 

311 return getattr(obj, '__qualname__', getattr(obj, '__name__', None)) 

312 

313 if self.is_module(): 

314 return () 

315 name = try_to_get_name(self._obj) 

316 if name is None: 

317 name = try_to_get_name(type(self._obj)) 

318 if name is None: 

319 return () 

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

321 

322 def dir(self): 

323 return dir(self._obj) 

324 

325 def has_iter(self): 

326 try: 

327 iter(self._obj) 

328 return True 

329 except TypeError: 

330 return False 

331 

332 def is_allowed_getattr(self, name, safe=True): 

333 # TODO this API is ugly. 

334 if not safe: 

335 # Unsafe is mostly used to check for __getattr__/__getattribute__. 

336 # getattr_static works for properties, but the underscore methods 

337 # are just ignored (because it's safer and avoids more code 

338 # execution). See also GH #1378. 

339 

340 # Avoid warnings, see comment in the next function. 

341 with warnings.catch_warnings(record=True): 

342 warnings.simplefilter("always") 

343 try: 

344 return hasattr(self._obj, name), False 

345 except Exception: 

346 # Obviously has an attribute (propably a property) that 

347 # gets executed, so just avoid all exceptions here. 

348 return False, False 

349 try: 

350 attr, is_get_descriptor = getattr_static(self._obj, name) 

351 except AttributeError: 

352 return False, False 

353 else: 

354 if is_get_descriptor and type(attr) not in ALLOWED_DESCRIPTOR_ACCESS: 

355 # In case of descriptors that have get methods we cannot return 

356 # it's value, because that would mean code execution. 

357 return True, True 

358 return True, False 

359 

360 def getattr_paths(self, name, default=_sentinel): 

361 try: 

362 # Make sure no warnings are printed here, this is autocompletion, 

363 # warnings should not be shown. See also GH #1383. 

364 with warnings.catch_warnings(record=True): 

365 warnings.simplefilter("always") 

366 return_obj = getattr(self._obj, name) 

367 except Exception as e: 

368 if default is _sentinel: 

369 if isinstance(e, AttributeError): 

370 # Happens e.g. in properties of 

371 # PyQt4.QtGui.QStyleOptionComboBox.currentText 

372 # -> just set it to None 

373 raise 

374 # Just in case anything happens, return an AttributeError. It 

375 # should not crash. 

376 raise AttributeError 

377 return_obj = default 

378 access = self._create_access(return_obj) 

379 if inspect.ismodule(return_obj): 

380 return [access] 

381 

382 try: 

383 module = return_obj.__module__ 

384 except AttributeError: 

385 pass 

386 else: 

387 if module is not None and isinstance(module, str): 

388 try: 

389 __import__(module) 

390 # For some modules like _sqlite3, the __module__ for classes is 

391 # different, in this case it's sqlite3. So we have to try to 

392 # load that "original" module, because it's not loaded yet. If 

393 # we don't do that, we don't really have a "parent" module and 

394 # we would fall back to builtins. 

395 except ImportError: 

396 pass 

397 

398 module = inspect.getmodule(return_obj) 

399 if module is None: 

400 module = inspect.getmodule(type(return_obj)) 

401 if module is None: 

402 module = builtins 

403 return [self._create_access(module), access] 

404 

405 def get_safe_value(self): 

406 if type(self._obj) in (bool, bytes, float, int, str, slice) or self._obj is None: 

407 return self._obj 

408 raise ValueError("Object is type %s and not simple" % type(self._obj)) 

409 

410 def get_api_type(self): 

411 return get_api_type(self._obj) 

412 

413 def get_array_type(self): 

414 if isinstance(self._obj, dict): 

415 return 'dict' 

416 return None 

417 

418 def get_key_paths(self): 

419 def iter_partial_keys(): 

420 # We could use list(keys()), but that might take a lot more memory. 

421 for (i, k) in enumerate(self._obj.keys()): 

422 # Limit key listing at some point. This is artificial, but this 

423 # way we don't get stalled because of slow completions 

424 if i > 50: 

425 break 

426 yield k 

427 

428 return [self._create_access_path(k) for k in iter_partial_keys()] 

429 

430 def get_access_path_tuples(self): 

431 accesses = [create_access(self._inference_state, o) for o in self._get_objects_path()] 

432 return [(access.py__name__(), access) for access in accesses] 

433 

434 def _get_objects_path(self): 

435 def get(): 

436 obj = self._obj 

437 yield obj 

438 try: 

439 obj = obj.__objclass__ 

440 except AttributeError: 

441 pass 

442 else: 

443 yield obj 

444 

445 try: 

446 # Returns a dotted string path. 

447 imp_plz = obj.__module__ 

448 except AttributeError: 

449 # Unfortunately in some cases like `int` there's no __module__ 

450 if not inspect.ismodule(obj): 

451 yield builtins 

452 else: 

453 if imp_plz is None: 

454 # Happens for example in `(_ for _ in []).send.__module__`. 

455 yield builtins 

456 else: 

457 try: 

458 yield sys.modules[imp_plz] 

459 except KeyError: 

460 # __module__ can be something arbitrary that doesn't exist. 

461 yield builtins 

462 

463 return list(reversed(list(get()))) 

464 

465 def execute_operation(self, other_access_handle, operator): 

466 other_access = other_access_handle.access 

467 op = _OPERATORS[operator] 

468 return self._create_access_path(op(self._obj, other_access._obj)) 

469 

470 def get_annotation_name_and_args(self): 

471 """ 

472 Returns Tuple[Optional[str], Tuple[AccessPath, ...]] 

473 """ 

474 name = None 

475 args = () 

476 if safe_getattr(self._obj, '__module__', default='') == 'typing': 

477 m = re.match(r'typing.(\w+)\[', repr(self._obj)) 

478 if m is not None: 

479 name = m.group(1) 

480 

481 import typing 

482 if sys.version_info >= (3, 8): 

483 args = typing.get_args(self._obj) 

484 else: 

485 args = safe_getattr(self._obj, '__args__', default=None) 

486 return name, tuple(self._create_access_path(arg) for arg in args) 

487 

488 def needs_type_completions(self): 

489 return inspect.isclass(self._obj) and self._obj != type 

490 

491 def _annotation_to_str(self, annotation): 

492 return inspect.formatannotation(annotation) 

493 

494 def get_signature_params(self): 

495 return [ 

496 SignatureParam( 

497 name=p.name, 

498 has_default=p.default is not p.empty, 

499 default=self._create_access_path(p.default), 

500 default_string=repr(p.default), 

501 has_annotation=p.annotation is not p.empty, 

502 annotation=self._create_access_path(p.annotation), 

503 annotation_string=self._annotation_to_str(p.annotation), 

504 kind_name=str(p.kind) 

505 ) for p in self._get_signature().parameters.values() 

506 ] 

507 

508 def _get_signature(self): 

509 obj = self._obj 

510 try: 

511 return inspect.signature(obj) 

512 except (RuntimeError, TypeError): 

513 # Reading the code of the function in Python 3.6 implies there are 

514 # at least these errors that might occur if something is wrong with 

515 # the signature. In that case we just want a simple escape for now. 

516 raise ValueError 

517 

518 def get_return_annotation(self): 

519 try: 

520 o = self._obj.__annotations__.get('return') 

521 except AttributeError: 

522 return None 

523 

524 if o is None: 

525 return None 

526 

527 try: 

528 o = typing.get_type_hints(self._obj).get('return') 

529 except Exception: 

530 pass 

531 

532 return self._create_access_path(o) 

533 

534 def negate(self): 

535 return self._create_access_path(-self._obj) 

536 

537 def get_dir_infos(self): 

538 """ 

539 Used to return a couple of infos that are needed when accessing the sub 

540 objects of an objects 

541 """ 

542 tuples = dict( 

543 (name, self.is_allowed_getattr(name)) 

544 for name in self.dir() 

545 ) 

546 return self.needs_type_completions(), tuples 

547 

548 

549def _is_class_instance(obj): 

550 """Like inspect.* methods.""" 

551 try: 

552 cls = obj.__class__ 

553 except AttributeError: 

554 return False 

555 else: 

556 # The isinstance check for cls is just there so issubclass doesn't 

557 # raise an exception. 

558 return cls != type and isinstance(cls, type) and not issubclass(cls, NOT_CLASS_TYPES)