1
0
forked from VimPlug/jedi

Refactor compiled.CompiledObject so it always owns an evaluator instance.

This commit is contained in:
Dave Halter
2015-12-08 02:19:33 +01:00
parent 18a10c436f
commit bef5fca516
13 changed files with 149 additions and 139 deletions

View File

@@ -12,7 +12,7 @@ import warnings
import sys import sys
from itertools import chain 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 import Parser, load_grammar
from jedi.parser.tokenize import source_tokens from jedi.parser.tokenize import source_tokens
from jedi.parser import tree from jedi.parser import tree
@@ -179,7 +179,7 @@ class Script(object):
if unfinished_dotted: if unfinished_dotted:
return completion_names return completion_names
else: else:
return keywords.keyword_names('import') return keywords.keyword_names(self._evaluator, 'import')
if isinstance(user_stmt, tree.Import): if isinstance(user_stmt, tree.Import):
module = self._parser.module() module = self._parser.module()
@@ -190,7 +190,7 @@ class Script(object):
if names is None and not isinstance(user_stmt, tree.Import): if names is None and not isinstance(user_stmt, tree.Import):
if not path and not dot: if not path and not dot:
# add keywords # 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 # TODO delete? We should search for valid parser
# transformations. # transformations.
completion_names += self._simple_complete(path, dot, like) completion_names += self._simple_complete(path, dot, like)
@@ -206,8 +206,7 @@ class Script(object):
user_stmt = self._parser.user_stmt_with_whitespace() user_stmt = self._parser.user_stmt_with_whitespace()
b = compiled.builtin completion_names = get_completions(user_stmt, self._evaluator.BUILTINS)
completion_names = get_completions(user_stmt, b)
if not dot: if not dot:
# add named params # add named params
@@ -647,7 +646,7 @@ class Interpreter(Script):
paths = path.split('.') if path else [] paths = path.split('.') if path else []
namespaces = (NamespaceModule(), builtins) namespaces = (NamespaceModule(), BUILTINS)
for p in paths: for p in paths:
old, namespaces = namespaces, [] old, namespaces = namespaces, []
for n in old: for n in old:

View File

@@ -15,7 +15,6 @@ from jedi.parser import load_grammar
from jedi.parser.fast import FastParser from jedi.parser.fast import FastParser
from jedi.evaluate import helpers from jedi.evaluate import helpers
from jedi.evaluate import iterable from jedi.evaluate import iterable
from jedi.evaluate import representation as er
def add_namespaces_to_parser(evaluator, namespaces, parser_module): def add_namespaces_to_parser(evaluator, namespaces, parser_module):
@@ -92,10 +91,7 @@ class LazyName(helpers.FakeName):
parser_path) parser_path)
if not found: if not found:
evaluated = compiled.CompiledObject(obj) evaluated = compiled.create(self._evaluator, obj)
if evaluated == builtins:
# The builtins module is special and always cached.
evaluated = compiled.builtin
found = [evaluated] found = [evaluated]
content = iterable.AlreadyEvaluated(found) content = iterable.AlreadyEvaluated(found)

View File

@@ -3,7 +3,6 @@ import keyword
from jedi._compatibility import is_py3 from jedi._compatibility import is_py3
from jedi import common from jedi import common
from jedi.evaluate import compiled
from jedi.evaluate.helpers import FakeName from jedi.evaluate.helpers import FakeName
try: try:
@@ -18,27 +17,27 @@ else:
keys = keyword.kwlist + ['None', 'False', 'True'] 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: 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: if string in keys:
return set([Keyword(string, pos)]) return set([Keyword(evaluator, string, pos)])
return set() return set()
def keyword_names(*args, **kwargs): def keyword_names(evaluator, *args, **kwargs):
return [k.name for k in keywords(*args, **kwargs)] return [k.name for k in keywords(evaluator, *args, **kwargs)]
def get_operator(string, pos): def get_operator(evaluator, string, pos):
return Keyword(string, pos) return Keyword(evaluator, string, pos)
class Keyword(object): class Keyword(object):
def __init__(self, name, pos): def __init__(self, evaluator, name, pos):
self.name = FakeName(name, self, pos) self.name = FakeName(name, self, pos)
self.start_pos = pos self.start_pos = pos
self.parent = compiled.builtin self.parent = evaluator.BUILTINS
def get_parent_until(self): def get_parent_until(self):
return self.parent return self.parent

View File

@@ -33,7 +33,7 @@ enable_notice = False
# callback, interface: level, str # callback, interface: level, str
debug_function = None debug_function = None
ignored_modules = ['jedi.evaluate.builtin', 'jedi.parser'] ignored_modules = ['jedi.parser']
_debug_indent = 0 _debug_indent = 0
_start_time = time.time() _start_time = time.time()

View File

@@ -86,8 +86,8 @@ class Evaluator(object):
# To memorize modules -> equals `sys.modules`. # To memorize modules -> equals `sys.modules`.
self.modules = {} # like `sys.modules`. self.modules = {} # like `sys.modules`.
self.compiled_cache = {} # see `compiled.create()` self.compiled_cache = {} # see `compiled.create()`
self.recursion_detector = recursion.RecursionDetector() self.recursion_detector = recursion.RecursionDetector(self)
self.execution_recursion_detector = recursion.ExecutionRecursionDetector() self.execution_recursion_detector = recursion.ExecutionRecursionDetector(self)
self.analysis = [] self.analysis = []
self.predefined_if_name_dict_dict = {} self.predefined_if_name_dict_dict = {}
self.is_analysis = False self.is_analysis = False
@@ -100,6 +100,9 @@ class Evaluator(object):
except ValueError: except ValueError:
pass pass
# Constants
self.BUILTINS = compiled.get_special_object(self, 'BUILTINS')
def wrap(self, element): def wrap(self, element):
if isinstance(element, tree.Class): if isinstance(element, tree.Class):
return er.Class(self, element) return er.Class(self, element)
@@ -256,14 +259,15 @@ class Evaluator(object):
@debug.increase_indent @debug.increase_indent
def _eval_element_not_cached(self, element): def _eval_element_not_cached(self, element):
debug.dbg('eval_element %s@%s', element, element.start_pos) 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'): if isinstance(element, (tree.Name, tree.Literal)) or tree.is_node(element, 'atom'):
types = self._eval_atom(element) types = self._eval_atom(element)
elif isinstance(element, tree.Keyword): elif isinstance(element, tree.Keyword):
# For False/True/None # For False/True/None
if element.value in ('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: else:
types = set() raise NotImplementedError
elif element.isinstance(tree.Lambda): elif element.isinstance(tree.Lambda):
types = set([er.LambdaWrapper(self, element)]) types = set([er.LambdaWrapper(self, element)])
elif element.isinstance(er.LambdaWrapper): elif element.isinstance(er.LambdaWrapper):

View File

@@ -41,7 +41,8 @@ class CompiledObject(Base):
path = None # modules have this attribute - set it to None. path = None # modules have this attribute - set it to None.
used_names = {} # To be consistent with modules. 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.obj = obj
self.parent = parent self.parent = parent
@@ -60,7 +61,7 @@ class CompiledObject(Base):
@CheckAttribute @CheckAttribute
def py__class__(self, evaluator): def py__class__(self, evaluator):
return CompiledObject(self.obj.__class__, parent=self.parent) return create(evaluator, self.obj.__class__, parent=self.parent)
@CheckAttribute @CheckAttribute
def py__mro__(self, evaluator): def py__mro__(self, evaluator):
@@ -142,7 +143,7 @@ class CompiledObject(Base):
# happens with numpy.core.umath._UFUNC_API (you get it # happens with numpy.core.umath._UFUNC_API (you get it
# automatically by doing `import numpy`. # automatically by doing `import numpy`.
c = type(None) c = type(None)
return CompiledObject(c, self.parent) return create(self._evaluator, c, self.parent)
return self return self
@property @property
@@ -159,17 +160,18 @@ class CompiledObject(Base):
search_global shouldn't change the fact that there's one dict, this way search_global shouldn't change the fact that there's one dict, this way
there's only one `object`. 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): def get_subscope_by_name(self, name):
if name in dir(self._cls().obj): if name in dir(self._cls().obj):
return CompiledName(self._cls(), name).parent return CompiledName(self._evaluator, self._cls(), name).parent
else: else:
raise KeyError("CompiledObject doesn't have an attribute '%s'." % name) raise KeyError("CompiledObject doesn't have an attribute '%s'." % name)
def get_index_types(self, evaluator, index_array=()): def get_index_types(self, evaluator, index_array=()):
# If the object doesn't have `__getitem__`, just raise the # If the object doesn't have `__getitem__`, just raise the
# AttributeError. # AttributeError.
raise NotImplementedError
if not hasattr(self.obj, '__getitem__'): if not hasattr(self.obj, '__getitem__'):
debug.warning('Tried to call __getitem__ on non-iterable.') debug.warning('Tried to call __getitem__ on non-iterable.')
return set() return set()
@@ -203,13 +205,13 @@ class CompiledObject(Base):
if not hasattr(self.obj, '__iter__'): if not hasattr(self.obj, '__iter__'):
raise AttributeError('No __iter__ on %s' % self.obj) 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): 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. # Get rid of side effects, we won't call custom `__getitem__`s.
return return
for part in self.obj: for part in self.obj:
yield set([CompiledObject(part)]) yield set([create(evaluator, part)])
return actual return actual
@property @property
@@ -223,12 +225,13 @@ class CompiledObject(Base):
for name in self._parse_function_doc()[1].split(): for name in self._parse_function_doc()[1].split():
try: try:
bltn_obj = _create_from_name(builtin, builtin, name) bltn_obj = builtin_from_name(evaluator, name)
except AttributeError: except AttributeError:
continue continue
else: else:
if isinstance(bltn_obj, CompiledObject) and bltn_obj.obj is None: if bltn_obj.obj is None:
# We want everything except None. # We want to evaluate everything except None.
# TODO do we?
continue continue
for result in evaluator.execute(bltn_obj, params): for result in evaluator.execute(bltn_obj, params):
yield result yield result
@@ -263,7 +266,8 @@ class LazyNamesDict(object):
""" """
A names_dict instance for compiled objects, resembles the parser.tree. 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._compiled_obj = compiled_obj
self._is_instance = is_instance self._is_instance = is_instance
@@ -276,7 +280,7 @@ class LazyNamesDict(object):
getattr(self._compiled_obj.obj, name) getattr(self._compiled_obj.obj, name)
except AttributeError: except AttributeError:
raise KeyError('%s in %s not found.' % (name, self._compiled_obj)) 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): def values(self):
obj = self._compiled_obj.obj obj = self._compiled_obj.obj
@@ -291,13 +295,14 @@ class LazyNamesDict(object):
# dir doesn't include the type names. # dir doesn't include the type names.
if not inspect.ismodule(obj) and obj != type and not self._is_instance: 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 return values
class CompiledName(FakeName): class CompiledName(FakeName):
def __init__(self, obj, name): def __init__(self, evaluator, obj, name):
super(CompiledName, self).__init__(name) super(CompiledName, self).__init__(name)
self._evaluator = evaluator
self._obj = obj self._obj = obj
self.name = name self.name = name
@@ -315,7 +320,7 @@ class CompiledName(FakeName):
@underscore_memoization @underscore_memoization
def parent(self): def parent(self):
module = self._obj.get_parent_until() 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 @parent.setter
def parent(self, value): def parent(self, value):
@@ -383,7 +388,7 @@ def load_module(evaluator, path=None, name=None):
# complicated import structure of Python. # complicated import structure of Python.
module = sys.modules[dotted_path] module = sys.modules[dotted_path]
return CompiledObject(module) return create(evaluator, module)
docstr_defaults = { docstr_defaults = {
@@ -455,19 +460,7 @@ def _parse_function_doc(doc):
return param_str, ret return param_str, ret
class Builtin(CompiledObject): def _create_from_name(evaluator, module, parent, name):
@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):
faked = fake.get_faked(module.obj, parent.obj, name) faked = fake.get_faked(module.obj, parent.obj, name)
# only functions are necessary. # only functions are necessary.
if faked is not None: if faked is not None:
@@ -481,35 +474,39 @@ def _create_from_name(module, parent, name):
# PyQt4.QtGui.QStyleOptionComboBox.currentText # PyQt4.QtGui.QStyleOptionComboBox.currentText
# -> just set it to None # -> just set it to None
obj = None obj = None
return CompiledObject(obj, parent) return create(evaluator, obj, parent)
builtin = Builtin(_builtins) def builtin_from_name(evaluator, string):
# TODO Rename magic_function_class to just function_class or something similar. bltn_obj = getattr(_builtins, string)
magic_function_class = CompiledObject(type(load_module), parent=builtin) return create(evaluator, bltn_obj)
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 keyword_from_value(obj): def _a_generator(foo):
if obj is None: """Used to have an object to return for generators."""
return none_obj yield 42
elif obj is False: yield foo
return false_obj
elif obj is True:
return true_obj _SPECIAL_OBJECTS = {
else: 'FUNCTION_CLASS': type(load_module),
raise NotImplementedError '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 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. # 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) key = id(obj), id(parent), id(module)
try: try:
return evaluator.compiled_cache[key][0] return evaluator.compiled_cache[key][0]
@@ -522,22 +519,22 @@ def compiled_objects_cache(func):
@compiled_objects_cache @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 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.
""" """
if not inspect.ismodule(obj): if not inspect.ismodule(obj):
faked = fake.get_faked(module and module.obj, obj) faked = fake.get_faked(module and module.obj, obj)
if faked is not None: if faked is not None:
faked.parent = parent faked.parent = parent
return faked return faked
try: # TODO delete
if parent == builtin and obj.__module__ in ('builtins', '__builtin__'): #try:
return builtin.get_by_name(obj.__name__) #if parent == builtin and obj.__module__ in ('builtins', '__builtin__'):
except AttributeError: #return builtin.get_by_name(obj.__name__)
pass #except AttributeError:
#pass
return CompiledObject(obj, parent) return CompiledObject(evaluator, obj, parent)

View File

@@ -64,7 +64,10 @@ def get_module(obj):
# Unfortunately in some cases like `int` there's no __module__ # Unfortunately in some cases like `int` there's no __module__
return builtins return builtins
else: else:
return __import__(imp_plz) if imp_plz is None:
return builtins
else:
return __import__(imp_plz)
def _faked(module, obj, name): def _faked(module, obj, name):
@@ -83,17 +86,23 @@ def _faked(module, obj, name):
return search_scope(faked_mod, obj.__name__) return search_scope(faked_mod, obj.__name__)
elif not inspect.isclass(obj): elif not inspect.isclass(obj):
# object is a method or descriptor # object is a method or descriptor
cls = search_scope(faked_mod, obj.__objclass__.__name__) try:
if cls is None: objclass = obj.__objclass__
return except AttributeError:
return search_scope(cls, obj.__name__) return None
else:
cls = search_scope(faked_mod, objclass.__name__)
if cls is None:
return None
return search_scope(cls, obj.__name__)
else: else:
if obj == module: if obj == module:
return search_scope(faked_mod, name) return search_scope(faked_mod, name)
else: else:
cls = search_scope(faked_mod, obj.__name__) cls = search_scope(faked_mod, obj.__name__)
if cls is None: if cls is None:
return return None
return search_scope(cls, name) return search_scope(cls, name)

View File

@@ -212,7 +212,7 @@ class NameFinder(object):
break break
debug.dbg('finder.filter_name "%s" in (%s): %s@%s', self.name_str, 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)) return list(self._clean_names(names))
def _clean_names(self, names): def _clean_names(self, names):
@@ -398,7 +398,7 @@ def _eval_param(evaluator, param, scope):
if not res_new: if not res_new:
if param.stars: if param.stars:
t = 'tuple' if param.stars == 1 else 'dict' 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) res_new = evaluator.execute(typ)
if param.default: if param.default:
res_new |= evaluator.eval_element(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()) scope = evaluator.wrap(scope.get_parent_scope())
# Add builtins to the global 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 yield names_dict, None

View File

@@ -41,7 +41,8 @@ class GeneratorMixin(object):
def names_dicts(self, search_global=False): # is always False def names_dicts(self, search_global=False): # is always False
dct = {} dct = {}
executes_generator = '__next__', 'send', 'next' 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: for name in names:
if name.value in executes_generator: if name.value in executes_generator:
parent = GeneratorMethod(self, name.parent) parent = GeneratorMethod(self, name.parent)
@@ -59,7 +60,8 @@ class GeneratorMixin(object):
return True return True
def py__class__(self, evaluator): 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)): class Generator(use_metaclass(CachedMetaClass, IterableWrapper, GeneratorMixin)):
@@ -185,7 +187,7 @@ class ArrayMixin(object):
@memoize_default() @memoize_default()
def names_dicts(self, search_global=False): # Always False. def names_dicts(self, search_global=False): # Always False.
# `array.type` is a string with the type, e.g. 'list'. # `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] # builtins only have one class -> [0]
scopes = self._evaluator.execute_evaluated(scope, self) scopes = self._evaluator.execute_evaluated(scope, self)
return list(scopes)[0].names_dicts(search_global) 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. return None # We don't know the length, because of appends.
def py__class__(self, evaluator): 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): class ListComprehension(Comprehension, ArrayMixin):
@@ -294,10 +296,10 @@ class Array(IterableWrapper, ArrayMixin):
@safe_property @safe_property
def parent(self): def parent(self):
return compiled.builtin return self._evaluator.BUILTINS
def get_parent_until(self): def get_parent_until(self):
return compiled.builtin return self._evaluator.BUILTINS
def __getattr__(self, name): def __getattr__(self, name):
if name not in ['start_pos', 'get_only_subelement', 'parent', if name not in ['start_pos', 'get_only_subelement', 'parent',

View File

@@ -6,8 +6,7 @@ import operator
from jedi._compatibility import unicode from jedi._compatibility import unicode
from jedi.parser import tree from jedi.parser import tree
from jedi import debug from jedi import debug
from jedi.evaluate.compiled import (CompiledObject, create, builtin, from jedi.evaluate.compiled import CompiledObject, create
keyword_from_value, true_obj, false_obj)
from jedi.evaluate import analysis from jedi.evaluate import analysis
# Maps Python syntax to the operator module. # Maps Python syntax to the operator module.
@@ -31,8 +30,8 @@ def literals_to_types(evaluator, result):
if is_literal(typ): if is_literal(typ):
# Literals are only valid as long as the operations are # Literals are only valid as long as the operations are
# correct. Otherwise add a value-free instance. # correct. Otherwise add a value-free instance.
cls = builtin.get_by_name(typ.name.get_code()) cls = create(evaluator, typ.name.value)
new_result.add(list(evaluator.execute(cls))[0]) new_result |= evaluator.execute(cls)
else: else:
new_result.add(typ) new_result.add(typ)
return new_result return new_result
@@ -97,7 +96,7 @@ def factor_calculate(evaluator, types, operator):
value = typ.py__bool__() value = typ.py__bool__()
if value is None: # Uncertainty. if value is None: # Uncertainty.
return return
yield keyword_from_value(not value) yield create(evaluator, not value)
else: else:
yield typ yield typ
@@ -156,10 +155,12 @@ def _element_calculate(evaluator, left, operator, right):
right = right.obj right = right.obj
try: try:
return set([keyword_from_value(operation(left, right))]) result = operation(left, right)
except TypeError: except TypeError:
# Could be True or False. # 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': elif operator == 'in':
return set() return set()

View File

@@ -9,7 +9,6 @@ count the function calls.
""" """
from jedi import debug from jedi import debug
from jedi import settings from jedi import settings
from jedi.evaluate import compiled
from jedi.evaluate import iterable from jedi.evaluate import iterable
@@ -31,12 +30,13 @@ class RecursionDetector(object):
A decorator to detect recursions in statements. In a recursion a statement 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. 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.top = None
self.current = None self.current = None
self._evaluator = evaluator
def push_stmt(self, stmt): def push_stmt(self, stmt):
self.current = _RecursionNode(stmt, self.current) self.current = _RecursionNode(self._evaluator, stmt, self.current)
check = self._check_recursion() check = self._check_recursion()
if check: if check:
debug.warning('catched stmt recursion: %s against %s @%s', stmt, debug.warning('catched stmt recursion: %s against %s @%s', stmt,
@@ -71,7 +71,8 @@ class RecursionDetector(object):
class _RecursionNode(object): class _RecursionNode(object):
""" A node of the RecursionDecorator. """ """ 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.script = stmt.get_parent_until()
self.position = stmt.start_pos self.position = stmt.start_pos
self.parent = parent self.parent = parent
@@ -80,7 +81,7 @@ class _RecursionNode(object):
# Don't check param instances, they are not causing recursions # Don't check param instances, they are not causing recursions
# The same's true for the builtins, because the builtins are really # The same's true for the builtins, because the builtins are really
# simple. # simple.
self.is_ignored = self.script == compiled.builtin self.is_ignored = self.script == self._evaluator.BUILTINS
def __eq__(self, other): def __eq__(self, other):
if not other: if not other:
@@ -107,13 +108,13 @@ def execution_recursion_decorator(func):
class ExecutionRecursionDetector(object): class ExecutionRecursionDetector(object):
""" """
Catches recursions of executions. 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.recursion_level = 0
self.parent_execution_funcs = [] self.parent_execution_funcs = []
self.execution_funcs = set() self.execution_funcs = set()
self.execution_count = 0 self.execution_count = 0
self._evaluator = evaluator
def __call__(self, execution): def __call__(self, execution):
debug.dbg('Execution recursions: %s', execution, self.recursion_level, debug.dbg('Execution recursions: %s', execution, self.recursion_level,
@@ -125,33 +126,33 @@ class ExecutionRecursionDetector(object):
self.pop_execution() self.pop_execution()
return result return result
def pop_execution(cls): def pop_execution(self):
cls.parent_execution_funcs.pop() self.parent_execution_funcs.pop()
cls.recursion_level -= 1 self.recursion_level -= 1
def push_execution(cls, execution): def push_execution(self, execution):
in_par_execution_funcs = execution.base in cls.parent_execution_funcs in_par_execution_funcs = execution.base in self.parent_execution_funcs
in_execution_funcs = execution.base in cls.execution_funcs in_execution_funcs = execution.base in self.execution_funcs
cls.recursion_level += 1 self.recursion_level += 1
cls.execution_count += 1 self.execution_count += 1
cls.execution_funcs.add(execution.base) self.execution_funcs.add(execution.base)
cls.parent_execution_funcs.append(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 return True
if isinstance(execution.base, (iterable.Array, iterable.Generator)): if isinstance(execution.base, (iterable.Array, iterable.Generator)):
return False return False
module = execution.get_parent_until() module = execution.get_parent_until()
if module == compiled.builtin: if module == self._evaluator.BUILTINS:
return False return False
if in_par_execution_funcs: 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 return True
if in_execution_funcs and \ 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 return True
if cls.execution_count > settings.max_executions_without_builtins: if self.execution_count > settings.max_executions_without_builtins:
return True return True
return False return False

View File

@@ -86,7 +86,7 @@ class Instance(use_metaclass(CachedMetaClass, Executed)):
self.is_generated = is_generated self.is_generated = is_generated
if base.name.get_code() in ['list', 'set'] \ 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. # compare the module path with the builtin name.
self.var_args = iterable.check_array_instances(evaluator, self) self.var_args = iterable.check_array_instances(evaluator, self)
elif not is_generated: elif not is_generated:
@@ -179,7 +179,8 @@ class Instance(use_metaclass(CachedMetaClass, Executed)):
""" Throws a KeyError if there's no method. """ """ Throws a KeyError if there's no method. """
# Arguments in __get__ descriptors are obj, class. # Arguments in __get__ descriptors are obj, class.
# `method` is the new parent of the array, don't know if that's good. # `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: try:
return self.execute_subscope_by_name('__get__', *args) return self.execute_subscope_by_name('__get__', *args)
except KeyError: except KeyError:
@@ -454,7 +455,7 @@ class Class(use_metaclass(CachedMetaClass, Wrapper)):
args = param.Arguments(self._evaluator, arglist) args = param.Arguments(self._evaluator, arglist)
return list(chain.from_iterable(args.eval_args())) return list(chain.from_iterable(args.eval_args()))
else: else:
return [compiled.object_obj] return [compiled.create(evaluator, object)]
def py__call__(self, evaluator, params): def py__call__(self, evaluator, params):
return set([Instance(evaluator, self, params)]) return set([Instance(evaluator, self, params)])
@@ -463,7 +464,7 @@ class Class(use_metaclass(CachedMetaClass, Wrapper)):
return self._evaluator.find_types(self, name) return self._evaluator.find_types(self, name)
def py__class__(self, evaluator): def py__class__(self, evaluator):
return compiled.builtin.get_by_name('type') return compiled.create(evaluator, 'type')
@property @property
def params(self): def params(self):
@@ -569,7 +570,8 @@ class Function(use_metaclass(CachedMetaClass, Wrapper)):
if search_global: if search_global:
yield self.names_dict yield self.names_dict
else: 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 yield names_dict
@Python3Method @Python3Method
@@ -580,7 +582,7 @@ class Function(use_metaclass(CachedMetaClass, Wrapper)):
return FunctionExecution(evaluator, self, params).get_return_types() return FunctionExecution(evaluator, self, params).get_return_types()
def py__class__(self, evaluator): def py__class__(self, evaluator):
return compiled.magic_function_class return compiled.get_special_object(evaluator, 'FUNCTION_CLASS')
def __getattr__(self, name): def __getattr__(self, name):
return getattr(self.base_func, name) return getattr(self.base_func, name)
@@ -920,7 +922,7 @@ class ModuleWrapper(use_metaclass(CachedMetaClass, tree.Module, Wrapper)):
return names return names
def py__class__(self, evaluator): def py__class__(self, evaluator):
return compiled.module_class return compiled.get_special_object(evaluator, 'MODULE_CLASS')
def __getattr__(self, name): def __getattr__(self, name):
return getattr(self._module, name) return getattr(self._module, name)

View File

@@ -32,7 +32,7 @@ def execute(evaluator, obj, arguments):
except AttributeError: except AttributeError:
pass pass
else: else:
if obj.parent == compiled.builtin: if obj.parent == evaluator.BUILTINS:
module_name = 'builtins' module_name = 'builtins'
elif isinstance(obj.parent, tree.Module): elif isinstance(obj.parent, tree.Module):
module_name = str(obj.parent.name) 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 # 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 set([compiled.true_obj, compiled.false_obj]) return set([compiled.create(True), compiled.create(False)])
mro = mro_func(evaluator) mro = mro_func(evaluator)
@@ -191,7 +191,7 @@ def builtins_isinstance(evaluator, objects, types, arguments):
if cls_or_tup.is_class(): if cls_or_tup.is_class():
bool_results.add(cls_or_tup in mro) bool_results.add(cls_or_tup in mro)
elif str(cls_or_tup.name) == 'tuple' \ 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. # Check for tuples.
classes = unite(cls_or_tup.py__iter__()) classes = unite(cls_or_tup.py__iter__())
bool_results.add(any(cls in mro for cls in classes)) 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: for node in nodes:
analysis.add(evaluator, 'type-error-isinstance', node) 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): def collections_namedtuple(evaluator, obj, arguments):