From 972123c9c9e964191b734acfb7d65940037ab99f Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Fri, 28 Jul 2023 15:54:54 +0200 Subject: [PATCH] Introduce the property return annotation --- jedi/inference/compiled/access.py | 22 +++++++++++++--------- jedi/inference/compiled/value.py | 2 +- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/jedi/inference/compiled/access.py b/jedi/inference/compiled/access.py index fb2d6150..4a685bf1 100644 --- a/jedi/inference/compiled/access.py +++ b/jedi/inference/compiled/access.py @@ -9,7 +9,7 @@ import re import builtins import typing from pathlib import Path -from typing import Optional, Tuple +from typing import Optional, Tuple, Union from jedi.inference.compiled.getattr_static import getattr_static @@ -147,7 +147,7 @@ class AccessPath: self.accesses = accesses -def create_access_path(inference_state, obj): +def create_access_path(inference_state, obj) -> AccessPath: access = create_access(inference_state, obj) return AccessPath(access.get_access_path_tuples()) @@ -175,7 +175,7 @@ class DirectObjectAccess: def _create_access(self, obj): return create_access(self._inference_state, obj) - def _create_access_path(self, obj): + def _create_access_path(self, obj) -> AccessPath: return create_access_path(self._inference_state, obj) def py__bool__(self): @@ -329,7 +329,7 @@ class DirectObjectAccess: except TypeError: return False - def is_allowed_getattr(self, name, safe=True) -> Tuple[bool, bool]: + def is_allowed_getattr(self, name, safe=True) -> Tuple[bool, bool, Optional[AccessPath]]: # TODO this API is ugly. try: attr, is_get_descriptor = getattr_static(self._obj, name) @@ -344,18 +344,22 @@ class DirectObjectAccess: with warnings.catch_warnings(record=True): warnings.simplefilter("always") try: - return hasattr(self._obj, name), False + return hasattr(self._obj, name), False, None except Exception: # Obviously has an attribute (probably a property) that # gets executed, so just avoid all exceptions here. pass - return False, False + return False, False, None else: if is_get_descriptor and type(attr) not in ALLOWED_DESCRIPTOR_ACCESS: + if isinstance(attr, property): + if hasattr(attr.fget, '__annotations__'): + a = DirectObjectAccess(self._inference_state, attr) + return True, True, a.get_return_annotation() # In case of descriptors that have get methods we cannot return # it's value, because that would mean code execution. - return True, True - return True, False + return True, True, None + return True, False, None def getattr_paths(self, name, default=_sentinel): try: @@ -515,7 +519,7 @@ class DirectObjectAccess: # the signature. In that case we just want a simple escape for now. raise ValueError - def get_return_annotation(self): + def get_return_annotation(self) -> Optional[AccessPath]: try: o = self._obj.__annotations__.get('return') except AttributeError: diff --git a/jedi/inference/compiled/value.py b/jedi/inference/compiled/value.py index 60051320..bc716922 100644 --- a/jedi/inference/compiled/value.py +++ b/jedi/inference/compiled/value.py @@ -444,7 +444,7 @@ class CompiledValueFilter(AbstractFilter): """ To remove quite a few access calls we introduced the callback here. """ - has_attribute, is_descriptor = allowed_getattr_callback( + has_attribute, is_descriptor, property_return_annotation = allowed_getattr_callback( name, ) if check_has_attribute and not has_attribute: