diff --git a/jedi/evaluate/representation.py b/jedi/evaluate/representation.py index f23e46f2..17a68972 100644 --- a/jedi/evaluate/representation.py +++ b/jedi/evaluate/representation.py @@ -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 diff --git a/jedi/evaluate/stdlib.py b/jedi/evaluate/stdlib.py index 4bd6a80e..85f24230 100644 --- a/jedi/evaluate/stdlib.py +++ b/jedi/evaluate/stdlib.py @@ -16,7 +16,7 @@ from jedi._compatibility import unicode from jedi.common import unite from jedi.evaluate import compiled from jedi.evaluate import representation as er -from jedi.evaluate.instance import InstanceFunctionExecution +from jedi.evaluate.instance import InstanceFunctionExecution, AbstractInstanceContext from jedi.evaluate import iterable from jedi.parser import ParserWithRecovery from jedi import debug @@ -127,7 +127,7 @@ def builtins_type(evaluator, objects, bases, dicts): return set([o.py__class__() for o in objects]) -class SuperInstance(er.Instance): +class SuperInstance(AbstractInstanceContext): """To be used like the object ``super`` returns.""" def __init__(self, evaluator, cls): su = cls.py_mro()[1]