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