mirror of
https://github.com/davidhalter/jedi.git
synced 2026-02-26 19:17:29 +08:00
Make sure that __getattr__ is always working with Interpreter
fixes #1378
This commit is contained in:
@@ -336,8 +336,23 @@ class DirectObjectAccess(object):
|
||||
except TypeError:
|
||||
return False
|
||||
|
||||
def is_allowed_getattr(self, name):
|
||||
def is_allowed_getattr(self, name, unsafe=False):
|
||||
# TODO this API is ugly.
|
||||
if unsafe:
|
||||
# Unsafe is mostly used to check for __getattr__/__getattribute__.
|
||||
# getattr_static works for properties, but the underscore methods
|
||||
# are just ignored (because it's safer and avoids more code
|
||||
# execution). See also GH #1378.
|
||||
|
||||
# Avoid warnings, see comment in the next function.
|
||||
with warnings.catch_warnings(record=True):
|
||||
warnings.simplefilter("always")
|
||||
try:
|
||||
return hasattr(self._obj, name), False
|
||||
except Exception:
|
||||
# Obviously has an attribute (propably a property) that
|
||||
# gets executed, so just avoid all exceptions here.
|
||||
return False, False
|
||||
try:
|
||||
attr, is_get_descriptor = getattr_static(self._obj, name)
|
||||
except AttributeError:
|
||||
@@ -490,7 +505,6 @@ class DirectObjectAccess(object):
|
||||
Used to return a couple of infos that are needed when accessing the sub
|
||||
objects of an objects
|
||||
"""
|
||||
# TODO is_allowed_getattr might raise an AttributeError
|
||||
tuples = dict(
|
||||
(force_unicode(name), self.is_allowed_getattr(name))
|
||||
for name in self.dir()
|
||||
|
||||
@@ -399,7 +399,7 @@ class CompiledObjectFilter(AbstractFilter):
|
||||
def get(self, name):
|
||||
return self._get(
|
||||
name,
|
||||
lambda name: self.compiled_object.access_handle.is_allowed_getattr(name),
|
||||
lambda name, unsafe: self.compiled_object.access_handle.is_allowed_getattr(name, unsafe),
|
||||
lambda name: name in self.compiled_object.access_handle.dir(),
|
||||
check_has_attribute=True
|
||||
)
|
||||
@@ -411,12 +411,18 @@ class CompiledObjectFilter(AbstractFilter):
|
||||
# Always use unicode objects in Python 2 from here.
|
||||
name = force_unicode(name)
|
||||
|
||||
has_attribute, is_descriptor = allowed_getattr_callback(name)
|
||||
if self._inference_state.allow_descriptor_getattr:
|
||||
pass
|
||||
|
||||
has_attribute, is_descriptor = allowed_getattr_callback(
|
||||
name,
|
||||
unsafe=self._inference_state.allow_descriptor_getattr
|
||||
)
|
||||
if check_has_attribute and not has_attribute:
|
||||
return []
|
||||
|
||||
if (is_descriptor and not self._inference_state.allow_descriptor_getattr) \
|
||||
or not has_attribute:
|
||||
if (is_descriptor or not has_attribute) \
|
||||
and not self._inference_state.allow_descriptor_getattr:
|
||||
return [self._get_cached_name(name, is_empty=True)]
|
||||
|
||||
if self.is_instance and not in_dir_callback(name):
|
||||
@@ -434,10 +440,15 @@ class CompiledObjectFilter(AbstractFilter):
|
||||
from jedi.inference.compiled import builtin_from_name
|
||||
names = []
|
||||
needs_type_completions, dir_infos = self.compiled_object.access_handle.get_dir_infos()
|
||||
# We could use `unsafe` here as well, especially as a parameter to
|
||||
# get_dir_infos. But this would lead to a lot of property executions
|
||||
# that are probably not wanted. The drawback for this is that we
|
||||
# have a different name for `get` and `values`. For `get` we always
|
||||
# execute.
|
||||
for name in dir_infos:
|
||||
names += self._get(
|
||||
name,
|
||||
lambda name: dir_infos[name],
|
||||
lambda name, unsafe: dir_infos[name],
|
||||
lambda name: name in dir_infos,
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user