forked from VimPlug/jedi
Refactor compiled.CompiledObject so it always owns an evaluator instance.
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -64,7 +64,10 @@ def get_module(obj):
|
||||
# Unfortunately in some cases like `int` there's no __module__
|
||||
return builtins
|
||||
else:
|
||||
return __import__(imp_plz)
|
||||
if imp_plz is None:
|
||||
return builtins
|
||||
else:
|
||||
return __import__(imp_plz)
|
||||
|
||||
|
||||
def _faked(module, obj, name):
|
||||
@@ -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__)
|
||||
if cls is None:
|
||||
return
|
||||
return search_scope(cls, obj.__name__)
|
||||
try:
|
||||
objclass = obj.__objclass__
|
||||
except AttributeError:
|
||||
return None
|
||||
else:
|
||||
cls = search_scope(faked_mod, objclass.__name__)
|
||||
if cls is None:
|
||||
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)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user