mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-06 14:04:26 +08:00
Get a lot of tests passing
This commit is contained in:
@@ -101,6 +101,7 @@ class Evaluator(object):
|
|||||||
self.is_analysis = False
|
self.is_analysis = False
|
||||||
self.python_version = sys.version_info[:2]
|
self.python_version = sys.version_info[:2]
|
||||||
self.project = project
|
self.project = project
|
||||||
|
self.access_cache = {}
|
||||||
project.add_evaluator(self)
|
project.add_evaluator(self)
|
||||||
|
|
||||||
if compiled_sub_process is None:
|
if compiled_sub_process is None:
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ Module for statical analysis.
|
|||||||
from jedi import debug
|
from jedi import debug
|
||||||
from parso.python import tree
|
from parso.python import tree
|
||||||
from jedi.evaluate.compiled import CompiledObject
|
from jedi.evaluate.compiled import CompiledObject
|
||||||
|
from jedi.evaluate.helpers import is_string
|
||||||
|
|
||||||
|
|
||||||
CODES = {
|
CODES = {
|
||||||
@@ -117,6 +118,7 @@ def add_attribute_error(name_context, lookup_context, name):
|
|||||||
slot_names = lookup_context.get_function_slot_names('__getattr__') + \
|
slot_names = lookup_context.get_function_slot_names('__getattr__') + \
|
||||||
lookup_context.get_function_slot_names('__getattribute__')
|
lookup_context.get_function_slot_names('__getattribute__')
|
||||||
for n in slot_names:
|
for n in slot_names:
|
||||||
|
# TODO do we even get here?
|
||||||
if isinstance(name, CompiledInstanceName) and \
|
if isinstance(name, CompiledInstanceName) and \
|
||||||
n.parent_context.obj == object:
|
n.parent_context.obj == object:
|
||||||
typ = Warning
|
typ = Warning
|
||||||
@@ -139,7 +141,7 @@ def _check_for_exception_catch(node_context, jedi_name, exception, payload=None)
|
|||||||
"""
|
"""
|
||||||
def check_match(cls, exception):
|
def check_match(cls, exception):
|
||||||
try:
|
try:
|
||||||
return isinstance(cls, CompiledObject) and issubclass(exception, cls.obj)
|
return isinstance(cls, CompiledObject) and cls.is_super_class(exception)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -189,8 +191,8 @@ def _check_for_exception_catch(node_context, jedi_name, exception, payload=None)
|
|||||||
# Check name
|
# Check name
|
||||||
key, lazy_context = args[1]
|
key, lazy_context = args[1]
|
||||||
names = list(lazy_context.infer())
|
names = list(lazy_context.infer())
|
||||||
assert len(names) == 1 and isinstance(names[0], CompiledObject)
|
assert len(names) == 1 and is_string(names[0])
|
||||||
assert names[0].obj == payload[1].value
|
assert names[0].get_safe_value() == payload[1].value
|
||||||
|
|
||||||
# Check objects
|
# Check objects
|
||||||
key, lazy_context = args[0]
|
key, lazy_context = args[0]
|
||||||
|
|||||||
@@ -8,15 +8,13 @@ import os
|
|||||||
import types
|
import types
|
||||||
from functools import partial
|
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 import debug
|
||||||
from jedi.cache import underscore_memoization, memoize_method
|
from jedi.cache import underscore_memoization, memoize_method
|
||||||
from jedi.evaluate.filters import AbstractFilter, AbstractNameDefinition, \
|
from jedi.evaluate.filters import AbstractFilter, AbstractNameDefinition, \
|
||||||
ContextNameMixin
|
ContextNameMixin
|
||||||
from jedi.evaluate.base_context import Context, ContextSet
|
from jedi.evaluate.base_context import Context, ContextSet
|
||||||
from jedi.evaluate.lazy_context import LazyKnownContext
|
from jedi.evaluate.compiled.access import DirectObjectAccess, _sentinel, create_access
|
||||||
from jedi.evaluate.compiled.getattr_static import getattr_static
|
|
||||||
from jedi.evaluate.compiled.access import DirectObjectAccess, _sentinel
|
|
||||||
from . import fake
|
from . import fake
|
||||||
|
|
||||||
|
|
||||||
@@ -75,7 +73,7 @@ class CompiledObject(Context):
|
|||||||
|
|
||||||
@CheckAttribute
|
@CheckAttribute
|
||||||
def py__class__(self):
|
def py__class__(self):
|
||||||
return create(self.evaluator, self.obj.__class__)
|
return create(self.evaluator, self.access.py__class__())
|
||||||
|
|
||||||
@CheckAttribute
|
@CheckAttribute
|
||||||
def py__mro__(self):
|
def py__mro__(self):
|
||||||
@@ -85,6 +83,7 @@ class CompiledObject(Context):
|
|||||||
|
|
||||||
@CheckAttribute
|
@CheckAttribute
|
||||||
def py__bases__(self):
|
def py__bases__(self):
|
||||||
|
raise NotImplementedError
|
||||||
return tuple(create(self.evaluator, cls) for cls in self.obj.__bases__)
|
return tuple(create(self.evaluator, cls) for cls in self.obj.__bases__)
|
||||||
|
|
||||||
def py__bool__(self):
|
def py__bool__(self):
|
||||||
@@ -111,7 +110,7 @@ class CompiledObject(Context):
|
|||||||
parts = p.strip().split('=')
|
parts = p.strip().split('=')
|
||||||
yield UnresolvableParamName(self, parts[0])
|
yield UnresolvableParamName(self, parts[0])
|
||||||
else:
|
else:
|
||||||
for signature_param in signature_params.values():
|
for signature_param in signature_params:
|
||||||
yield SignatureParamName(self, signature_param)
|
yield SignatureParamName(self, signature_param)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
@@ -201,7 +200,7 @@ class CompiledObject(Context):
|
|||||||
|
|
||||||
def dict_values(self):
|
def dict_values(self):
|
||||||
return ContextSet.from_iterable(
|
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):
|
def get_safe_value(self, default=_sentinel):
|
||||||
@@ -213,6 +212,12 @@ class CompiledObject(Context):
|
|||||||
self.access.execute_operation(other.access, operator)
|
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):
|
class CompiledName(AbstractNameDefinition):
|
||||||
def __init__(self, evaluator, parent_context, name):
|
def __init__(self, evaluator, parent_context, name):
|
||||||
@@ -304,8 +309,11 @@ class CompiledObjectFilter(AbstractFilter):
|
|||||||
@memoize_method
|
@memoize_method
|
||||||
def get(self, name):
|
def get(self, name):
|
||||||
name = str(name)
|
name = str(name)
|
||||||
if not self._compiled_object.access.is_allowed_getattr(name):
|
try:
|
||||||
return [EmptyCompiledName(self._evaluator, name)]
|
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():
|
if self._is_instance and name not in self._compiled_object.access.dir():
|
||||||
return []
|
return []
|
||||||
@@ -463,7 +471,6 @@ def _parse_function_doc(doc):
|
|||||||
|
|
||||||
def _create_from_name(evaluator, compiled_object, name):
|
def _create_from_name(evaluator, compiled_object, name):
|
||||||
faked = None
|
faked = None
|
||||||
print(compiled_object.tree_node)
|
|
||||||
try:
|
try:
|
||||||
faked = fake.get_faked_with_parent_context(compiled_object, name)
|
faked = fake.get_faked_with_parent_context(compiled_object, name)
|
||||||
if faked.type == 'funcdef':
|
if faked.type == 'funcdef':
|
||||||
@@ -472,8 +479,8 @@ def _create_from_name(evaluator, compiled_object, name):
|
|||||||
except fake.FakeDoesNotExist:
|
except fake.FakeDoesNotExist:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
obj = compiled_object.access.getattr(name, default=None)
|
access = compiled_object.access.getattr(name, default=None)
|
||||||
return create(evaluator, obj, parent_context=compiled_object, faked=faked)
|
return create(evaluator, access, parent_context=compiled_object, faked=faked)
|
||||||
|
|
||||||
|
|
||||||
def builtin_from_name(evaluator, string):
|
def builtin_from_name(evaluator, string):
|
||||||
@@ -498,7 +505,11 @@ _SPECIAL_OBJECTS = {
|
|||||||
|
|
||||||
def get_special_object(evaluator, identifier):
|
def get_special_object(evaluator, identifier):
|
||||||
obj = _SPECIAL_OBJECTS[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):
|
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
|
Caching the id has the advantage that an object doesn't need to be
|
||||||
hashable.
|
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)
|
cache = getattr(evaluator, attribute_name)
|
||||||
# Do a very cheap form of caching here.
|
# Do a very cheap form of caching here.
|
||||||
key = id(obj), id(parent_context)
|
key = id(obj), id(parent_context)
|
||||||
@@ -516,9 +527,9 @@ def compiled_objects_cache(attribute_name):
|
|||||||
return cache[key][0]
|
return cache[key][0]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
# TODO this whole decorator is way too ugly
|
# 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.
|
# 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 result
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
@@ -526,16 +537,17 @@ def compiled_objects_cache(attribute_name):
|
|||||||
|
|
||||||
|
|
||||||
@compiled_objects_cache('compiled_cache')
|
@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
|
A very weird interface class to this module. The more options provided the
|
||||||
more acurate loading compiled objects is.
|
more acurate loading compiled objects is.
|
||||||
"""
|
"""
|
||||||
print('create', obj)
|
|
||||||
if isinstance(obj, DirectObjectAccess):
|
if isinstance(obj, DirectObjectAccess):
|
||||||
access = obj
|
access = obj
|
||||||
else:
|
else:
|
||||||
access = DirectObjectAccess(obj)
|
print('xxx', obj)
|
||||||
|
return create(evaluator, create_access(evaluator, obj), parent_context, faked)
|
||||||
|
|
||||||
if inspect.ismodule(obj):
|
if inspect.ismodule(obj):
|
||||||
if parent_context is not None:
|
if parent_context is not None:
|
||||||
# Modules don't have parents, be careful with caching: recurse.
|
# 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
|
pass
|
||||||
else:
|
else:
|
||||||
for access2, tree_node in zip(accesses, tree_nodes):
|
for access2, tree_node in zip(accesses, tree_nodes):
|
||||||
parent_context = CompiledObject(evaluator, access2, parent_context, tree_node)
|
parent_context = create(evaluator, access2, parent_context, faked=tree_node)
|
||||||
print('foo', obj, tree_nodes, parent_context)
|
|
||||||
|
|
||||||
# TODO this if is ugly. Please remove, it may make certain
|
# TODO this if is ugly. Please remove, it may make certain
|
||||||
# properties of that function unusable.
|
# 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
|
from jedi.evaluate.context.function import FunctionContext
|
||||||
return FunctionContext(evaluator, parent_context.parent_context, tree_node)
|
return FunctionContext(evaluator, parent_context.parent_context, tree_node)
|
||||||
return parent_context
|
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)
|
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)
|
return CompiledObject(evaluator, access, parent_context, faked)
|
||||||
|
|
||||||
|
|
||||||
def _create_from_access(evaluator, access, parent_context=None, faked=None):
|
def _create_from_access(evaluator, access, parent_context=None, faked=None):
|
||||||
if parent_context is None:
|
if parent_context is None:
|
||||||
parent_context = create(evaluator, _builtins)
|
parent_context = create(evaluator, _builtins)
|
||||||
return CompiledObject(evaluator, access, parent_context, faked)
|
return create(evaluator, access, parent_context, faked=faked)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ from collections import namedtuple
|
|||||||
|
|
||||||
from jedi._compatibility import unicode, is_py3, is_py34, builtins, py_version
|
from jedi._compatibility import unicode, is_py3, is_py34, builtins, py_version
|
||||||
from jedi.evaluate.compiled.getattr_static import getattr_static
|
from jedi.evaluate.compiled.getattr_static import getattr_static
|
||||||
|
from jedi.evaluate.cache import evaluator_function_cache
|
||||||
|
|
||||||
|
|
||||||
MethodDescriptorType = type(str.replace)
|
MethodDescriptorType = type(str.replace)
|
||||||
@@ -76,15 +77,22 @@ _OPERATORS.update(COMPARISON_OPERATORS)
|
|||||||
SignatureParam = namedtuple('SignatureParam', 'name default empty annotation')
|
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):
|
class DirectObjectAccess(object):
|
||||||
def __init__(self, obj):
|
def __init__(self, evaluator, obj):
|
||||||
|
self._evaluator = evaluator
|
||||||
self._obj = obj
|
self._obj = obj
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '%s(%s)' % (self.__class__.__name__, self._obj)
|
return '%s(%s)' % (self.__class__.__name__, self._obj)
|
||||||
|
|
||||||
def _create_access(self, obj):
|
def _create_access(self, obj):
|
||||||
return DirectObjectAccess(obj)
|
return create_access(self._evaluator, obj)
|
||||||
|
|
||||||
def py__bool__(self):
|
def py__bool__(self):
|
||||||
return bool(self._obj)
|
return bool(self._obj)
|
||||||
@@ -99,7 +107,7 @@ class DirectObjectAccess(object):
|
|||||||
return inspect.getdoc(self._obj) or ''
|
return inspect.getdoc(self._obj) or ''
|
||||||
|
|
||||||
def py__name__(self):
|
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
|
inspect.ismethoddescriptor(self._obj): # slots
|
||||||
cls = self._obj
|
cls = self._obj
|
||||||
else:
|
else:
|
||||||
@@ -138,6 +146,9 @@ class DirectObjectAccess(object):
|
|||||||
lst.append(self._create_access(part))
|
lst.append(self._create_access(part))
|
||||||
return lst
|
return lst
|
||||||
|
|
||||||
|
def py__class__(self):
|
||||||
|
return self._create_access(self._obj.__class__)
|
||||||
|
|
||||||
def get_repr(self):
|
def get_repr(self):
|
||||||
return repr(self._obj)
|
return repr(self._obj)
|
||||||
|
|
||||||
@@ -161,7 +172,7 @@ class DirectObjectAccess(object):
|
|||||||
try:
|
try:
|
||||||
attr, is_get_descriptor = getattr_static(self._obj, name)
|
attr, is_get_descriptor = getattr_static(self._obj, name)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return []
|
raise
|
||||||
else:
|
else:
|
||||||
if is_get_descriptor \
|
if is_get_descriptor \
|
||||||
and not type(attr) in ALLOWED_DESCRIPTOR_ACCESS:
|
and not type(attr) in ALLOWED_DESCRIPTOR_ACCESS:
|
||||||
@@ -274,11 +285,20 @@ class DirectObjectAccess(object):
|
|||||||
default=p.default,
|
default=p.default,
|
||||||
empty=p.empty,
|
empty=p.empty,
|
||||||
annotation=p.annotation,
|
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."""
|
"""Like inspect.* methods."""
|
||||||
try:
|
try:
|
||||||
cls = obj.__class__
|
cls = obj.__class__
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class MixedObject(object):
|
|||||||
self.parent_context = parent_context
|
self.parent_context = parent_context
|
||||||
self.compiled_object = compiled_object
|
self.compiled_object = compiled_object
|
||||||
self._context = tree_context
|
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
|
# We have to overwrite everything that has to do with trailers, name
|
||||||
# lookups and filters to make it possible to route name lookups towards
|
# lookups and filters to make it possible to route name lookups towards
|
||||||
@@ -49,7 +49,7 @@ class MixedObject(object):
|
|||||||
yield MixedObjectFilter(self.evaluator, self)
|
yield MixedObjectFilter(self.evaluator, self)
|
||||||
|
|
||||||
def __repr__(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):
|
def __getattr__(self, name):
|
||||||
return getattr(self._context, name)
|
return getattr(self._context, name)
|
||||||
@@ -74,17 +74,11 @@ class MixedName(compiled.CompiledName):
|
|||||||
|
|
||||||
@underscore_memoization
|
@underscore_memoization
|
||||||
def infer(self):
|
def infer(self):
|
||||||
obj = self.parent_context.obj
|
access = self.parent_context.access
|
||||||
try:
|
# TODO use logic from compiled.CompiledObjectFilter
|
||||||
# TODO use logic from compiled.CompiledObjectFilter
|
access = access.getattr(self.string_name, default=None)
|
||||||
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
|
|
||||||
return ContextSet(
|
return ContextSet(
|
||||||
_create(self._evaluator, obj, parent_context=self.parent_context)
|
_create(self._evaluator, access, parent_context=self.parent_context)
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -135,7 +129,10 @@ def _get_object_to_check(python_object):
|
|||||||
raise TypeError # Prevents computation of `repr` within inspect.
|
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:
|
try:
|
||||||
python_object = _get_object_to_check(python_object)
|
python_object = _get_object_to_check(python_object)
|
||||||
path = inspect.getsourcefile(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')
|
@compiled.compiled_objects_cache('mixed_cache')
|
||||||
def _create(evaluator, obj, parent_context=None, *args):
|
def _create(evaluator, access, parent_context=None, *args):
|
||||||
tree_node, path = find_syntax_node_name(evaluator, obj)
|
tree_node, path = _find_syntax_node_name(evaluator, access)
|
||||||
|
|
||||||
compiled_object = compiled.create(
|
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:
|
if tree_node is None:
|
||||||
return compiled_object
|
return compiled_object
|
||||||
|
|
||||||
@@ -218,7 +215,7 @@ def _create(evaluator, obj, parent_context=None, *args):
|
|||||||
node_is_object=True
|
node_is_object=True
|
||||||
)
|
)
|
||||||
if tree_node.type == 'classdef':
|
if tree_node.type == 'classdef':
|
||||||
if not inspect.isclass(obj):
|
if not access.is_class():
|
||||||
# Is an instance, not a class.
|
# Is an instance, not a class.
|
||||||
tree_context, = tree_context.execute_evaluated()
|
tree_context, = tree_context.execute_evaluated()
|
||||||
|
|
||||||
@@ -228,4 +225,3 @@ def _create(evaluator, obj, parent_context=None, *args):
|
|||||||
compiled_object,
|
compiled_object,
|
||||||
tree_context=tree_context
|
tree_context=tree_context
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -373,7 +373,7 @@ class SequenceLiteralContext(ArrayMixin, AbstractIterable):
|
|||||||
for key_node, value in self._items():
|
for key_node, value in self._items():
|
||||||
for key in self._defining_context.eval_node(key_node):
|
for key in self._defining_context.eval_node(key_node):
|
||||||
if is_string(key):
|
if is_string(key):
|
||||||
yield key.obj, LazyTreeContext(self._defining_context, value)
|
yield key.get_safe_value(), LazyTreeContext(self._defining_context, value)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<%s of %s>" % (self.__class__.__name__, self.atom)
|
return "<%s of %s>" % (self.__class__.__name__, self.atom)
|
||||||
|
|||||||
@@ -192,4 +192,3 @@ def _create_default_param(execution_context, param):
|
|||||||
def create_default_params(execution_context, funcdef):
|
def create_default_params(execution_context, funcdef):
|
||||||
return [_create_default_param(execution_context, p)
|
return [_create_default_param(execution_context, p)
|
||||||
for p in funcdef.get_params()]
|
for p in funcdef.get_params()]
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ from jedi.evaluate import compiled
|
|||||||
from jedi.evaluate.base_context import NO_CONTEXTS, ContextSet
|
from jedi.evaluate.base_context import NO_CONTEXTS, ContextSet
|
||||||
from jedi.evaluate.lazy_context import LazyTreeContext
|
from jedi.evaluate.lazy_context import LazyTreeContext
|
||||||
from jedi.evaluate.context import ModuleContext
|
from jedi.evaluate.context import ModuleContext
|
||||||
|
from jedi.evaluate.helpers import is_string
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi import _compatibility
|
from jedi import _compatibility
|
||||||
from jedi import parser_utils
|
from jedi import parser_utils
|
||||||
@@ -60,16 +61,15 @@ def _fix_forward_reference(context, node):
|
|||||||
" not %s" % (node, evaled_nodes))
|
" not %s" % (node, evaled_nodes))
|
||||||
return node
|
return node
|
||||||
evaled_node = list(evaled_nodes)[0]
|
evaled_node = list(evaled_nodes)[0]
|
||||||
if isinstance(evaled_node, compiled.CompiledObject) and \
|
if is_string(evaled_node):
|
||||||
isinstance(evaled_node.obj, str):
|
|
||||||
try:
|
try:
|
||||||
new_node = context.evaluator.grammar.parse(
|
new_node = context.evaluator.grammar.parse(
|
||||||
_compatibility.unicode(evaled_node.obj),
|
_compatibility.unicode(evaled_node.get_safe_value()),
|
||||||
start_symbol='eval_input',
|
start_symbol='eval_input',
|
||||||
error_recovery=False
|
error_recovery=False
|
||||||
)
|
)
|
||||||
except ParserSyntaxError:
|
except ParserSyntaxError:
|
||||||
debug.warning('Annotation not parsed: %s' % evaled_node.obj)
|
debug.warning('Annotation not parsed: %s' % evaled_node)
|
||||||
return node
|
return node
|
||||||
else:
|
else:
|
||||||
module = node.get_root_node()
|
module = node.get_root_node()
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ def builtins_getattr(evaluator, objects, names, defaults=None):
|
|||||||
for obj in objects:
|
for obj in objects:
|
||||||
for name in names:
|
for name in names:
|
||||||
if is_string(name):
|
if is_string(name):
|
||||||
return obj.py__getattribute__(name.obj)
|
return obj.py__getattribute__(name.get_safe_value())
|
||||||
else:
|
else:
|
||||||
debug.warning('getattr called without str')
|
debug.warning('getattr called without str')
|
||||||
continue
|
continue
|
||||||
@@ -216,18 +216,21 @@ def builtins_reversed(evaluator, sequences, obj, arguments):
|
|||||||
def builtins_isinstance(evaluator, objects, types, arguments):
|
def builtins_isinstance(evaluator, objects, types, arguments):
|
||||||
bool_results = set()
|
bool_results = set()
|
||||||
for o in objects:
|
for o in objects:
|
||||||
|
cls = o.py__class__()
|
||||||
try:
|
try:
|
||||||
mro_func = o.py__class__().py__mro__
|
mro_func = cls.py__mro__
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# This is temporary. Everything should have a class attribute in
|
# This is temporary. Everything should have a class attribute in
|
||||||
# Python?! Maybe we'll leave it here, because some numpy objects or
|
# Python?! Maybe we'll leave it here, because some numpy objects or
|
||||||
# whatever might not.
|
# whatever might not.
|
||||||
return ContextSet(compiled.create(True), compiled.create(False))
|
return ContextSet(compiled.create(evaluator, True), compiled.create(evaluator, False))
|
||||||
|
|
||||||
mro = mro_func()
|
mro = mro_func()
|
||||||
|
print(mro, types)
|
||||||
|
|
||||||
for cls_or_tup in types:
|
for cls_or_tup in types:
|
||||||
if cls_or_tup.is_class():
|
if cls_or_tup.is_class():
|
||||||
|
print(id(mro[0]), mro[0], id(cls_or_tup), cls_or_tup)
|
||||||
bool_results.add(cls_or_tup in mro)
|
bool_results.add(cls_or_tup in mro)
|
||||||
elif cls_or_tup.name.string_name == 'tuple' \
|
elif cls_or_tup.name.string_name == 'tuple' \
|
||||||
and cls_or_tup.get_root_context() == evaluator.BUILTINS:
|
and cls_or_tup.get_root_context() == evaluator.BUILTINS:
|
||||||
@@ -246,6 +249,7 @@ def builtins_isinstance(evaluator, objects, types, arguments):
|
|||||||
'not %s.' % cls_or_tup
|
'not %s.' % cls_or_tup
|
||||||
analysis.add(lazy_context._context, 'type-error-isinstance', node, message)
|
analysis.add(lazy_context._context, 'type-error-isinstance', node, message)
|
||||||
|
|
||||||
|
print(objects, types, bool_results)
|
||||||
return ContextSet.from_iterable(compiled.create(evaluator, x) for x in bool_results)
|
return ContextSet.from_iterable(compiled.create(evaluator, x) for x in bool_results)
|
||||||
|
|
||||||
|
|
||||||
@@ -265,15 +269,16 @@ def collections_namedtuple(evaluator, obj, arguments):
|
|||||||
|
|
||||||
# Process arguments
|
# Process arguments
|
||||||
# TODO here we only use one of the types, we should use all.
|
# TODO here we only use one of the types, we should use all.
|
||||||
name = list(_follow_param(evaluator, arguments, 0))[0].obj
|
# TODO this is buggy, doesn't need to be a string
|
||||||
|
name = list(_follow_param(evaluator, arguments, 0))[0].get_safe_value()
|
||||||
_fields = list(_follow_param(evaluator, arguments, 1))[0]
|
_fields = list(_follow_param(evaluator, arguments, 1))[0]
|
||||||
if isinstance(_fields, compiled.CompiledObject):
|
if isinstance(_fields, compiled.CompiledObject):
|
||||||
fields = _fields.obj.replace(',', ' ').split()
|
fields = _fields.get_safe_value().replace(',', ' ').split()
|
||||||
elif isinstance(_fields, iterable.AbstractIterable):
|
elif isinstance(_fields, iterable.AbstractIterable):
|
||||||
fields = [
|
fields = [
|
||||||
v.obj
|
v.get_safe_value()
|
||||||
for lazy_context in _fields.py__iter__()
|
for lazy_context in _fields.py__iter__()
|
||||||
for v in lazy_context.infer() if hasattr(v, 'obj')
|
for v in lazy_context.infer() if is_string(v)
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
return NO_CONTEXTS
|
return NO_CONTEXTS
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
Functions evaluating the syntax tree.
|
Functions evaluating the syntax tree.
|
||||||
"""
|
"""
|
||||||
import copy
|
import copy
|
||||||
import operator as op
|
|
||||||
|
|
||||||
from parso.python import tree
|
from parso.python import tree
|
||||||
|
|
||||||
@@ -309,7 +308,7 @@ def eval_factor(context_set, operator):
|
|||||||
for context in context_set:
|
for context in context_set:
|
||||||
if operator == '-':
|
if operator == '-':
|
||||||
if is_number(context):
|
if is_number(context):
|
||||||
yield compiled.create(context.evaluator, -context.obj)
|
yield context.negate()
|
||||||
elif operator == 'not':
|
elif operator == 'not':
|
||||||
value = context.py__bool__()
|
value = context.py__bool__()
|
||||||
if value is None: # Uncertainty.
|
if value is None: # Uncertainty.
|
||||||
@@ -383,6 +382,7 @@ def _eval_comparison_part(evaluator, context, left, operator, right):
|
|||||||
# `int() % float()`.
|
# `int() % float()`.
|
||||||
return ContextSet(left)
|
return ContextSet(left)
|
||||||
elif operator in COMPARISON_OPERATORS:
|
elif operator in COMPARISON_OPERATORS:
|
||||||
|
print(operator, left, right)
|
||||||
if is_compiled(left) and is_compiled(right):
|
if is_compiled(left) and is_compiled(right):
|
||||||
# Possible, because the return is not an option. Just compare.
|
# Possible, because the return is not an option. Just compare.
|
||||||
try:
|
try:
|
||||||
@@ -391,8 +391,10 @@ def _eval_comparison_part(evaluator, context, left, operator, right):
|
|||||||
# Could be True or False.
|
# Could be True or False.
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError
|
if operator in ('is', '!=', '==', 'is not'):
|
||||||
return ContextSet(compiled.create(evaluator, result))
|
operation = COMPARISON_OPERATORS[operator]
|
||||||
|
bool_ = operation(left, right)
|
||||||
|
return ContextSet(compiled.create(evaluator, bool_))
|
||||||
|
|
||||||
return ContextSet(compiled.create(evaluator, True), compiled.create(evaluator, False))
|
return ContextSet(compiled.create(evaluator, True), compiled.create(evaluator, False))
|
||||||
elif operator == 'in':
|
elif operator == 'in':
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ def _paths_from_assignment(module_context, expr_stmt):
|
|||||||
for lazy_context in cn.infer().iterate(cn):
|
for lazy_context in cn.infer().iterate(cn):
|
||||||
for context in lazy_context.infer():
|
for context in lazy_context.infer():
|
||||||
if is_string(context):
|
if is_string(context):
|
||||||
abs_path = _abs_path(module_context, context.obj)
|
abs_path = _abs_path(module_context, context.get_safe_value())
|
||||||
if abs_path is not None:
|
if abs_path is not None:
|
||||||
yield abs_path
|
yield abs_path
|
||||||
|
|
||||||
@@ -144,7 +144,7 @@ def _paths_from_list_modifications(module_context, trailer1, trailer2):
|
|||||||
|
|
||||||
for context in module_context.create_context(arg).eval_node(arg):
|
for context in module_context.create_context(arg).eval_node(arg):
|
||||||
if is_string(context):
|
if is_string(context):
|
||||||
abs_path = _abs_path(module_context, context.obj)
|
abs_path = _abs_path(module_context, context.get_safe_value())
|
||||||
if abs_path is not None:
|
if abs_path is not None:
|
||||||
yield abs_path
|
yield abs_path
|
||||||
|
|
||||||
|
|||||||
@@ -125,3 +125,8 @@ class StaticAnalysisCase(object):
|
|||||||
def cwd_tmpdir(monkeypatch, tmpdir):
|
def cwd_tmpdir(monkeypatch, tmpdir):
|
||||||
with helpers.set_cwd(tmpdir.dirpath):
|
with helpers.set_cwd(tmpdir.dirpath):
|
||||||
yield tmpdir
|
yield tmpdir
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def evaluator():
|
||||||
|
return jedi.Script('')._evaluator
|
||||||
|
|||||||
@@ -28,11 +28,6 @@ def test_versions(version):
|
|||||||
assert any(executable in p for p in sys_path)
|
assert any(executable in p for p in sys_path)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def evaluator():
|
|
||||||
return jedi.Script('')._evaluator
|
|
||||||
|
|
||||||
|
|
||||||
def test_import_module(evaluator):
|
def test_import_module(evaluator):
|
||||||
compiled_obj = evaluator.compiled_subprocess.import_module(name='math')
|
compiled_obj = evaluator.compiled_subprocess.import_module(name='math')
|
||||||
assert compiled_obj.py__bool__() is True
|
assert compiled_obj.py__bool__() is True
|
||||||
|
|||||||
@@ -50,12 +50,12 @@ def test_parse_function_doc_illegal_docstr():
|
|||||||
assert ('', '') == compiled._parse_function_doc(docstr)
|
assert ('', '') == compiled._parse_function_doc(docstr)
|
||||||
|
|
||||||
|
|
||||||
def test_doc():
|
def test_doc(evaluator):
|
||||||
"""
|
"""
|
||||||
Even CompiledObject docs always return empty docstrings - not None, that's
|
Even CompiledObject docs always return empty docstrings - not None, that's
|
||||||
just a Jedi API definition.
|
just a Jedi API definition.
|
||||||
"""
|
"""
|
||||||
obj = compiled.CompiledObject(_evaluator(), ''.__getnewargs__)
|
obj = compiled.create(evaluator, ''.__getnewargs__)
|
||||||
assert obj.py__doc__() == ''
|
assert obj.py__doc__() == ''
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from jedi._compatibility import py_version, unicode
|
|||||||
|
|
||||||
def _eval_literal(code):
|
def _eval_literal(code):
|
||||||
def_, = jedi.Script(code).goto_definitions()
|
def_, = jedi.Script(code).goto_definitions()
|
||||||
return def_._name._context.obj
|
return def_._name._context.access._obj
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif('sys.version_info[:2] < (3, 6)')
|
@pytest.mark.skipif('sys.version_info[:2] < (3, 6)')
|
||||||
|
|||||||
@@ -14,4 +14,4 @@ def test_equals(source):
|
|||||||
script = Script(source)
|
script = Script(source)
|
||||||
node = script._get_module_node().children[0]
|
node = script._get_module_node().children[0]
|
||||||
first, = script._get_module().eval_node(node)
|
first, = script._get_module().eval_node(node)
|
||||||
assert isinstance(first, CompiledObject) and first.obj is True
|
assert isinstance(first, CompiledObject) and first.access._obj is True
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ def test_add_to_end():
|
|||||||
|
|
||||||
def test_tokenizer_with_string_literal_backslash():
|
def test_tokenizer_with_string_literal_backslash():
|
||||||
c = jedi.Script("statement = u'foo\\\n'; statement").goto_definitions()
|
c = jedi.Script("statement = u'foo\\\n'; statement").goto_definitions()
|
||||||
assert c[0]._name._context.obj == 'foo'
|
assert c[0]._name._context.get_safe_value() == 'foo'
|
||||||
|
|
||||||
|
|
||||||
def test_ellipsis():
|
def test_ellipsis():
|
||||||
|
|||||||
Reference in New Issue
Block a user