forked from VimPlug/jedi
Some class fixes.
This commit is contained in:
@@ -111,19 +111,16 @@ class Evaluator(object):
|
||||
self.execution_recursion_detector = recursion.ExecutionRecursionDetector(self)
|
||||
|
||||
def wrap(self, element, parent_context):
|
||||
if isinstance(element, Context) or element is None:
|
||||
# TODO this is so ugly, please refactor.
|
||||
return element
|
||||
|
||||
if element.type == 'classdef':
|
||||
return er.ClassContext(self, element, parent_context)
|
||||
elif element.type == 'funcdef':
|
||||
return er.FunctionContext(self, parent_context, element)
|
||||
return er.AnonymousFunctionExecution(self, parent_context, element)
|
||||
elif element.type == 'lambda':
|
||||
return er.LambdaWrapper(self, element)
|
||||
elif element.type == 'file_input':
|
||||
return er.ModuleContext(self, element)
|
||||
else:
|
||||
raise DeprecationWarning
|
||||
return element
|
||||
|
||||
def find_types(self, context, name_str, position=None, search_global=False,
|
||||
@@ -317,6 +314,7 @@ class Evaluator(object):
|
||||
elif element.type == 'dotted_name':
|
||||
types = self._eval_atom(context, element.children[0])
|
||||
for next_name in element.children[2::2]:
|
||||
# TODO add search_global=True?
|
||||
types = set(chain.from_iterable(self.find_types(typ, next_name)
|
||||
for typ in types))
|
||||
types = types
|
||||
|
||||
@@ -9,7 +9,7 @@ from jedi.evaluate import flow_analysis
|
||||
from jedi.common import to_list, unite
|
||||
|
||||
|
||||
class AbstractNameDefinition():
|
||||
class AbstractNameDefinition(object):
|
||||
start_pos = None
|
||||
string_name = None
|
||||
parent_context = None
|
||||
@@ -96,6 +96,8 @@ class AbstractFilter(object):
|
||||
|
||||
|
||||
class AbstractUsedNamesFilter(AbstractFilter):
|
||||
name_class = TreeNameDefinition
|
||||
|
||||
def __init__(self, context, parser_scope, origin_scope=None):
|
||||
super(AbstractUsedNamesFilter, self).__init__(origin_scope)
|
||||
self._parser_scope = parser_scope
|
||||
@@ -111,7 +113,7 @@ class AbstractUsedNamesFilter(AbstractFilter):
|
||||
return self._convert_names(self._filter(names))
|
||||
|
||||
def _convert_names(self, names):
|
||||
return [TreeNameDefinition(self._context, name) for name in names]
|
||||
return [self.name_class(self._context, name) for name in names]
|
||||
|
||||
def values(self):
|
||||
return self._convert_names(name for name_list in self._used_names.values()
|
||||
|
||||
@@ -210,8 +210,8 @@ class NameFinder(object):
|
||||
# deliver types.
|
||||
self._found_predefined_if_name = types
|
||||
else:
|
||||
check = flow_analysis.reachability_check(self._context, self.context,
|
||||
origin_scope)
|
||||
check = flow_analysis.reachability_check(
|
||||
self._context, self.context, origin_scope)
|
||||
if check is flow_analysis.UNREACHABLE:
|
||||
self._found_predefined_if_name = set()
|
||||
else:
|
||||
@@ -341,6 +341,7 @@ class NameFinder(object):
|
||||
|
||||
|
||||
def _get_global_stmt_scopes(evaluator, global_stmt, name):
|
||||
raise DeprecationWarning
|
||||
global_stmt_scope = global_stmt.get_parent_scope()
|
||||
module = global_stmt_scope.get_parent_until()
|
||||
for used_name in module.used_names[str(name)]:
|
||||
@@ -400,7 +401,18 @@ def _apply_decorators(evaluator, context, node):
|
||||
Returns the function, that should to be executed in the end.
|
||||
This is also the places where the decorators are processed.
|
||||
"""
|
||||
decoratee_context = evaluator.wrap(node, parent_context=context)
|
||||
if node.type == 'classdef':
|
||||
decoratee_context = er.ClassContext(
|
||||
evaluator,
|
||||
parent_context=context,
|
||||
classdef=node
|
||||
)
|
||||
else:
|
||||
decoratee_context = er.FunctionContext(
|
||||
evaluator,
|
||||
parent_context=context,
|
||||
funcdef=node
|
||||
)
|
||||
initial = values = set([decoratee_context])
|
||||
for dec in reversed(node.get_decorators()):
|
||||
debug.dbg('decorator: %s %s', dec, values)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from abc import abstractproperty
|
||||
|
||||
from jedi.common import unite
|
||||
from jedi.common import unite, to_list
|
||||
from jedi import debug
|
||||
from jedi.evaluate import compiled
|
||||
from jedi.evaluate.filters import ParserTreeFilter, ContextName
|
||||
from jedi.evaluate.filters import ParserTreeFilter, ContextName, TreeNameDefinition
|
||||
from jedi.evaluate.context import Context
|
||||
|
||||
|
||||
@@ -91,13 +91,13 @@ class AbstractInstanceContext(Context):
|
||||
if isinstance(cls, compiled.CompiledObject):
|
||||
yield SelfNameFilter(self._evaluator, self, cls, origin_scope)
|
||||
else:
|
||||
yield SelfNameFilter(self._evaluator, self, cls.base, origin_scope)
|
||||
yield SelfNameFilter(self._evaluator, self, cls.classdef, 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)
|
||||
yield InstanceClassFilter(self._evaluator, self, cls.classdef, origin_scope)
|
||||
|
||||
def py__getitem__(self, index):
|
||||
try:
|
||||
@@ -165,7 +165,31 @@ class CompiledInstanceClassFilter(compiled.CompiledObjectFilter):
|
||||
for name in names]
|
||||
|
||||
|
||||
class BoundMethod(object):
|
||||
def __init__(self, function):
|
||||
self._function = function
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(self._function, name)
|
||||
|
||||
|
||||
class InstanceNameDefinition(TreeNameDefinition):
|
||||
@to_list
|
||||
def infer(self):
|
||||
contexts = super(InstanceNameDefinition, self).infer()
|
||||
from jedi.evaluate.representation import FunctionContext
|
||||
for context in contexts:
|
||||
"""
|
||||
if isinstance(contexts, FunctionContext):
|
||||
# TODO what about compiled objects?
|
||||
yield BoundMethod(context)
|
||||
else:
|
||||
"""
|
||||
yield context
|
||||
|
||||
class InstanceClassFilter(ParserTreeFilter):
|
||||
name_class = InstanceNameDefinition
|
||||
|
||||
def __init__(self, evaluator, context, parser_scope, origin_scope):
|
||||
super(InstanceClassFilter, self).__init__(
|
||||
evaluator=evaluator,
|
||||
|
||||
@@ -417,9 +417,9 @@ class ClassContext(use_metaclass(CachedMetaClass, context.TreeContext, Wrapper))
|
||||
This class is not only important to extend `tree.Class`, it is also a
|
||||
important for descriptors (if the descriptor methods are evaluated or not).
|
||||
"""
|
||||
def __init__(self, evaluator, base, parent_context):
|
||||
def __init__(self, evaluator, classdef, parent_context):
|
||||
super(ClassContext, self).__init__(evaluator, parent_context=parent_context)
|
||||
self.base = base
|
||||
self.classdef = classdef
|
||||
|
||||
@memoize_default(default=())
|
||||
def py__mro__(self):
|
||||
@@ -430,38 +430,41 @@ class ClassContext(use_metaclass(CachedMetaClass, context.TreeContext, Wrapper))
|
||||
mro = [self]
|
||||
# TODO Do a proper mro resolution. Currently we are just listing
|
||||
# classes. However, it's a complicated algorithm.
|
||||
for cls in self.py__bases__():
|
||||
# TODO detect for TypeError: duplicate base class str,
|
||||
# e.g. `class X(str, str): pass`
|
||||
try:
|
||||
mro_method = cls.py__mro__
|
||||
except AttributeError:
|
||||
# TODO add a TypeError like:
|
||||
"""
|
||||
>>> class Y(lambda: test): pass
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
TypeError: function() argument 1 must be code, not str
|
||||
>>> class Y(1): pass
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
TypeError: int() takes at most 2 arguments (3 given)
|
||||
"""
|
||||
pass
|
||||
else:
|
||||
add(cls)
|
||||
for cls_new in mro_method():
|
||||
add(cls_new)
|
||||
for lazy_cls in self.py__bases__():
|
||||
# TODO there's multiple different mro paths possible if this yields
|
||||
# multiple possibilities. Could be changed to be more correct.
|
||||
for cls in lazy_cls.infer():
|
||||
# TODO detect for TypeError: duplicate base class str,
|
||||
# e.g. `class X(str, str): pass`
|
||||
try:
|
||||
mro_method = cls.py__mro__
|
||||
except AttributeError:
|
||||
# TODO add a TypeError like:
|
||||
"""
|
||||
>>> class Y(lambda: test): pass
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
TypeError: function() argument 1 must be code, not str
|
||||
>>> class Y(1): pass
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
TypeError: int() takes at most 2 arguments (3 given)
|
||||
"""
|
||||
pass
|
||||
else:
|
||||
add(cls)
|
||||
for cls_new in mro_method():
|
||||
add(cls_new)
|
||||
return tuple(mro)
|
||||
|
||||
@memoize_default(default=())
|
||||
def py__bases__(self):
|
||||
arglist = self.base.get_super_arglist()
|
||||
arglist = self.classdef.get_super_arglist()
|
||||
if arglist:
|
||||
args = param.Arguments(self._evaluator, self, arglist)
|
||||
return list(chain.from_iterable(args.eval_args()))
|
||||
args = param.TreeArguments(self._evaluator, self, arglist)
|
||||
return [value for key, value in args.unpack() if key is None]
|
||||
else:
|
||||
return [compiled.create(self._evaluator, object)]
|
||||
return [context.LazyKnownContext(compiled.create(self._evaluator, object))]
|
||||
|
||||
def py__call__(self, params):
|
||||
return set([TreeInstance(self._evaluator, self.parent_context, self, params)])
|
||||
@@ -488,44 +491,38 @@ class ClassContext(use_metaclass(CachedMetaClass, context.TreeContext, Wrapper))
|
||||
|
||||
def get_filters(self, search_global, until_position=None, origin_scope=None, is_instance=False):
|
||||
if search_global:
|
||||
yield ParserTreeFilter(self._evaluator, self, self.base, until_position, origin_scope=origin_scope)
|
||||
yield ParserTreeFilter(self._evaluator, self, self.classdef, until_position, origin_scope=origin_scope)
|
||||
else:
|
||||
for scope in self.py__mro__():
|
||||
if isinstance(scope, compiled.CompiledObject):
|
||||
for filter in scope.get_filters(is_instance=is_instance):
|
||||
yield filter
|
||||
else:
|
||||
yield ParserTreeFilter(self._evaluator, self, scope.base, origin_scope=origin_scope)
|
||||
yield ParserTreeFilter(self._evaluator, self, scope.classdef, origin_scope=origin_scope)
|
||||
|
||||
def is_class(self):
|
||||
return True
|
||||
|
||||
def get_subscope_by_name(self, name):
|
||||
raise DeprecationWarning
|
||||
for s in self.py__mro__():
|
||||
for sub in reversed(s.subscopes):
|
||||
if sub.name.value == name:
|
||||
return sub
|
||||
raise KeyError("Couldn't find subscope.")
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name not in ['start_pos', 'end_pos', 'parent', 'raw_doc',
|
||||
'doc', 'get_imports', 'get_parent_until', 'get_code',
|
||||
'subscopes', 'names_dict', 'type']:
|
||||
return super(ClassContext, self).__getattribute__(name)
|
||||
return getattr(self.base, name)
|
||||
|
||||
def __repr__(self):
|
||||
return "<e%s of %s>" % (type(self).__name__, self.base)
|
||||
return "<e%s of %s>" % (type(self).__name__, self.classdef)
|
||||
|
||||
|
||||
class FunctionContext(use_metaclass(CachedMetaClass, context.TreeContext, Wrapper)):
|
||||
"""
|
||||
Needed because of decorators. Decorators are evaluated here.
|
||||
"""
|
||||
def __init__(self, evaluator, parent_context, func):
|
||||
def __init__(self, evaluator, parent_context, funcdef):
|
||||
""" This should not be called directly """
|
||||
super(FunctionContext, self).__init__(evaluator, parent_context)
|
||||
self.base = self.base_func = func
|
||||
self.base = self.base_func = funcdef
|
||||
|
||||
def names_dicts(self, search_global):
|
||||
if search_global:
|
||||
@@ -713,6 +710,16 @@ class FunctionExecutionContext(Executed):
|
||||
return "<%s of %s>" % (type(self).__name__, self.funcdef)
|
||||
|
||||
|
||||
class AnonymousFunctionExecution(FunctionExecutionContext):
|
||||
def __init__(self, evaluator, parent_context, funcdef):
|
||||
super(AnonymousFunctionExecution, self).__init__(
|
||||
evaluator, parent_context, funcdef, var_args=None)
|
||||
|
||||
@memoize_default(default=NO_DEFAULT)
|
||||
def get_params(self):
|
||||
return []
|
||||
|
||||
|
||||
class GlobalName(helpers.FakeName):
|
||||
def __init__(self, name):
|
||||
"""
|
||||
|
||||
@@ -153,7 +153,7 @@ def builtins_super(evaluator, types, objects, scope):
|
||||
cls = cls.base
|
||||
su = cls.py__bases__()
|
||||
if su:
|
||||
return evaluator.execute(su[0])
|
||||
return su[0].infer()
|
||||
return set()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user