1
0
forked from VimPlug/jedi

Fixing getattr tests.

This commit is contained in:
Dave Halter
2016-11-07 20:15:58 +01:00
parent 40f599c3b6
commit 4a8fd73601
9 changed files with 83 additions and 66 deletions

View File

@@ -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,7 +527,14 @@ class Evaluator(object):
if scope_node == module_context.module_node:
return module_context
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':
class_context = er.ClassContext(self, scope_node, parent_context)
if child_is_funcdef:

View File

@@ -1,4 +1,6 @@
from jedi.common import unite
class Context(object):
type = None # TODO remove

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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,9 +709,9 @@ 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,
until_position,
origin_scope=origin_scope)
yield self.function_execution_filter(self.evaluator, self, self.funcdef,
until_position,
origin_scope=origin_scope)
@memoize_default(default=NO_DEFAULT)
def get_params(self):

View File

@@ -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)