1
0
forked from VimPlug/jedi

Refactor some things regarding Python 2 support

This commit is contained in:
Dave Halter
2017-12-27 02:09:58 +01:00
parent 7e063ff7af
commit a8d3c46e9d
4 changed files with 51 additions and 27 deletions

View File

@@ -45,18 +45,6 @@ WrapperDescriptorType = type(set.__iter__)
object_class_dict = type.__dict__["__dict__"].__get__(object)
ClassMethodDescriptorType = type(object_class_dict['__subclasshook__'])
ALLOWED_DESCRIPTOR_ACCESS = (
types.FunctionType,
types.GetSetDescriptorType,
types.MemberDescriptorType,
MethodDescriptorType,
WrapperDescriptorType,
ClassMethodDescriptorType,
staticmethod,
classmethod,
)
def _a_generator(foo):
"""Used to have an object to return for generators."""
yield 42
@@ -83,6 +71,32 @@ _OPERATORS = {
}
_OPERATORS.update(COMPARISON_OPERATORS)
ALLOWED_DESCRIPTOR_ACCESS = (
types.FunctionType,
types.GetSetDescriptorType,
types.MemberDescriptorType,
MethodDescriptorType,
WrapperDescriptorType,
ClassMethodDescriptorType,
staticmethod,
classmethod,
)
def safe_getattr(obj, name, default=_sentinel):
try:
attr, is_get_descriptor = getattr_static(obj, name)
except AttributeError:
if default is _sentinel:
raise
return default
else:
if is_get_descriptor and type(attr) in ALLOWED_DESCRIPTOR_ACCESS:
# In case of descriptors that have get methods we cannot return
# it's value, because that would mean code execution.
return getattr(obj, name)
return attr
SignatureParam = namedtuple('SignatureParam', 'name has_default default has_annotation annotation')
@@ -247,13 +261,19 @@ class DirectObjectAccess(object):
@_force_unicode_decorator
def get_repr(self):
builtins = 'builtins', '__builtin__'
if inspect.ismodule(self._obj):
return repr(self._obj)
# Try to avoid execution of the property.
if safe_getattr(self._obj, '__module__', default='') in builtins:
return repr(self._obj)
type_ = type(self._obj)
if type_ == type:
return type.__repr__(self._obj)
builtins = 'builtins', '__builtin__'
if getattr_static(type_, '__module__', default='') in builtins:
if safe_getattr(type_, '__module__', default='') in builtins:
# Allow direct execution of repr for builtins.
return repr(self._obj)
return object.__repr__(self._obj)
@@ -281,8 +301,7 @@ class DirectObjectAccess(object):
except AttributeError:
return False, False
else:
if is_get_descriptor \
and not type(attr) in ALLOWED_DESCRIPTOR_ACCESS:
if is_get_descriptor and type(attr) not in ALLOWED_DESCRIPTOR_ACCESS:
# In case of descriptors that have get methods we cannot return
# it's value, because that would mean code execution.
return True, True

View File

@@ -5,6 +5,7 @@ import re
from functools import partial
from jedi import debug
from jedi._compatibility import force_unicode
from jedi.cache import underscore_memoization, memoize_method
from jedi.evaluate.filters import AbstractFilter, AbstractNameDefinition, \
ContextNameMixin
@@ -313,6 +314,9 @@ class CompiledObjectFilter(AbstractFilter):
if not has_attribute:
return []
# Always use unicode objects in Python 2 from here.
name = force_unicode(name)
if is_descriptor:
return [self._get_cached_name(name, is_empty=True)]
@@ -442,7 +446,7 @@ def create_from_access_path(evaluator, access_path):
for name, access in access_path.accesses:
try:
if parent_context is None:
faked = fake.get_faked_module(evaluator.latest_grammar, access_path.accesses[0][0])
faked = fake.get_faked_module(evaluator, access_path.accesses[0][0])
else:
faked = fake.get_faked_with_parent_context(parent_context, name)
except fake.FakeDoesNotExist:

View File

@@ -29,17 +29,18 @@ class FakeDoesNotExist(Exception):
pass
def _load_faked_module(grammar, module_name):
if module_name == '__builtin__' and not is_py3:
module_name = 'builtins'
def _load_faked_module(evaluator, module_name):
try:
return fake_modules[module_name]
except KeyError:
pass
check_module_name = module_name
if module_name == '__builtin__' and evaluator.environment.version_info.major == 2:
check_module_name = 'builtins'
try:
path = _path_dict[module_name]
path = _path_dict[check_module_name]
except KeyError:
fake_modules[module_name] = None
return
@@ -47,9 +48,9 @@ def _load_faked_module(grammar, module_name):
with open(path) as f:
source = f.read()
fake_modules[module_name] = m = grammar.parse(unicode(source))
fake_modules[module_name] = m = evaluator.latest_grammar.parse(unicode(source))
if module_name == 'builtins' and not is_py3:
if check_module_name != module_name:
# There are two implementations of `open` for either python 2/3.
# -> Rename the python2 version (`look at fake/builtins.pym`).
open_func = _search_scope(m, 'open')
@@ -74,8 +75,8 @@ def get_faked_with_parent_context(parent_context, name):
raise FakeDoesNotExist
def get_faked_module(grammar, string_name):
module = _load_faked_module(grammar, string_name)
def get_faked_module(evaluator, string_name):
module = _load_faked_module(evaluator, string_name)
if module is None:
raise FakeDoesNotExist
return module

View File

@@ -64,7 +64,7 @@ def _fix_forward_reference(context, node):
if is_string(evaled_node):
try:
new_node = context.evaluator.grammar.parse(
_compatibility.unicode(evaled_node.get_safe_value()),
_compatibility.force_unicode(evaled_node.get_safe_value()),
start_symbol='eval_input',
error_recovery=False
)