forked from VimPlug/jedi
Fixing getattr tests.
This commit is contained in:
@@ -78,7 +78,7 @@ from jedi.evaluate import precedence
|
||||
from jedi.evaluate import param
|
||||
from jedi.evaluate import helpers
|
||||
from jedi.evaluate.context import Context
|
||||
from jedi.evaluate.instance import AnonymousInstance
|
||||
from jedi.evaluate.instance import AnonymousInstance, AnonymousInstanceFunctionExecution
|
||||
|
||||
|
||||
class Evaluator(object):
|
||||
@@ -527,6 +527,13 @@ class Evaluator(object):
|
||||
if scope_node == module_context.module_node:
|
||||
return module_context
|
||||
elif is_funcdef:
|
||||
if isinstance(parent_context, AnonymousInstance):
|
||||
return AnonymousInstanceFunctionExecution(
|
||||
parent_context,
|
||||
parent_context.parent_context,
|
||||
scope_node
|
||||
)
|
||||
else:
|
||||
return er.AnonymousFunctionExecution(self, parent_context, scope_node)
|
||||
elif scope_node.type == 'classdef':
|
||||
class_context = er.ClassContext(self, scope_node, parent_context)
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
from jedi.common import unite
|
||||
|
||||
|
||||
class Context(object):
|
||||
type = None # TODO remove
|
||||
|
||||
|
||||
@@ -98,9 +98,9 @@ def _search_function_executions(evaluator, funcdef):
|
||||
"""
|
||||
from jedi.evaluate import representation as er
|
||||
|
||||
def get_possible_nodes(module, func_name):
|
||||
def get_possible_nodes(module_node, func_name):
|
||||
try:
|
||||
names = module.used_names[func_name]
|
||||
names = module_node.used_names[func_name]
|
||||
except KeyError:
|
||||
return
|
||||
|
||||
@@ -110,7 +110,7 @@ def _search_function_executions(evaluator, funcdef):
|
||||
if trailer.type == 'trailer' and bracket == '(':
|
||||
yield name, trailer
|
||||
|
||||
current_module = funcdef.get_parent_until()
|
||||
current_module_node = funcdef.get_parent_until()
|
||||
func_name = unicode(funcdef.name)
|
||||
compare_node = funcdef
|
||||
if func_name == '__init__':
|
||||
@@ -122,9 +122,10 @@ def _search_function_executions(evaluator, funcdef):
|
||||
|
||||
found_executions = False
|
||||
i = 0
|
||||
for mod in imports.get_modules_containing_name(evaluator, [current_module], func_name):
|
||||
module_context = er.ModuleContext(evaluator, mod)
|
||||
for name, trailer in get_possible_nodes(mod, func_name):
|
||||
for module_node in imports.get_module_nodes_containing_name(
|
||||
evaluator, [current_module_node], func_name):
|
||||
module_context = er.ModuleContext(evaluator, module_node)
|
||||
for name, trailer in get_possible_nodes(module_node, func_name):
|
||||
i += 1
|
||||
|
||||
# This is a simple way to stop Jedi's dynamic param recursion
|
||||
@@ -134,16 +135,16 @@ def _search_function_executions(evaluator, funcdef):
|
||||
return
|
||||
|
||||
random_context = evaluator.create_context(module_context, name)
|
||||
for context in evaluator.goto_definitions(random_context, name):
|
||||
if compare_node == context.funcdef:
|
||||
for value in evaluator.goto_definitions(random_context, name):
|
||||
if compare_node == value.funcdef:
|
||||
arglist = trailer.children[1]
|
||||
if arglist == ')':
|
||||
arglist = ()
|
||||
args = TreeArguments(evaluator, random_context, arglist, trailer)
|
||||
yield er.FunctionExecutionContext(
|
||||
evaluator,
|
||||
context.parent_context,
|
||||
context.funcdef,
|
||||
value.parent_context,
|
||||
value.funcdef,
|
||||
args
|
||||
)
|
||||
found_executions = True
|
||||
|
||||
@@ -75,6 +75,16 @@ class ParamName(ContextName):
|
||||
return params[self.tree_name.parent.position_nr]
|
||||
|
||||
|
||||
class AnonymousInstanceParamName(ParamName):
|
||||
def infer(self):
|
||||
if self.tree_name.parent.position_nr == 0:
|
||||
# This is a speed optimization, to return the self param (because
|
||||
# it's known). This only affects anonymous instances.
|
||||
return set([self.parent_context])
|
||||
else:
|
||||
return self._get_param().infer()
|
||||
|
||||
|
||||
class AbstractFilter(object):
|
||||
_until_position = None
|
||||
|
||||
@@ -145,6 +155,8 @@ class ParserTreeFilter(AbstractUsedNamesFilter):
|
||||
|
||||
|
||||
class FunctionExecutionFilter(ParserTreeFilter):
|
||||
param_name = ParamName
|
||||
|
||||
def __init__(self, evaluator, context, parser_scope,
|
||||
until_position=None, origin_scope=None):
|
||||
super(FunctionExecutionFilter, self).__init__(
|
||||
@@ -160,11 +172,15 @@ class FunctionExecutionFilter(ParserTreeFilter):
|
||||
for name in names:
|
||||
param = search_ancestor(name, 'param')
|
||||
if param:
|
||||
yield ParamName(self._context, name)
|
||||
yield self.param_name(self._context, name)
|
||||
else:
|
||||
yield TreeNameDefinition(self._context, name)
|
||||
|
||||
|
||||
class AnonymousInstanceFunctionExecutionFilter(FunctionExecutionFilter):
|
||||
param_name = AnonymousInstanceParamName
|
||||
|
||||
|
||||
class GlobalNameFilter(AbstractUsedNamesFilter):
|
||||
def __init__(self, context, parser_scope, origin_scope=None):
|
||||
super(GlobalNameFilter, self).__init__(context, parser_scope)
|
||||
|
||||
@@ -448,16 +448,15 @@ def _load_module(evaluator, path=None, source=None, sys_path=None, parent_module
|
||||
p = path
|
||||
p = fast.FastParser(evaluator.grammar, common.source_to_unicode(source), p)
|
||||
save_parser(path, p)
|
||||
from jedi.evaluate.representation import ModuleWrapper
|
||||
return ModuleWrapper(evaluator, p.module, parent_module)
|
||||
return p.module
|
||||
|
||||
if sys_path is None:
|
||||
sys_path = evaluator.sys_path
|
||||
|
||||
cached = load_parser(path)
|
||||
module = load(source) if cached is None else cached.module
|
||||
module = evaluator.wrap(module)
|
||||
return module
|
||||
from jedi.evaluate.representation import ModuleContext
|
||||
return ModuleContext(evaluator, module)
|
||||
|
||||
|
||||
def add_module(evaluator, module_name, module):
|
||||
@@ -469,7 +468,7 @@ def add_module(evaluator, module_name, module):
|
||||
evaluator.modules[module_name] = module
|
||||
|
||||
|
||||
def get_modules_containing_name(evaluator, mods, name):
|
||||
def get_module_nodes_containing_name(evaluator, module_nodes, name):
|
||||
"""
|
||||
Search a name in the directories of modules.
|
||||
"""
|
||||
@@ -492,9 +491,9 @@ def get_modules_containing_name(evaluator, mods, name):
|
||||
return module
|
||||
|
||||
# skip non python modules
|
||||
mods = set(m for m in mods if not isinstance(m, compiled.CompiledObject))
|
||||
module_nodes = set(m for m in module_nodes if not isinstance(m, compiled.CompiledObject))
|
||||
mod_paths = set()
|
||||
for m in mods:
|
||||
for m in module_nodes:
|
||||
mod_paths.add(m.path)
|
||||
yield m
|
||||
|
||||
@@ -513,5 +512,5 @@ def get_modules_containing_name(evaluator, mods, name):
|
||||
for p in sorted(paths):
|
||||
# make testing easier, sort it - same results on every interpreter
|
||||
c = check_python_file(p)
|
||||
if c is not None and c not in mods and not isinstance(c, compiled.CompiledObject):
|
||||
yield c
|
||||
if c is not None and c not in module_nodes and not isinstance(c, compiled.CompiledObject):
|
||||
yield c.module_node
|
||||
|
||||
@@ -3,7 +3,7 @@ from abc import abstractproperty
|
||||
from jedi.common import unite
|
||||
from jedi import debug
|
||||
from jedi.evaluate import compiled
|
||||
from jedi.evaluate.filters import ParserTreeFilter, ContextName, TreeNameDefinition
|
||||
from jedi.evaluate import filters
|
||||
from jedi.evaluate.context import Context, LazyKnownContext
|
||||
from jedi.evaluate.cache import memoize_default
|
||||
from jedi.cache import memoize_method
|
||||
@@ -155,7 +155,7 @@ class CompiledInstance(AbstractInstanceContext):
|
||||
class TreeInstance(AbstractInstanceContext):
|
||||
@property
|
||||
def name(self):
|
||||
return ContextName(self, self.class_context.name.tree_name)
|
||||
return filters.ContextName(self, self.class_context.name.tree_name)
|
||||
|
||||
@memoize_default()
|
||||
def create_instance_context(self, class_context, node):
|
||||
@@ -230,14 +230,14 @@ class BoundMethod(object):
|
||||
return '<%s: %s>' % (self.__class__.__name__, self._function)
|
||||
|
||||
|
||||
class InstanceNameDefinition(TreeNameDefinition):
|
||||
class InstanceNameDefinition(filters.TreeNameDefinition):
|
||||
def infer(self):
|
||||
contexts = super(InstanceNameDefinition, self).infer()
|
||||
for context in contexts:
|
||||
yield context
|
||||
|
||||
|
||||
class InstanceClassFilter(ParserTreeFilter):
|
||||
class InstanceClassFilter(filters.ParserTreeFilter):
|
||||
name_class = InstanceNameDefinition
|
||||
|
||||
def __init__(self, evaluator, context, class_context, origin_scope):
|
||||
@@ -298,7 +298,7 @@ class SelfNameFilter(InstanceClassFilter):
|
||||
yield name
|
||||
|
||||
|
||||
class LazyInstanceName(TreeNameDefinition):
|
||||
class LazyInstanceName(filters.TreeNameDefinition):
|
||||
"""
|
||||
This name calculates the parent_context lazily.
|
||||
"""
|
||||
@@ -321,19 +321,25 @@ class LazyInstanceName(TreeNameDefinition):
|
||||
|
||||
|
||||
class InstanceVarArgs(object):
|
||||
def __init__(self, instance, var_args):
|
||||
def __init__(self, instance, funcdef, var_args):
|
||||
self._instance = instance
|
||||
self._funcdef = funcdef
|
||||
self._var_args = var_args
|
||||
|
||||
@memoize_method
|
||||
def get_var_args(self):
|
||||
def _get_var_args(self):
|
||||
if self._var_args is None:
|
||||
return search_params(self.evaluator, self.parent_context, self.funcdef)
|
||||
# TODO this parent_context might be wrong. test?!
|
||||
return search_params(
|
||||
self._instance.evaluator,
|
||||
self._instance.class_context,
|
||||
self._funcdef
|
||||
)
|
||||
return self._var_args
|
||||
|
||||
def unpack(self, func=None):
|
||||
yield None, LazyKnownContext(self._instance)
|
||||
for values in self._get_var_args.unpack(func):
|
||||
for values in self._get_var_args().unpack(func):
|
||||
yield values
|
||||
|
||||
def get_calling_var_args(self):
|
||||
@@ -342,7 +348,15 @@ class InstanceVarArgs(object):
|
||||
|
||||
class InstanceFunctionExecution(er.FunctionExecutionContext):
|
||||
def __init__(self, instance, parent_context, funcdef, var_args):
|
||||
var_args = InstanceVarArgs(instance, var_args)
|
||||
var_args = InstanceVarArgs(instance, funcdef, var_args)
|
||||
|
||||
super(InstanceFunctionExecution, self).__init__(
|
||||
instance.evaluator, parent_context, funcdef, var_args)
|
||||
|
||||
|
||||
class AnonymousInstanceFunctionExecution(InstanceFunctionExecution):
|
||||
function_execution_filter = filters.AnonymousInstanceFunctionExecutionFilter
|
||||
|
||||
def __init__(self, instance, parent_context, funcdef):
|
||||
super(AnonymousInstanceFunctionExecution, self).__init__(
|
||||
instance, parent_context, funcdef, None)
|
||||
|
||||
@@ -28,35 +28,20 @@ def try_iter_content(types, depth=0):
|
||||
try_iter_content(iter_types, depth + 1)
|
||||
|
||||
|
||||
class AbstractArguments(tree.Base):
|
||||
def get_parent_until(self, *args, **kwargs):
|
||||
raise DeprecationWarning
|
||||
if self.trailer is None:
|
||||
try:
|
||||
element = self.argument_node[0]
|
||||
if isinstance(element, iterable.AlreadyEvaluated):
|
||||
element = list(self._evaluator.eval_element(self._context, element))[0]
|
||||
except IndexError:
|
||||
return None
|
||||
else:
|
||||
return element.get_parent_until(*args, **kwargs)
|
||||
else:
|
||||
return self.trailer.get_parent_until(*args, **kwargs)
|
||||
|
||||
class AbstractArguments():
|
||||
def eval_argument_clinic(self, arguments):
|
||||
"""Uses a list with argument clinic information (see PEP 436)."""
|
||||
raise DeprecationWarning('not sure if we really deprecate it')
|
||||
iterator = self.unpack()
|
||||
for i, (name, optional, allow_kwargs) in enumerate(arguments):
|
||||
key, va_values = next(iterator, (None, []))
|
||||
key, argument = next(iterator, (None, None))
|
||||
if key is not None:
|
||||
raise NotImplementedError
|
||||
if not va_values and not optional:
|
||||
if argument is None and not optional:
|
||||
debug.warning('TypeError: %s expected at least %s arguments, got %s',
|
||||
name, len(arguments), i)
|
||||
raise ValueError
|
||||
values = set(chain.from_iterable(self._evaluator.eval_element(self._context, el)
|
||||
for el in va_values))
|
||||
values = set() if argument is None else argument.infer()
|
||||
|
||||
if not values and not optional:
|
||||
# For the stdlib we always want values. If we don't get them,
|
||||
# that's ok, maybe something is too hard to resolve, however,
|
||||
@@ -65,11 +50,6 @@ class AbstractArguments(tree.Base):
|
||||
raise ValueError
|
||||
yield values
|
||||
|
||||
def scope(self):
|
||||
raise DeprecationWarning
|
||||
# Returns the scope in which the arguments are used.
|
||||
return (self.trailer or self.argument_node).get_parent_until(tree.IsScope)
|
||||
|
||||
def eval_args(self):
|
||||
# TODO this method doesn't work with named args and a lot of other
|
||||
# things. Use unpack.
|
||||
@@ -171,7 +151,7 @@ class TreeArguments(AbstractArguments):
|
||||
yield argument, default, stars
|
||||
|
||||
def __repr__(self):
|
||||
return '<%s: %s>' % (type(self).__name__, self.argument_node)
|
||||
return '<%s: %s>' % (self.__class__.__name__, self.argument_node)
|
||||
|
||||
def get_calling_var_args(self):
|
||||
return _get_calling_var_args(self._evaluator, self)
|
||||
|
||||
@@ -589,6 +589,8 @@ class FunctionExecutionContext(Executed):
|
||||
multiple calls to functions and recursion has to be avoided. But this is
|
||||
responsibility of the decorators.
|
||||
"""
|
||||
function_execution_filter = FunctionExecutionFilter
|
||||
|
||||
def __init__(self, evaluator, parent_context, funcdef, var_args):
|
||||
super(FunctionExecutionContext, self).__init__(evaluator, parent_context, var_args)
|
||||
self.funcdef = funcdef
|
||||
@@ -707,7 +709,7 @@ class FunctionExecutionContext(Executed):
|
||||
del evaluator.predefined_if_name_dict_dict[for_stmt]
|
||||
|
||||
def get_filters(self, search_global, until_position=None, origin_scope=None):
|
||||
yield FunctionExecutionFilter(self.evaluator, self, self.funcdef,
|
||||
yield self.function_execution_filter(self.evaluator, self, self.funcdef,
|
||||
until_position,
|
||||
origin_scope=origin_scope)
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ class NotInStdLib(LookupError):
|
||||
|
||||
def execute(evaluator, obj, arguments):
|
||||
try:
|
||||
obj_name = str(obj.name)
|
||||
obj_name = obj.name.string_name
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
@@ -109,10 +109,6 @@ def argument_clinic(string, want_obj=False, want_scope=False, want_arguments=Fal
|
||||
def builtins_getattr(evaluator, objects, names, defaults=None):
|
||||
# follow the first param
|
||||
for obj in objects:
|
||||
if not isinstance(obj, (er.Instance, er.Class, tree.Module, compiled.CompiledObject)):
|
||||
debug.warning('getattr called without instance')
|
||||
continue
|
||||
|
||||
for name in names:
|
||||
if precedence.is_string(name):
|
||||
return evaluator.find_types(obj, name.obj)
|
||||
|
||||
Reference in New Issue
Block a user