1 import inspect 2 import types 3 import traceback 4 import sys 5 import operator as op 6 from collections import namedtuple 7 import warnings 8 import re 9 import builtins 10 import typing 11 from pathlib import Path 12 from typing import Optional, Tuple 13 14 from jedi.inference.compiled.getattr_static import getattr_static 15 16 ALLOWED_GETITEM_TYPES = (str, list, tuple, bytes, bytearray, dict) 17 18 MethodDescriptorType = type(str.replace) 19 # These are not considered classes and access is granted even though they have 20 # a __class__ attribute. 21 NOT_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. 40 MethodDescriptorType = type(str.replace) 41 WrapperDescriptorType = type(set.__iter__) 42 # `object.__subclasshook__` is an already executed descriptor. 43 object_class_dict = type.__dict__["__dict__"].__get__(object) # type: ignore[index] 44 ClassMethodDescriptorType = type(object_class_dict['__subclasshook__']) 45 46 _sentinel = object() 47 48 # Maps Python syntax to the operator module. 49 COMPARISON_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 66 ALLOWED_DESCRIPTOR_ACCESS = ( 67 types.FunctionType, 68 types.GetSetDescriptorType, 69 types.MemberDescriptorType, 70 MethodDescriptorType, 71 WrapperDescriptorType, 72 ClassMethodDescriptorType, 73 staticmethod, 74 classmethod, 75 ) 76 77 78 def 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 98 SignatureParam = namedtuple( 99 'SignatureParam', 100 'name has_default default default_string has_annotation annotation annotation_string kind_name' 101 ) 102 103 104 def 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 113 def create_access(inference_state, obj): 114 return inference_state.compiled_subprocess.get_or_create_access_handle(obj) 115 116 117 def 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 145 class AccessPath: 146 def __init__(self, accesses): 147 self.accesses = accesses 148 149 150 def create_access_path(inference_state, obj) -> AccessPath: 151 access = create_access(inference_state, obj) 152 return AccessPath(access.get_access_path_tuples()) 153 154 155 def 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 167 class 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) -> AccessPath: 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, *, safe=True): 234 if safe and 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) -> Tuple[bool, bool, Optional[AccessPath]]: 333 # TODO this API is ugly. 334 try: 335 attr, is_get_descriptor = getattr_static(self._obj, name) 336 except AttributeError: 337 if not safe: 338 # Unsafe is mostly used to check for __getattr__/__getattribute__. 339 # getattr_static works for properties, but the underscore methods 340 # are just ignored (because it's safer and avoids more code 341 # execution). See also GH #1378. 342 343 # Avoid warnings, see comment in the next function. 344 with warnings.catch_warnings(record=True): 345 warnings.simplefilter("always") 346 try: 347 return hasattr(self._obj, name), False, None 348 except Exception: 349 # Obviously has an attribute (probably a property) that 350 # gets executed, so just avoid all exceptions here. 351 pass 352 return False, False, None 353 else: 354 if is_get_descriptor and type(attr) not in ALLOWED_DESCRIPTOR_ACCESS: 355 if isinstance(attr, property): 356 if hasattr(attr.fget, '__annotations__'): 357 a = DirectObjectAccess(self._inference_state, attr.fget) 358 return True, True, a.get_return_annotation() 359 # In case of descriptors that have get methods we cannot return 360 # it's value, because that would mean code execution. 361 return True, True, None 362 return True, False, None 363 364 def getattr_paths(self, name, default=_sentinel): 365 try: 366 # Make sure no warnings are printed here, this is autocompletion, 367 # warnings should not be shown. See also GH #1383. 368 with warnings.catch_warnings(record=True): 369 warnings.simplefilter("always") 370 return_obj = getattr(self._obj, name) 371 except Exception as e: 372 if default is _sentinel: 373 if isinstance(e, AttributeError): 374 # Happens e.g. in properties of 375 # PyQt4.QtGui.QStyleOptionComboBox.currentText 376 # -> just set it to None 377 raise 378 # Just in case anything happens, return an AttributeError. It 379 # should not crash. 380 raise AttributeError 381 return_obj = default 382 access = self._create_access(return_obj) 383 if inspect.ismodule(return_obj): 384 return [access] 385 386 try: 387 module = return_obj.__module__ 388 except AttributeError: 389 pass 390 else: 391 if module is not None and isinstance(module, str): 392 try: 393 __import__(module) 394 # For some modules like _sqlite3, the __module__ for classes is 395 # different, in this case it's sqlite3. So we have to try to 396 # load that "original" module, because it's not loaded yet. If 397 # we don't do that, we don't really have a "parent" module and 398 # we would fall back to builtins. 399 except ImportError: 400 pass 401 402 module = inspect.getmodule(return_obj) 403 if module is None: 404 module = inspect.getmodule(type(return_obj)) 405 if module is None: 406 module = builtins 407 return [self._create_access(module), access] 408 409 def get_safe_value(self): 410 if type(self._obj) in (bool, bytes, float, int, str, slice) or self._obj is None: 411 return self._obj 412 raise ValueError("Object is type %s and not simple" % type(self._obj)) 413 414 def get_api_type(self): 415 return get_api_type(self._obj) 416 417 def get_array_type(self): 418 if isinstance(self._obj, dict): 419 return 'dict' 420 return None 421 422 def get_key_paths(self): 423 def iter_partial_keys(): 424 # We could use list(keys()), but that might take a lot more memory. 425 for (i, k) in enumerate(self._obj.keys()): 426 # Limit key listing at some point. This is artificial, but this 427 # way we don't get stalled because of slow completions 428 if i > 50: 429 break 430 yield k 431 432 return [self._create_access_path(k) for k in iter_partial_keys()] 433 434 def get_access_path_tuples(self): 435 accesses = [create_access(self._inference_state, o) for o in self._get_objects_path()] 436 return [(access.py__name__(), access) for access in accesses] 437 438 def _get_objects_path(self): 439 def get(): 440 obj = self._obj 441 yield obj 442 try: 443 obj = obj.__objclass__ 444 except AttributeError: 445 pass 446 else: 447 yield obj 448 449 try: 450 # Returns a dotted string path. 451 imp_plz = obj.__module__ 452 except AttributeError: 453 # Unfortunately in some cases like `int` there's no __module__ 454 if not inspect.ismodule(obj): 455 yield builtins 456 else: 457 if imp_plz is None: 458 # Happens for example in `(_ for _ in []).send.__module__`. 459 yield builtins 460 else: 461 try: 462 yield sys.modules[imp_plz] 463 except KeyError: 464 # __module__ can be something arbitrary that doesn't exist. 465 yield builtins 466 467 return list(reversed(list(get()))) 468 469 def execute_operation(self, other_access_handle, operator): 470 other_access = other_access_handle.access 471 op = _OPERATORS[operator] 472 return self._create_access_path(op(self._obj, other_access._obj)) 473 474 def get_annotation_name_and_args(self): 475 """ 476 Returns Tuple[Optional[str], Tuple[AccessPath, ...]] 477 """ 478 name = None 479 args = () 480 if safe_getattr(self._obj, '__module__', default='') == 'typing': 481 m = re.match(r'typing.(\w+)\[', repr(self._obj)) 482 if m is not None: 483 name = m.group(1) 484 485 import typing 486 if sys.version_info >= (3, 8): 487 args = typing.get_args(self._obj) 488 else: 489 args = safe_getattr(self._obj, '__args__', default=None) 490 return name, tuple(self._create_access_path(arg) for arg in args) 491 492 def needs_type_completions(self): 493 return inspect.isclass(self._obj) and self._obj != type 494 495 def _annotation_to_str(self, annotation): 496 return inspect.formatannotation(annotation) 497 498 def get_signature_params(self): 499 return [ 500 SignatureParam( 501 name=p.name, 502 has_default=p.default is not p.empty, 503 default=self._create_access_path(p.default), 504 default_string=repr(p.default), 505 has_annotation=p.annotation is not p.empty, 506 annotation=self._create_access_path(p.annotation), 507 annotation_string=self._annotation_to_str(p.annotation), 508 kind_name=str(p.kind) 509 ) for p in self._get_signature().parameters.values() 510 ] 511 512 def _get_signature(self): 513 obj = self._obj 514 try: 515 return inspect.signature(obj) 516 except (RuntimeError, TypeError): 517 # Reading the code of the function in Python 3.6 implies there are 518 # at least these errors that might occur if something is wrong with 519 # the signature. In that case we just want a simple escape for now. 520 raise ValueError 521 522 def get_return_annotation(self) -> Optional[AccessPath]: 523 try: 524 o = self._obj.__annotations__.get('return') 525 except AttributeError: 526 return None 527 528 if o is None: 529 return None 530 531 try: 532 o = typing.get_type_hints(self._obj).get('return') 533 except Exception: 534 pass 535 536 return self._create_access_path(o) 537 538 def negate(self): 539 return self._create_access_path(-self._obj) 540 541 def get_dir_infos(self): 542 """ 543 Used to return a couple of infos that are needed when accessing the sub 544 objects of an objects 545 """ 546 tuples = dict( 547 (name, self.is_allowed_getattr(name)) 548 for name in self.dir() 549 ) 550 return self.needs_type_completions(), tuples 551 552 553 def _is_class_instance(obj): 554 """Like inspect.* methods.""" 555 try: 556 cls = obj.__class__ 557 except AttributeError: 558 return False 559 else: 560 # The isinstance check for cls is just there so issubclass doesn't 561 # raise an exception. 562 return cls != type and isinstance(cls, type) and not issubclass(cls, NOT_CLASS_TYPES) 563