forked from VimPlug/jedi
Remove the old instance.
This commit is contained in:
@@ -73,324 +73,6 @@ class Executed(context.TreeContext):
|
||||
return True
|
||||
|
||||
|
||||
class Instance(use_metaclass(CachedMetaClass, Executed)):
|
||||
"""
|
||||
This class is used to evaluate instances.
|
||||
"""
|
||||
def __init__(self, evaluator, parent_context, class_context, var_args, is_generated=False):
|
||||
raise DeprecationWarning
|
||||
super(Instance, self).__init__(evaluator, parent_context, var_args)
|
||||
# Generated instances are classes that are just generated by self
|
||||
# (No var_args) used.
|
||||
self.is_generated = is_generated
|
||||
self._class_context = class_context
|
||||
|
||||
self._init_execution = None
|
||||
if class_context.name.string_name in ['list', 'set'] \
|
||||
and evaluator.BUILTINS == parent_context.get_root_context():
|
||||
# compare the module path with the builtin name.
|
||||
self.var_args = iterable.check_array_instances(evaluator, self)
|
||||
elif not is_generated:
|
||||
# Need to execute the __init__ function, because the dynamic param
|
||||
# searching needs it.
|
||||
try:
|
||||
method = self.get_subscope_by_name('__init__')
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
self._init_execution = evaluator.execute(method, self.var_args)
|
||||
|
||||
def is_class(self):
|
||||
return False
|
||||
|
||||
@property
|
||||
def py__call__(self):
|
||||
def actual(params):
|
||||
return self.evaluator.execute(method, params)
|
||||
|
||||
try:
|
||||
method = self.get_subscope_by_name('__call__')
|
||||
except KeyError:
|
||||
# Means the Instance is not callable.
|
||||
raise AttributeError
|
||||
|
||||
return actual
|
||||
|
||||
def py__class__(self):
|
||||
return self.class_context
|
||||
|
||||
def py__bool__(self):
|
||||
# Signalize that we don't know about the bool type.
|
||||
return None
|
||||
|
||||
@memoize_default()
|
||||
def _get_init_execution(self):
|
||||
try:
|
||||
func = self.get_subscope_by_name('__init__')
|
||||
except KeyError:
|
||||
return None
|
||||
return FunctionExecutionContext(self.evaluator, self, func, self.var_args)
|
||||
|
||||
def _get_func_self_name(self, func):
|
||||
"""
|
||||
Returns the name of the first param in a class method (which is
|
||||
normally self.
|
||||
"""
|
||||
try:
|
||||
return str(func.params[0].name)
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
def _self_names_dict(self, add_mro=True):
|
||||
names = {}
|
||||
# This loop adds the names of the self object, copies them and removes
|
||||
# the self.
|
||||
for sub in self.base.subscopes:
|
||||
if isinstance(sub, tree.ClassContext):
|
||||
continue
|
||||
# Get the self name, if there's one.
|
||||
self_name = self._get_func_self_name(sub)
|
||||
if self_name is None:
|
||||
continue
|
||||
|
||||
if sub.name.value == '__init__' and not self.is_generated:
|
||||
# ``__init__`` is special because the params need are injected
|
||||
# this way. Therefore an execution is necessary.
|
||||
if not sub.get_decorators():
|
||||
# __init__ decorators should generally just be ignored,
|
||||
# because to follow them and their self variables is too
|
||||
# complicated.
|
||||
sub = self._get_init_execution()
|
||||
for name_list in sub.names_dict.values():
|
||||
for name in name_list:
|
||||
if name.value == self_name and name.get_previous_sibling() is None:
|
||||
trailer = name.get_next_sibling()
|
||||
if tree.is_node(trailer, 'trailer') \
|
||||
and len(trailer.children) == 2 \
|
||||
and trailer.children[0] == '.':
|
||||
name = trailer.children[1] # After dot.
|
||||
if name.is_definition():
|
||||
arr = names.setdefault(name.value, [])
|
||||
arr.append(get_instance_el(self.evaluator, self, name))
|
||||
return names
|
||||
|
||||
def get_subscope_by_name(self, name):
|
||||
sub = self._class_context.get_subscope_by_name(name)
|
||||
return get_instance_el(self.evaluator, self, sub, True)
|
||||
|
||||
def execute_subscope_by_name(self, name, *args):
|
||||
method = self.get_subscope_by_name(name)
|
||||
return self.evaluator.execute_evaluated(method, *args)
|
||||
|
||||
def get_descriptor_returns(self, obj):
|
||||
""" 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.
|
||||
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:
|
||||
return set([self])
|
||||
|
||||
@memoize_default()
|
||||
def names_dicts(self, search_global):
|
||||
yield self._self_names_dict()
|
||||
|
||||
for s in self._class_context.py__mro__()[1:]:
|
||||
if not isinstance(s, compiled.CompiledObject):
|
||||
# Compiled objects don't have `self.` names.
|
||||
for inst in self.evaluator.execute(s):
|
||||
yield inst._self_names_dict(add_mro=False)
|
||||
|
||||
for names_dict in self.base.names_dicts(search_global=False, is_instance=True):
|
||||
yield LazyInstanceDict(self.evaluator, self, names_dict)
|
||||
|
||||
def get_filters(self, search_global, until_position=None, origin_scope=None):
|
||||
for cls in self._class_context.py__mro__():
|
||||
if isinstance(cls, compiled.CompiledObject):
|
||||
yield SelfNameFilter(self.evaluator, self, cls, origin_scope)
|
||||
else:
|
||||
yield SelfNameFilter(self.evaluator, self, cls.base, origin_scope)
|
||||
|
||||
for cls in self._class_context.py__mro__():
|
||||
if isinstance(cls, compiled.CompiledObject):
|
||||
yield CompiledInstanceClassFilter(self.evaluator, self, cls)
|
||||
else:
|
||||
yield InstanceClassFilter(self.evaluator, self, cls.base, origin_scope)
|
||||
|
||||
def py__getitem__(self, index):
|
||||
try:
|
||||
method = self.get_subscope_by_name('__getitem__')
|
||||
except KeyError:
|
||||
debug.warning('No __getitem__, cannot access the array.')
|
||||
return set()
|
||||
else:
|
||||
index_obj = compiled.create(self.evaluator, index)
|
||||
return self.evaluator.execute_evaluated(method, index_obj)
|
||||
|
||||
def py__iter__(self):
|
||||
try:
|
||||
method = self.get_subscope_by_name('__iter__')
|
||||
except KeyError:
|
||||
debug.warning('No __iter__ on %s.' % self)
|
||||
return
|
||||
else:
|
||||
iters = self.evaluator.execute(method)
|
||||
for generator in iters:
|
||||
if isinstance(generator, Instance):
|
||||
# `__next__` logic.
|
||||
name = '__next__' if is_py3 else 'next'
|
||||
try:
|
||||
yield generator.execute_subscope_by_name(name)
|
||||
except KeyError:
|
||||
debug.warning('Instance has no __next__ function in %s.', generator)
|
||||
else:
|
||||
for typ in generator.py__iter__():
|
||||
yield typ
|
||||
|
||||
@property
|
||||
@underscore_memoization
|
||||
def name(self):
|
||||
return ContextName(self, self._class_context.name.string_name)
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s of %s(%s)>" % (self.__class__.__name__, self._class_context,
|
||||
self.var_args)
|
||||
|
||||
|
||||
class LazyInstanceDict(object):
|
||||
def __init__(self, evaluator, instance, dct):
|
||||
self._evaluator = evaluator
|
||||
self._instance = instance
|
||||
self._dct = dct
|
||||
|
||||
def __getitem__(self, name):
|
||||
return [get_instance_el(self._evaluator, self._instance, var, True)
|
||||
for var in self._dct[name]]
|
||||
|
||||
def values(self):
|
||||
return [self[key] for key in self._dct]
|
||||
|
||||
|
||||
class InstanceName(tree.Name):
|
||||
def __init__(self, origin_name, parent):
|
||||
super(InstanceName, self).__init__(origin_name.value,
|
||||
origin_name.start_pos)
|
||||
self._origin_name = origin_name
|
||||
self.parent = parent
|
||||
|
||||
def is_definition(self):
|
||||
return self._origin_name.is_definition()
|
||||
|
||||
|
||||
def get_instance_el(evaluator, instance, var, is_class_var=False):
|
||||
"""
|
||||
Returns an InstanceElement if it makes sense, otherwise leaves the object
|
||||
untouched.
|
||||
|
||||
Basically having an InstanceElement is context information. That is needed
|
||||
in quite a lot of cases, which includes Nodes like ``power``, that need to
|
||||
know where a self name comes from for example.
|
||||
"""
|
||||
return var
|
||||
if isinstance(var, tree.Name):
|
||||
parent = get_instance_el(evaluator, instance, var.parent, is_class_var)
|
||||
return InstanceName(var, parent)
|
||||
elif var.type != 'funcdef' \
|
||||
and isinstance(var, (Instance, compiled.CompiledObject, tree.Leaf,
|
||||
tree.Module, FunctionExecutionContext)):
|
||||
return var
|
||||
|
||||
var = evaluator.wrap(var)
|
||||
return InstanceElement(evaluator, instance, var, is_class_var)
|
||||
|
||||
|
||||
class InstanceElement(use_metaclass(CachedMetaClass, tree.Base)):
|
||||
"""
|
||||
InstanceElement is a wrapper for any object, that is used as an instance
|
||||
variable (e.g. self.variable or class methods).
|
||||
"""
|
||||
def __init__(self, evaluator, instance, var, is_class_var):
|
||||
self.evaluator = evaluator
|
||||
self.instance = instance
|
||||
self.var = var
|
||||
self.is_class_var = is_class_var
|
||||
|
||||
@common.safe_property
|
||||
@memoize_default()
|
||||
def parent(self):
|
||||
par = self.var.parent
|
||||
if isinstance(par, ClassContext) and par == self.instance.base \
|
||||
or not isinstance(self.instance.base, (tree.Class, ClassContext)) \
|
||||
or isinstance(par, tree.Class) \
|
||||
and par == self.instance.base.base:
|
||||
par = self.instance
|
||||
else:
|
||||
par = get_instance_el(self.evaluator, self.instance, par,
|
||||
self.is_class_var)
|
||||
return par
|
||||
|
||||
def get_parent_until(self, *args, **kwargs):
|
||||
return tree.BaseNode.get_parent_until(self, *args, **kwargs)
|
||||
|
||||
def get_definition(self):
|
||||
return self.get_parent_until((tree.ExprStmt, tree.IsScope, tree.Import))
|
||||
|
||||
def get_decorated_func(self):
|
||||
""" Needed because the InstanceElement should not be stripped """
|
||||
func = self.var.get_decorated_func()
|
||||
func = get_instance_el(self.evaluator, self.instance, func)
|
||||
return func
|
||||
|
||||
def get_rhs(self):
|
||||
return get_instance_el(self.evaluator, self.instance,
|
||||
self.var.get_rhs(), self.is_class_var)
|
||||
|
||||
def is_definition(self):
|
||||
return self.var.is_definition()
|
||||
|
||||
@property
|
||||
def children(self):
|
||||
# Copy and modify the array.
|
||||
return [get_instance_el(self.evaluator, self.instance, command, self.is_class_var)
|
||||
for command in self.var.children]
|
||||
|
||||
@property
|
||||
@memoize_default()
|
||||
def name(self):
|
||||
return ContextName(self.var.name, self)
|
||||
|
||||
def __iter__(self):
|
||||
for el in self.var.__iter__():
|
||||
yield get_instance_el(self.evaluator, self.instance, el,
|
||||
self.is_class_var)
|
||||
|
||||
def __getitem__(self, index):
|
||||
return get_instance_el(self.evaluator, self.instance, self.var[index],
|
||||
self.is_class_var)
|
||||
|
||||
def isinstance(self, *cls):
|
||||
return isinstance(self.var, cls)
|
||||
|
||||
def is_scope(self):
|
||||
"""
|
||||
Since we inherit from Base, it would overwrite the action we want here.
|
||||
"""
|
||||
return self.var.is_scope()
|
||||
|
||||
def py__call__(self, params):
|
||||
if isinstance(self.var, compiled.CompiledObject):
|
||||
# This check is a bit strange, but CompiledObject itself is a bit
|
||||
# more complicated than we would it actually like to be.
|
||||
return self.var.py__call__(params)
|
||||
else:
|
||||
return FunctionContext.py__call__(self, params)
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s of %s>" % (self.__class__.__name__, self.var)
|
||||
|
||||
|
||||
class Wrapper(tree.Base):
|
||||
def is_scope(self):
|
||||
return True
|
||||
|
||||
Reference in New Issue
Block a user