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

@@ -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)

View File

@@ -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)