1
0
forked from VimPlug/jedi

Get a lot of tests passing

This commit is contained in:
Dave Halter
2017-11-26 17:48:00 +01:00
parent c266fb301b
commit e71f0062dd
17 changed files with 120 additions and 79 deletions

View File

@@ -8,15 +8,13 @@ import os
import types
from functools import partial
from jedi._compatibility import builtins as _builtins, unicode, py_version
from jedi._compatibility import builtins as _builtins
from jedi import debug
from jedi.cache import underscore_memoization, memoize_method
from jedi.evaluate.filters import AbstractFilter, AbstractNameDefinition, \
ContextNameMixin
from jedi.evaluate.base_context import Context, ContextSet
from jedi.evaluate.lazy_context import LazyKnownContext
from jedi.evaluate.compiled.getattr_static import getattr_static
from jedi.evaluate.compiled.access import DirectObjectAccess, _sentinel
from jedi.evaluate.compiled.access import DirectObjectAccess, _sentinel, create_access
from . import fake
@@ -75,7 +73,7 @@ class CompiledObject(Context):
@CheckAttribute
def py__class__(self):
return create(self.evaluator, self.obj.__class__)
return create(self.evaluator, self.access.py__class__())
@CheckAttribute
def py__mro__(self):
@@ -85,6 +83,7 @@ class CompiledObject(Context):
@CheckAttribute
def py__bases__(self):
raise NotImplementedError
return tuple(create(self.evaluator, cls) for cls in self.obj.__bases__)
def py__bool__(self):
@@ -111,7 +110,7 @@ class CompiledObject(Context):
parts = p.strip().split('=')
yield UnresolvableParamName(self, parts[0])
else:
for signature_param in signature_params.values():
for signature_param in signature_params:
yield SignatureParamName(self, signature_param)
def __repr__(self):
@@ -201,7 +200,7 @@ class CompiledObject(Context):
def dict_values(self):
return ContextSet.from_iterable(
create(self.evaluator, v) for v in self.obj.values()
create(self.evaluator, access) for access in self.access.dict_values()
)
def get_safe_value(self, default=_sentinel):
@@ -213,6 +212,12 @@ class CompiledObject(Context):
self.access.execute_operation(other.access, operator)
)
def negate(self):
return create(self.evaluator, self.access.negate())
def is_super_class(self, exception):
return self.access.is_super_class(exception)
class CompiledName(AbstractNameDefinition):
def __init__(self, evaluator, parent_context, name):
@@ -304,8 +309,11 @@ class CompiledObjectFilter(AbstractFilter):
@memoize_method
def get(self, name):
name = str(name)
if not self._compiled_object.access.is_allowed_getattr(name):
return [EmptyCompiledName(self._evaluator, name)]
try:
if not self._compiled_object.access.is_allowed_getattr(name):
return [EmptyCompiledName(self._evaluator, name)]
except AttributeError:
return []
if self._is_instance and name not in self._compiled_object.access.dir():
return []
@@ -463,7 +471,6 @@ def _parse_function_doc(doc):
def _create_from_name(evaluator, compiled_object, name):
faked = None
print(compiled_object.tree_node)
try:
faked = fake.get_faked_with_parent_context(compiled_object, name)
if faked.type == 'funcdef':
@@ -472,8 +479,8 @@ def _create_from_name(evaluator, compiled_object, name):
except fake.FakeDoesNotExist:
pass
obj = compiled_object.access.getattr(name, default=None)
return create(evaluator, obj, parent_context=compiled_object, faked=faked)
access = compiled_object.access.getattr(name, default=None)
return create(evaluator, access, parent_context=compiled_object, faked=faked)
def builtin_from_name(evaluator, string):
@@ -498,7 +505,11 @@ _SPECIAL_OBJECTS = {
def get_special_object(evaluator, identifier):
obj = _SPECIAL_OBJECTS[identifier]
return create(evaluator, obj, parent_context=create(evaluator, _builtins))
if identifier == 'BUILTINS':
parent_context = None
else:
parent_context = create(evaluator, _builtins)
return create(evaluator, obj, parent_context=parent_context)
def compiled_objects_cache(attribute_name):
@@ -508,7 +519,7 @@ def compiled_objects_cache(attribute_name):
Caching the id has the advantage that an object doesn't need to be
hashable.
"""
def wrapper(evaluator, obj, parent_context=None, module=None, faked=None):
def wrapper(evaluator, obj, parent_context=None, faked=None):
cache = getattr(evaluator, attribute_name)
# Do a very cheap form of caching here.
key = id(obj), id(parent_context)
@@ -516,9 +527,9 @@ def compiled_objects_cache(attribute_name):
return cache[key][0]
except KeyError:
# TODO this whole decorator is way too ugly
result = func(evaluator, obj, parent_context, module, faked)
result = func(evaluator, obj, parent_context, faked)
# Need to cache all of them, otherwise the id could be overwritten.
cache[key] = result, obj, parent_context, module, faked
cache[key] = result, obj, parent_context, faked
return result
return wrapper
@@ -526,16 +537,17 @@ def compiled_objects_cache(attribute_name):
@compiled_objects_cache('compiled_cache')
def create(evaluator, obj, parent_context=None, module=None, faked=None):
def create(evaluator, obj, parent_context=None, faked=None):
"""
A very weird interface class to this module. The more options provided the
more acurate loading compiled objects is.
"""
print('create', obj)
if isinstance(obj, DirectObjectAccess):
access = obj
else:
access = DirectObjectAccess(obj)
print('xxx', obj)
return create(evaluator, create_access(evaluator, obj), parent_context, faked)
if inspect.ismodule(obj):
if parent_context is not None:
# Modules don't have parents, be careful with caching: recurse.
@@ -554,8 +566,7 @@ def create(evaluator, obj, parent_context=None, module=None, faked=None):
pass
else:
for access2, tree_node in zip(accesses, tree_nodes):
parent_context = CompiledObject(evaluator, access2, parent_context, tree_node)
print('foo', obj, tree_nodes, parent_context)
parent_context = create(evaluator, access2, parent_context, faked=tree_node)
# TODO this if is ugly. Please remove, it may make certain
# properties of that function unusable.
@@ -563,13 +574,18 @@ def create(evaluator, obj, parent_context=None, module=None, faked=None):
from jedi.evaluate.context.function import FunctionContext
return FunctionContext(evaluator, parent_context.parent_context, tree_node)
return parent_context
if parent_context is None:
# TODO wow this is a mess....
if parent_context is None and not faked:
parent_context = create(evaluator, _builtins)
return create(evaluator, obj, parent_context)
print('OOOOOOOOOO', obj)
if access._obj == _builtins and parent_context is not None:
raise 1
return CompiledObject(evaluator, access, parent_context, faked)
def _create_from_access(evaluator, access, parent_context=None, faked=None):
if parent_context is None:
parent_context = create(evaluator, _builtins)
return CompiledObject(evaluator, access, parent_context, faked)
return create(evaluator, access, parent_context, faked=faked)

View File

@@ -5,6 +5,7 @@ from collections import namedtuple
from jedi._compatibility import unicode, is_py3, is_py34, builtins, py_version
from jedi.evaluate.compiled.getattr_static import getattr_static
from jedi.evaluate.cache import evaluator_function_cache
MethodDescriptorType = type(str.replace)
@@ -76,15 +77,22 @@ _OPERATORS.update(COMPARISON_OPERATORS)
SignatureParam = namedtuple('SignatureParam', 'name default empty annotation')
@evaluator_function_cache()
def create_access(evaluator, obj):
print('create', obj)
return DirectObjectAccess(evaluator, obj)
class DirectObjectAccess(object):
def __init__(self, obj):
def __init__(self, evaluator, obj):
self._evaluator = evaluator
self._obj = obj
def __repr__(self):
return '%s(%s)' % (self.__class__.__name__, self._obj)
def _create_access(self, obj):
return DirectObjectAccess(obj)
return create_access(self._evaluator, obj)
def py__bool__(self):
return bool(self._obj)
@@ -99,7 +107,7 @@ class DirectObjectAccess(object):
return inspect.getdoc(self._obj) or ''
def py__name__(self):
if not is_class_instance(self._obj) or \
if not _is_class_instance(self._obj) or \
inspect.ismethoddescriptor(self._obj): # slots
cls = self._obj
else:
@@ -138,6 +146,9 @@ class DirectObjectAccess(object):
lst.append(self._create_access(part))
return lst
def py__class__(self):
return self._create_access(self._obj.__class__)
def get_repr(self):
return repr(self._obj)
@@ -161,7 +172,7 @@ class DirectObjectAccess(object):
try:
attr, is_get_descriptor = getattr_static(self._obj, name)
except AttributeError:
return []
raise
else:
if is_get_descriptor \
and not type(attr) in ALLOWED_DESCRIPTOR_ACCESS:
@@ -274,11 +285,20 @@ class DirectObjectAccess(object):
default=p.default,
empty=p.empty,
annotation=p.annotation,
) for p in signature.parameters
) for p in signature.parameters.values()
]
def negate(self):
return self._create_access(-self._obj)
def is_class_instance(obj):
def dict_values(self):
return [self._create_access(v) for v in self._obj.values()]
def is_super_class(self, exception):
return issubclass(exception, self._obj)
def _is_class_instance(obj):
"""Like inspect.* methods."""
try:
cls = obj.__class__

View File

@@ -37,7 +37,7 @@ class MixedObject(object):
self.parent_context = parent_context
self.compiled_object = compiled_object
self._context = tree_context
self.obj = compiled_object.obj
self.access = compiled_object.access
# We have to overwrite everything that has to do with trailers, name
# lookups and filters to make it possible to route name lookups towards
@@ -49,7 +49,7 @@ class MixedObject(object):
yield MixedObjectFilter(self.evaluator, self)
def __repr__(self):
return '<%s: %s>' % (type(self).__name__, repr(self.obj))
return '<%s: %s>' % (type(self).__name__, repr(self.access))
def __getattr__(self, name):
return getattr(self._context, name)
@@ -74,17 +74,11 @@ class MixedName(compiled.CompiledName):
@underscore_memoization
def infer(self):
obj = self.parent_context.obj
try:
# TODO use logic from compiled.CompiledObjectFilter
obj = getattr(obj, self.string_name)
except AttributeError:
# Happens e.g. in properties of
# PyQt4.QtGui.QStyleOptionComboBox.currentText
# -> just set it to None
obj = None
access = self.parent_context.access
# TODO use logic from compiled.CompiledObjectFilter
access = access.getattr(self.string_name, default=None)
return ContextSet(
_create(self._evaluator, obj, parent_context=self.parent_context)
_create(self._evaluator, access, parent_context=self.parent_context)
)
@property
@@ -135,7 +129,10 @@ def _get_object_to_check(python_object):
raise TypeError # Prevents computation of `repr` within inspect.
def find_syntax_node_name(evaluator, python_object):
def _find_syntax_node_name(evaluator, access):
# TODO accessing this is bad, but it probably doesn't matter that much,
# because we're working with interpreteters only here.
python_object = access._obj
try:
python_object = _get_object_to_check(python_object)
path = inspect.getsourcefile(python_object)
@@ -195,11 +192,11 @@ def find_syntax_node_name(evaluator, python_object):
@compiled.compiled_objects_cache('mixed_cache')
def _create(evaluator, obj, parent_context=None, *args):
tree_node, path = find_syntax_node_name(evaluator, obj)
def _create(evaluator, access, parent_context=None, *args):
tree_node, path = _find_syntax_node_name(evaluator, access)
compiled_object = compiled.create(
evaluator, obj, parent_context=parent_context.compiled_object)
evaluator, access, parent_context=parent_context.compiled_object)
if tree_node is None:
return compiled_object
@@ -218,7 +215,7 @@ def _create(evaluator, obj, parent_context=None, *args):
node_is_object=True
)
if tree_node.type == 'classdef':
if not inspect.isclass(obj):
if not access.is_class():
# Is an instance, not a class.
tree_context, = tree_context.execute_evaluated()
@@ -228,4 +225,3 @@ def _create(evaluator, obj, parent_context=None, *args):
compiled_object,
tree_context=tree_context
)