forked from VimPlug/jedi
Refactor compiled.CompiledObject so it always owns an evaluator instance.
This commit is contained in:
@@ -12,7 +12,7 @@ import warnings
|
||||
import sys
|
||||
from itertools import chain
|
||||
|
||||
from jedi._compatibility import unicode, builtins
|
||||
from jedi._compatibility import unicode
|
||||
from jedi.parser import Parser, load_grammar
|
||||
from jedi.parser.tokenize import source_tokens
|
||||
from jedi.parser import tree
|
||||
@@ -179,7 +179,7 @@ class Script(object):
|
||||
if unfinished_dotted:
|
||||
return completion_names
|
||||
else:
|
||||
return keywords.keyword_names('import')
|
||||
return keywords.keyword_names(self._evaluator, 'import')
|
||||
|
||||
if isinstance(user_stmt, tree.Import):
|
||||
module = self._parser.module()
|
||||
@@ -190,7 +190,7 @@ class Script(object):
|
||||
if names is None and not isinstance(user_stmt, tree.Import):
|
||||
if not path and not dot:
|
||||
# add keywords
|
||||
completion_names += keywords.keyword_names(all=True)
|
||||
completion_names += keywords.keyword_names(self._evaluator, all=True)
|
||||
# TODO delete? We should search for valid parser
|
||||
# transformations.
|
||||
completion_names += self._simple_complete(path, dot, like)
|
||||
@@ -206,8 +206,7 @@ class Script(object):
|
||||
|
||||
user_stmt = self._parser.user_stmt_with_whitespace()
|
||||
|
||||
b = compiled.builtin
|
||||
completion_names = get_completions(user_stmt, b)
|
||||
completion_names = get_completions(user_stmt, self._evaluator.BUILTINS)
|
||||
|
||||
if not dot:
|
||||
# add named params
|
||||
@@ -647,7 +646,7 @@ class Interpreter(Script):
|
||||
|
||||
paths = path.split('.') if path else []
|
||||
|
||||
namespaces = (NamespaceModule(), builtins)
|
||||
namespaces = (NamespaceModule(), BUILTINS)
|
||||
for p in paths:
|
||||
old, namespaces = namespaces, []
|
||||
for n in old:
|
||||
|
||||
@@ -15,7 +15,6 @@ from jedi.parser import load_grammar
|
||||
from jedi.parser.fast import FastParser
|
||||
from jedi.evaluate import helpers
|
||||
from jedi.evaluate import iterable
|
||||
from jedi.evaluate import representation as er
|
||||
|
||||
|
||||
def add_namespaces_to_parser(evaluator, namespaces, parser_module):
|
||||
@@ -92,10 +91,7 @@ class LazyName(helpers.FakeName):
|
||||
parser_path)
|
||||
|
||||
if not found:
|
||||
evaluated = compiled.CompiledObject(obj)
|
||||
if evaluated == builtins:
|
||||
# The builtins module is special and always cached.
|
||||
evaluated = compiled.builtin
|
||||
evaluated = compiled.create(self._evaluator, obj)
|
||||
found = [evaluated]
|
||||
|
||||
content = iterable.AlreadyEvaluated(found)
|
||||
|
||||
@@ -3,7 +3,6 @@ import keyword
|
||||
|
||||
from jedi._compatibility import is_py3
|
||||
from jedi import common
|
||||
from jedi.evaluate import compiled
|
||||
from jedi.evaluate.helpers import FakeName
|
||||
|
||||
try:
|
||||
@@ -18,27 +17,27 @@ else:
|
||||
keys = keyword.kwlist + ['None', 'False', 'True']
|
||||
|
||||
|
||||
def keywords(string='', pos=(0, 0), all=False):
|
||||
def keywords(evaluator, string='', pos=(0, 0), all=False):
|
||||
if all:
|
||||
return set([Keyword(k, pos) for k in keys])
|
||||
return set([Keyword(evaluator, k, pos) for k in keys])
|
||||
if string in keys:
|
||||
return set([Keyword(string, pos)])
|
||||
return set([Keyword(evaluator, string, pos)])
|
||||
return set()
|
||||
|
||||
|
||||
def keyword_names(*args, **kwargs):
|
||||
return [k.name for k in keywords(*args, **kwargs)]
|
||||
def keyword_names(evaluator, *args, **kwargs):
|
||||
return [k.name for k in keywords(evaluator, *args, **kwargs)]
|
||||
|
||||
|
||||
def get_operator(string, pos):
|
||||
return Keyword(string, pos)
|
||||
def get_operator(evaluator, string, pos):
|
||||
return Keyword(evaluator, string, pos)
|
||||
|
||||
|
||||
class Keyword(object):
|
||||
def __init__(self, name, pos):
|
||||
def __init__(self, evaluator, name, pos):
|
||||
self.name = FakeName(name, self, pos)
|
||||
self.start_pos = pos
|
||||
self.parent = compiled.builtin
|
||||
self.parent = evaluator.BUILTINS
|
||||
|
||||
def get_parent_until(self):
|
||||
return self.parent
|
||||
|
||||
@@ -33,7 +33,7 @@ enable_notice = False
|
||||
|
||||
# callback, interface: level, str
|
||||
debug_function = None
|
||||
ignored_modules = ['jedi.evaluate.builtin', 'jedi.parser']
|
||||
ignored_modules = ['jedi.parser']
|
||||
_debug_indent = 0
|
||||
_start_time = time.time()
|
||||
|
||||
|
||||
@@ -86,8 +86,8 @@ class Evaluator(object):
|
||||
# To memorize modules -> equals `sys.modules`.
|
||||
self.modules = {} # like `sys.modules`.
|
||||
self.compiled_cache = {} # see `compiled.create()`
|
||||
self.recursion_detector = recursion.RecursionDetector()
|
||||
self.execution_recursion_detector = recursion.ExecutionRecursionDetector()
|
||||
self.recursion_detector = recursion.RecursionDetector(self)
|
||||
self.execution_recursion_detector = recursion.ExecutionRecursionDetector(self)
|
||||
self.analysis = []
|
||||
self.predefined_if_name_dict_dict = {}
|
||||
self.is_analysis = False
|
||||
@@ -100,6 +100,9 @@ class Evaluator(object):
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# Constants
|
||||
self.BUILTINS = compiled.get_special_object(self, 'BUILTINS')
|
||||
|
||||
def wrap(self, element):
|
||||
if isinstance(element, tree.Class):
|
||||
return er.Class(self, element)
|
||||
@@ -256,14 +259,15 @@ class Evaluator(object):
|
||||
@debug.increase_indent
|
||||
def _eval_element_not_cached(self, element):
|
||||
debug.dbg('eval_element %s@%s', element, element.start_pos)
|
||||
types = set()
|
||||
if isinstance(element, (tree.Name, tree.Literal)) or tree.is_node(element, 'atom'):
|
||||
types = self._eval_atom(element)
|
||||
elif isinstance(element, tree.Keyword):
|
||||
# For False/True/None
|
||||
if element.value in ('False', 'True', 'None'):
|
||||
types = set([compiled.builtin.get_by_name(element.value)])
|
||||
types.add(compiled.builtin_from_name(self, element.value))
|
||||
else:
|
||||
types = set()
|
||||
raise NotImplementedError
|
||||
elif element.isinstance(tree.Lambda):
|
||||
types = set([er.LambdaWrapper(self, element)])
|
||||
elif element.isinstance(er.LambdaWrapper):
|
||||
|
||||
@@ -41,7 +41,8 @@ class CompiledObject(Base):
|
||||
path = None # modules have this attribute - set it to None.
|
||||
used_names = {} # To be consistent with modules.
|
||||
|
||||
def __init__(self, obj, parent=None):
|
||||
def __init__(self, evaluator, obj, parent=None):
|
||||
self._evaluator = evaluator
|
||||
self.obj = obj
|
||||
self.parent = parent
|
||||
|
||||
@@ -60,7 +61,7 @@ class CompiledObject(Base):
|
||||
|
||||
@CheckAttribute
|
||||
def py__class__(self, evaluator):
|
||||
return CompiledObject(self.obj.__class__, parent=self.parent)
|
||||
return create(evaluator, self.obj.__class__, parent=self.parent)
|
||||
|
||||
@CheckAttribute
|
||||
def py__mro__(self, evaluator):
|
||||
@@ -142,7 +143,7 @@ class CompiledObject(Base):
|
||||
# happens with numpy.core.umath._UFUNC_API (you get it
|
||||
# automatically by doing `import numpy`.
|
||||
c = type(None)
|
||||
return CompiledObject(c, self.parent)
|
||||
return create(self._evaluator, c, self.parent)
|
||||
return self
|
||||
|
||||
@property
|
||||
@@ -159,17 +160,18 @@ class CompiledObject(Base):
|
||||
search_global shouldn't change the fact that there's one dict, this way
|
||||
there's only one `object`.
|
||||
"""
|
||||
return [LazyNamesDict(self._cls(), is_instance)]
|
||||
return [LazyNamesDict(self._evaluator, self._cls(), is_instance)]
|
||||
|
||||
def get_subscope_by_name(self, name):
|
||||
if name in dir(self._cls().obj):
|
||||
return CompiledName(self._cls(), name).parent
|
||||
return CompiledName(self._evaluator, self._cls(), name).parent
|
||||
else:
|
||||
raise KeyError("CompiledObject doesn't have an attribute '%s'." % name)
|
||||
|
||||
def get_index_types(self, evaluator, index_array=()):
|
||||
# If the object doesn't have `__getitem__`, just raise the
|
||||
# AttributeError.
|
||||
raise NotImplementedError
|
||||
if not hasattr(self.obj, '__getitem__'):
|
||||
debug.warning('Tried to call __getitem__ on non-iterable.')
|
||||
return set()
|
||||
@@ -203,13 +205,13 @@ class CompiledObject(Base):
|
||||
if not hasattr(self.obj, '__iter__'):
|
||||
raise AttributeError('No __iter__ on %s' % self.obj)
|
||||
|
||||
def actual():
|
||||
def actual(evaluator):
|
||||
if type(self.obj) not in (str, list, tuple, unicode, bytes, bytearray, dict):
|
||||
# Get rid of side effects, we won't call custom `__getitem__`s.
|
||||
return
|
||||
|
||||
for part in self.obj:
|
||||
yield set([CompiledObject(part)])
|
||||
yield set([create(evaluator, part)])
|
||||
return actual
|
||||
|
||||
@property
|
||||
@@ -223,12 +225,13 @@ class CompiledObject(Base):
|
||||
|
||||
for name in self._parse_function_doc()[1].split():
|
||||
try:
|
||||
bltn_obj = _create_from_name(builtin, builtin, name)
|
||||
bltn_obj = builtin_from_name(evaluator, name)
|
||||
except AttributeError:
|
||||
continue
|
||||
else:
|
||||
if isinstance(bltn_obj, CompiledObject) and bltn_obj.obj is None:
|
||||
# We want everything except None.
|
||||
if bltn_obj.obj is None:
|
||||
# We want to evaluate everything except None.
|
||||
# TODO do we?
|
||||
continue
|
||||
for result in evaluator.execute(bltn_obj, params):
|
||||
yield result
|
||||
@@ -263,7 +266,8 @@ class LazyNamesDict(object):
|
||||
"""
|
||||
A names_dict instance for compiled objects, resembles the parser.tree.
|
||||
"""
|
||||
def __init__(self, compiled_obj, is_instance):
|
||||
def __init__(self, evaluator, compiled_obj, is_instance):
|
||||
self._evaluator = evaluator
|
||||
self._compiled_obj = compiled_obj
|
||||
self._is_instance = is_instance
|
||||
|
||||
@@ -276,7 +280,7 @@ class LazyNamesDict(object):
|
||||
getattr(self._compiled_obj.obj, name)
|
||||
except AttributeError:
|
||||
raise KeyError('%s in %s not found.' % (name, self._compiled_obj))
|
||||
return [CompiledName(self._compiled_obj, name)]
|
||||
return [CompiledName(self._evaluator, self._compiled_obj, name)]
|
||||
|
||||
def values(self):
|
||||
obj = self._compiled_obj.obj
|
||||
@@ -291,13 +295,14 @@ class LazyNamesDict(object):
|
||||
|
||||
# dir doesn't include the type names.
|
||||
if not inspect.ismodule(obj) and obj != type and not self._is_instance:
|
||||
values += _type_names_dict.values()
|
||||
values += create(self._evaluator, type).names_dict.values()
|
||||
return values
|
||||
|
||||
|
||||
class CompiledName(FakeName):
|
||||
def __init__(self, obj, name):
|
||||
def __init__(self, evaluator, obj, name):
|
||||
super(CompiledName, self).__init__(name)
|
||||
self._evaluator = evaluator
|
||||
self._obj = obj
|
||||
self.name = name
|
||||
|
||||
@@ -315,7 +320,7 @@ class CompiledName(FakeName):
|
||||
@underscore_memoization
|
||||
def parent(self):
|
||||
module = self._obj.get_parent_until()
|
||||
return _create_from_name(module, self._obj, self.name)
|
||||
return _create_from_name(self._evaluator, module, self._obj, self.name)
|
||||
|
||||
@parent.setter
|
||||
def parent(self, value):
|
||||
@@ -383,7 +388,7 @@ def load_module(evaluator, path=None, name=None):
|
||||
# complicated import structure of Python.
|
||||
module = sys.modules[dotted_path]
|
||||
|
||||
return CompiledObject(module)
|
||||
return create(evaluator, module)
|
||||
|
||||
|
||||
docstr_defaults = {
|
||||
@@ -455,19 +460,7 @@ def _parse_function_doc(doc):
|
||||
return param_str, ret
|
||||
|
||||
|
||||
class Builtin(CompiledObject):
|
||||
@memoize_method
|
||||
def get_by_name(self, name):
|
||||
return self.names_dict[name][0].parent
|
||||
|
||||
|
||||
def _a_generator(foo):
|
||||
"""Used to have an object to return for generators."""
|
||||
yield 42
|
||||
yield foo
|
||||
|
||||
|
||||
def _create_from_name(module, parent, name):
|
||||
def _create_from_name(evaluator, module, parent, name):
|
||||
faked = fake.get_faked(module.obj, parent.obj, name)
|
||||
# only functions are necessary.
|
||||
if faked is not None:
|
||||
@@ -481,35 +474,39 @@ def _create_from_name(module, parent, name):
|
||||
# PyQt4.QtGui.QStyleOptionComboBox.currentText
|
||||
# -> just set it to None
|
||||
obj = None
|
||||
return CompiledObject(obj, parent)
|
||||
return create(evaluator, obj, parent)
|
||||
|
||||
|
||||
builtin = Builtin(_builtins)
|
||||
# TODO Rename magic_function_class to just function_class or something similar.
|
||||
magic_function_class = CompiledObject(type(load_module), parent=builtin)
|
||||
module_class = CompiledObject(type(os))
|
||||
generator_obj = CompiledObject(_a_generator(1.0))
|
||||
_type_names_dict = builtin.get_by_name('type').names_dict
|
||||
none_obj = builtin.get_by_name('None')
|
||||
false_obj = builtin.get_by_name('False')
|
||||
true_obj = builtin.get_by_name('True')
|
||||
object_obj = builtin.get_by_name('object')
|
||||
def builtin_from_name(evaluator, string):
|
||||
bltn_obj = getattr(_builtins, string)
|
||||
return create(evaluator, bltn_obj)
|
||||
|
||||
|
||||
def keyword_from_value(obj):
|
||||
if obj is None:
|
||||
return none_obj
|
||||
elif obj is False:
|
||||
return false_obj
|
||||
elif obj is True:
|
||||
return true_obj
|
||||
else:
|
||||
raise NotImplementedError
|
||||
def _a_generator(foo):
|
||||
"""Used to have an object to return for generators."""
|
||||
yield 42
|
||||
yield foo
|
||||
|
||||
|
||||
_SPECIAL_OBJECTS = {
|
||||
'FUNCTION_CLASS': type(load_module),
|
||||
'MODULE_CLASS': type(os),
|
||||
'GENERATOR_OBJECT': _a_generator(1.0),
|
||||
'BUILTINS': _builtins,
|
||||
}
|
||||
|
||||
|
||||
def get_special_object(evaluator, identifier):
|
||||
obj = _SPECIAL_OBJECTS[identifier]
|
||||
return create(evaluator, obj, parent=create(evaluator, _builtins))
|
||||
|
||||
|
||||
def compiled_objects_cache(func):
|
||||
def wrapper(evaluator, obj, parent=builtin, module=None):
|
||||
def wrapper(evaluator, obj, parent=None, module=None):
|
||||
# Do a very cheap form of caching here.
|
||||
if parent is None and obj != _builtins:
|
||||
parent = create(evaluator, _builtins)
|
||||
|
||||
key = id(obj), id(parent), id(module)
|
||||
try:
|
||||
return evaluator.compiled_cache[key][0]
|
||||
@@ -522,22 +519,22 @@ def compiled_objects_cache(func):
|
||||
|
||||
|
||||
@compiled_objects_cache
|
||||
def create(evaluator, obj, parent=builtin, module=None):
|
||||
def create(evaluator, obj, parent=None, module=None):
|
||||
"""
|
||||
A very weird interface class to this module. The more options provided the
|
||||
more acurate loading compiled objects is.
|
||||
"""
|
||||
|
||||
if not inspect.ismodule(obj):
|
||||
faked = fake.get_faked(module and module.obj, obj)
|
||||
if faked is not None:
|
||||
faked.parent = parent
|
||||
return faked
|
||||
|
||||
try:
|
||||
if parent == builtin and obj.__module__ in ('builtins', '__builtin__'):
|
||||
return builtin.get_by_name(obj.__name__)
|
||||
except AttributeError:
|
||||
pass
|
||||
# TODO delete
|
||||
#try:
|
||||
#if parent == builtin and obj.__module__ in ('builtins', '__builtin__'):
|
||||
#return builtin.get_by_name(obj.__name__)
|
||||
#except AttributeError:
|
||||
#pass
|
||||
|
||||
return CompiledObject(obj, parent)
|
||||
return CompiledObject(evaluator, obj, parent)
|
||||
|
||||
@@ -63,6 +63,9 @@ def get_module(obj):
|
||||
except AttributeError:
|
||||
# Unfortunately in some cases like `int` there's no __module__
|
||||
return builtins
|
||||
else:
|
||||
if imp_plz is None:
|
||||
return builtins
|
||||
else:
|
||||
return __import__(imp_plz)
|
||||
|
||||
@@ -83,17 +86,23 @@ def _faked(module, obj, name):
|
||||
return search_scope(faked_mod, obj.__name__)
|
||||
elif not inspect.isclass(obj):
|
||||
# object is a method or descriptor
|
||||
cls = search_scope(faked_mod, obj.__objclass__.__name__)
|
||||
try:
|
||||
objclass = obj.__objclass__
|
||||
except AttributeError:
|
||||
return None
|
||||
else:
|
||||
cls = search_scope(faked_mod, objclass.__name__)
|
||||
if cls is None:
|
||||
return
|
||||
return None
|
||||
return search_scope(cls, obj.__name__)
|
||||
|
||||
else:
|
||||
if obj == module:
|
||||
return search_scope(faked_mod, name)
|
||||
else:
|
||||
cls = search_scope(faked_mod, obj.__name__)
|
||||
if cls is None:
|
||||
return
|
||||
return None
|
||||
return search_scope(cls, name)
|
||||
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@ class NameFinder(object):
|
||||
break
|
||||
|
||||
debug.dbg('finder.filter_name "%s" in (%s): %s@%s', self.name_str,
|
||||
self.scope, u(names), self.position)
|
||||
self.scope, names, self.position)
|
||||
return list(self._clean_names(names))
|
||||
|
||||
def _clean_names(self, names):
|
||||
@@ -398,7 +398,7 @@ def _eval_param(evaluator, param, scope):
|
||||
if not res_new:
|
||||
if param.stars:
|
||||
t = 'tuple' if param.stars == 1 else 'dict'
|
||||
typ = list(evaluator.find_types(compiled.builtin, t))[0]
|
||||
typ = list(evaluator.find_types(evaluator.BUILTINS, t))[0]
|
||||
res_new = evaluator.execute(typ)
|
||||
if param.default:
|
||||
res_new |= evaluator.eval_element(param.default)
|
||||
@@ -538,7 +538,7 @@ def global_names_dict_generator(evaluator, scope, position):
|
||||
scope = evaluator.wrap(scope.get_parent_scope())
|
||||
|
||||
# Add builtins to the global scope.
|
||||
for names_dict in compiled.builtin.names_dicts(True):
|
||||
for names_dict in evaluator.BUILTINS.names_dicts(True):
|
||||
yield names_dict, None
|
||||
|
||||
|
||||
|
||||
@@ -41,7 +41,8 @@ class GeneratorMixin(object):
|
||||
def names_dicts(self, search_global=False): # is always False
|
||||
dct = {}
|
||||
executes_generator = '__next__', 'send', 'next'
|
||||
for names in compiled.generator_obj.names_dict.values():
|
||||
gen_obj = compiled.get_special_object(self._evaluator, 'GENERATOR_OBJECT')
|
||||
for names in gen_obj.names_dict.values():
|
||||
for name in names:
|
||||
if name.value in executes_generator:
|
||||
parent = GeneratorMethod(self, name.parent)
|
||||
@@ -59,7 +60,8 @@ class GeneratorMixin(object):
|
||||
return True
|
||||
|
||||
def py__class__(self, evaluator):
|
||||
return compiled.generator_obj.py__class__(evaluator)
|
||||
gen_obj = compiled.get_special_object(self._evaluator, 'GENERATOR_OBJECT')
|
||||
return gen_obj.py__class__(evaluator)
|
||||
|
||||
|
||||
class Generator(use_metaclass(CachedMetaClass, IterableWrapper, GeneratorMixin)):
|
||||
@@ -185,7 +187,7 @@ class ArrayMixin(object):
|
||||
@memoize_default()
|
||||
def names_dicts(self, search_global=False): # Always False.
|
||||
# `array.type` is a string with the type, e.g. 'list'.
|
||||
scope = compiled.builtin.get_by_name(self.type)
|
||||
scope = compiled.builtin_from_name(self._evaluator, self.type)
|
||||
# builtins only have one class -> [0]
|
||||
scopes = self._evaluator.execute_evaluated(scope, self)
|
||||
return list(scopes)[0].names_dicts(search_global)
|
||||
@@ -194,7 +196,7 @@ class ArrayMixin(object):
|
||||
return None # We don't know the length, because of appends.
|
||||
|
||||
def py__class__(self, evaluator):
|
||||
return compiled.builtin.get_by_name(self.type)
|
||||
return compiled.builtin_from_name(evaluator, self.type)
|
||||
|
||||
|
||||
class ListComprehension(Comprehension, ArrayMixin):
|
||||
@@ -294,10 +296,10 @@ class Array(IterableWrapper, ArrayMixin):
|
||||
|
||||
@safe_property
|
||||
def parent(self):
|
||||
return compiled.builtin
|
||||
return self._evaluator.BUILTINS
|
||||
|
||||
def get_parent_until(self):
|
||||
return compiled.builtin
|
||||
return self._evaluator.BUILTINS
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name not in ['start_pos', 'get_only_subelement', 'parent',
|
||||
|
||||
@@ -6,8 +6,7 @@ import operator
|
||||
from jedi._compatibility import unicode
|
||||
from jedi.parser import tree
|
||||
from jedi import debug
|
||||
from jedi.evaluate.compiled import (CompiledObject, create, builtin,
|
||||
keyword_from_value, true_obj, false_obj)
|
||||
from jedi.evaluate.compiled import CompiledObject, create
|
||||
from jedi.evaluate import analysis
|
||||
|
||||
# Maps Python syntax to the operator module.
|
||||
@@ -31,8 +30,8 @@ def literals_to_types(evaluator, result):
|
||||
if is_literal(typ):
|
||||
# Literals are only valid as long as the operations are
|
||||
# correct. Otherwise add a value-free instance.
|
||||
cls = builtin.get_by_name(typ.name.get_code())
|
||||
new_result.add(list(evaluator.execute(cls))[0])
|
||||
cls = create(evaluator, typ.name.value)
|
||||
new_result |= evaluator.execute(cls)
|
||||
else:
|
||||
new_result.add(typ)
|
||||
return new_result
|
||||
@@ -97,7 +96,7 @@ def factor_calculate(evaluator, types, operator):
|
||||
value = typ.py__bool__()
|
||||
if value is None: # Uncertainty.
|
||||
return
|
||||
yield keyword_from_value(not value)
|
||||
yield create(evaluator, not value)
|
||||
else:
|
||||
yield typ
|
||||
|
||||
@@ -156,10 +155,12 @@ def _element_calculate(evaluator, left, operator, right):
|
||||
right = right.obj
|
||||
|
||||
try:
|
||||
return set([keyword_from_value(operation(left, right))])
|
||||
result = operation(left, right)
|
||||
except TypeError:
|
||||
# Could be True or False.
|
||||
return set([true_obj, false_obj])
|
||||
return set([create(evaluator, True), create(evaluator, False)])
|
||||
else:
|
||||
return set([create(evaluator, result)])
|
||||
elif operator == 'in':
|
||||
return set()
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ count the function calls.
|
||||
"""
|
||||
from jedi import debug
|
||||
from jedi import settings
|
||||
from jedi.evaluate import compiled
|
||||
from jedi.evaluate import iterable
|
||||
|
||||
|
||||
@@ -31,12 +30,13 @@ class RecursionDetector(object):
|
||||
A decorator to detect recursions in statements. In a recursion a statement
|
||||
at the same place, in the same module may not be executed two times.
|
||||
"""
|
||||
def __init__(self):
|
||||
def __init__(self, evaluator):
|
||||
self.top = None
|
||||
self.current = None
|
||||
self._evaluator = evaluator
|
||||
|
||||
def push_stmt(self, stmt):
|
||||
self.current = _RecursionNode(stmt, self.current)
|
||||
self.current = _RecursionNode(self._evaluator, stmt, self.current)
|
||||
check = self._check_recursion()
|
||||
if check:
|
||||
debug.warning('catched stmt recursion: %s against %s @%s', stmt,
|
||||
@@ -71,7 +71,8 @@ class RecursionDetector(object):
|
||||
|
||||
class _RecursionNode(object):
|
||||
""" A node of the RecursionDecorator. """
|
||||
def __init__(self, stmt, parent):
|
||||
def __init__(self, evaluator, stmt, parent):
|
||||
self._evaluator = evaluator
|
||||
self.script = stmt.get_parent_until()
|
||||
self.position = stmt.start_pos
|
||||
self.parent = parent
|
||||
@@ -80,7 +81,7 @@ class _RecursionNode(object):
|
||||
# Don't check param instances, they are not causing recursions
|
||||
# The same's true for the builtins, because the builtins are really
|
||||
# simple.
|
||||
self.is_ignored = self.script == compiled.builtin
|
||||
self.is_ignored = self.script == self._evaluator.BUILTINS
|
||||
|
||||
def __eq__(self, other):
|
||||
if not other:
|
||||
@@ -107,13 +108,13 @@ def execution_recursion_decorator(func):
|
||||
class ExecutionRecursionDetector(object):
|
||||
"""
|
||||
Catches recursions of executions.
|
||||
It is designed like a Singelton. Only one instance should exist.
|
||||
"""
|
||||
def __init__(self):
|
||||
def __init__(self, evaluator):
|
||||
self.recursion_level = 0
|
||||
self.parent_execution_funcs = []
|
||||
self.execution_funcs = set()
|
||||
self.execution_count = 0
|
||||
self._evaluator = evaluator
|
||||
|
||||
def __call__(self, execution):
|
||||
debug.dbg('Execution recursions: %s', execution, self.recursion_level,
|
||||
@@ -125,33 +126,33 @@ class ExecutionRecursionDetector(object):
|
||||
self.pop_execution()
|
||||
return result
|
||||
|
||||
def pop_execution(cls):
|
||||
cls.parent_execution_funcs.pop()
|
||||
cls.recursion_level -= 1
|
||||
def pop_execution(self):
|
||||
self.parent_execution_funcs.pop()
|
||||
self.recursion_level -= 1
|
||||
|
||||
def push_execution(cls, execution):
|
||||
in_par_execution_funcs = execution.base in cls.parent_execution_funcs
|
||||
in_execution_funcs = execution.base in cls.execution_funcs
|
||||
cls.recursion_level += 1
|
||||
cls.execution_count += 1
|
||||
cls.execution_funcs.add(execution.base)
|
||||
cls.parent_execution_funcs.append(execution.base)
|
||||
def push_execution(self, execution):
|
||||
in_par_execution_funcs = execution.base in self.parent_execution_funcs
|
||||
in_execution_funcs = execution.base in self.execution_funcs
|
||||
self.recursion_level += 1
|
||||
self.execution_count += 1
|
||||
self.execution_funcs.add(execution.base)
|
||||
self.parent_execution_funcs.append(execution.base)
|
||||
|
||||
if cls.execution_count > settings.max_executions:
|
||||
if self.execution_count > settings.max_executions:
|
||||
return True
|
||||
|
||||
if isinstance(execution.base, (iterable.Array, iterable.Generator)):
|
||||
return False
|
||||
module = execution.get_parent_until()
|
||||
if module == compiled.builtin:
|
||||
if module == self._evaluator.BUILTINS:
|
||||
return False
|
||||
|
||||
if in_par_execution_funcs:
|
||||
if cls.recursion_level > settings.max_function_recursion_level:
|
||||
if self.recursion_level > settings.max_function_recursion_level:
|
||||
return True
|
||||
if in_execution_funcs and \
|
||||
len(cls.execution_funcs) > settings.max_until_execution_unique:
|
||||
len(self.execution_funcs) > settings.max_until_execution_unique:
|
||||
return True
|
||||
if cls.execution_count > settings.max_executions_without_builtins:
|
||||
if self.execution_count > settings.max_executions_without_builtins:
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -86,7 +86,7 @@ class Instance(use_metaclass(CachedMetaClass, Executed)):
|
||||
self.is_generated = is_generated
|
||||
|
||||
if base.name.get_code() in ['list', 'set'] \
|
||||
and compiled.builtin == base.get_parent_until():
|
||||
and evaluator.BUILTINS == base.get_parent_until():
|
||||
# compare the module path with the builtin name.
|
||||
self.var_args = iterable.check_array_instances(evaluator, self)
|
||||
elif not is_generated:
|
||||
@@ -179,7 +179,8 @@ class Instance(use_metaclass(CachedMetaClass, Executed)):
|
||||
""" Throws a KeyError if there's no method. """
|
||||
# Arguments in __get__ descriptors are obj, class.
|
||||
# `method` is the new parent of the array, don't know if that's good.
|
||||
args = [obj, obj.base] if isinstance(obj, Instance) else [compiled.none_obj, obj]
|
||||
none_obj = compiled.create(self._evaluator, None)
|
||||
args = [obj, obj.base] if isinstance(obj, Instance) else [none_obj, obj]
|
||||
try:
|
||||
return self.execute_subscope_by_name('__get__', *args)
|
||||
except KeyError:
|
||||
@@ -454,7 +455,7 @@ class Class(use_metaclass(CachedMetaClass, Wrapper)):
|
||||
args = param.Arguments(self._evaluator, arglist)
|
||||
return list(chain.from_iterable(args.eval_args()))
|
||||
else:
|
||||
return [compiled.object_obj]
|
||||
return [compiled.create(evaluator, object)]
|
||||
|
||||
def py__call__(self, evaluator, params):
|
||||
return set([Instance(evaluator, self, params)])
|
||||
@@ -463,7 +464,7 @@ class Class(use_metaclass(CachedMetaClass, Wrapper)):
|
||||
return self._evaluator.find_types(self, name)
|
||||
|
||||
def py__class__(self, evaluator):
|
||||
return compiled.builtin.get_by_name('type')
|
||||
return compiled.create(evaluator, 'type')
|
||||
|
||||
@property
|
||||
def params(self):
|
||||
@@ -569,7 +570,8 @@ class Function(use_metaclass(CachedMetaClass, Wrapper)):
|
||||
if search_global:
|
||||
yield self.names_dict
|
||||
else:
|
||||
for names_dict in compiled.magic_function_class.names_dicts(False):
|
||||
scope = compiled.get_special_object(self._evaluator, 'FUNCTION_CLASS')
|
||||
for names_dict in scope.names_dicts(False):
|
||||
yield names_dict
|
||||
|
||||
@Python3Method
|
||||
@@ -580,7 +582,7 @@ class Function(use_metaclass(CachedMetaClass, Wrapper)):
|
||||
return FunctionExecution(evaluator, self, params).get_return_types()
|
||||
|
||||
def py__class__(self, evaluator):
|
||||
return compiled.magic_function_class
|
||||
return compiled.get_special_object(evaluator, 'FUNCTION_CLASS')
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(self.base_func, name)
|
||||
@@ -920,7 +922,7 @@ class ModuleWrapper(use_metaclass(CachedMetaClass, tree.Module, Wrapper)):
|
||||
return names
|
||||
|
||||
def py__class__(self, evaluator):
|
||||
return compiled.module_class
|
||||
return compiled.get_special_object(evaluator, 'MODULE_CLASS')
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(self._module, name)
|
||||
|
||||
@@ -32,7 +32,7 @@ def execute(evaluator, obj, arguments):
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
if obj.parent == compiled.builtin:
|
||||
if obj.parent == evaluator.BUILTINS:
|
||||
module_name = 'builtins'
|
||||
elif isinstance(obj.parent, tree.Module):
|
||||
module_name = str(obj.parent.name)
|
||||
@@ -183,7 +183,7 @@ def builtins_isinstance(evaluator, objects, types, arguments):
|
||||
# This is temporary. Everything should have a class attribute in
|
||||
# Python?! Maybe we'll leave it here, because some numpy objects or
|
||||
# whatever might not.
|
||||
return set([compiled.true_obj, compiled.false_obj])
|
||||
return set([compiled.create(True), compiled.create(False)])
|
||||
|
||||
mro = mro_func(evaluator)
|
||||
|
||||
@@ -191,7 +191,7 @@ def builtins_isinstance(evaluator, objects, types, arguments):
|
||||
if cls_or_tup.is_class():
|
||||
bool_results.add(cls_or_tup in mro)
|
||||
elif str(cls_or_tup.name) == 'tuple' \
|
||||
and cls_or_tup.get_parent_scope() == compiled.builtin:
|
||||
and cls_or_tup.get_parent_scope() == evaluator.BUILTINS:
|
||||
# Check for tuples.
|
||||
classes = unite(cls_or_tup.py__iter__())
|
||||
bool_results.add(any(cls in mro for cls in classes))
|
||||
@@ -200,7 +200,7 @@ def builtins_isinstance(evaluator, objects, types, arguments):
|
||||
for node in nodes:
|
||||
analysis.add(evaluator, 'type-error-isinstance', node)
|
||||
|
||||
return set(compiled.keyword_from_value(x) for x in bool_results)
|
||||
return set(compiled.create(evaluator, x) for x in bool_results)
|
||||
|
||||
|
||||
def collections_namedtuple(evaluator, obj, arguments):
|
||||
|
||||
Reference in New Issue
Block a user