Merge branch 'master' into typeshed

This commit is contained in:
Dave Halter
2018-08-06 12:49:51 +02:00
13 changed files with 109 additions and 122 deletions

View File

@@ -8,7 +8,7 @@ from jedi.evaluate.lazy_context import LazyKnownContext, LazyKnownContexts, \
from jedi.evaluate.filters import ParamName from jedi.evaluate.filters import ParamName
from jedi.evaluate.base_context import NO_CONTEXTS from jedi.evaluate.base_context import NO_CONTEXTS
from jedi.evaluate.context import iterable from jedi.evaluate.context import iterable
from jedi.evaluate.param import get_params, ExecutedParam from jedi.evaluate.param import get_executed_params, ExecutedParam
def try_iter_content(types, depth=0): def try_iter_content(types, depth=0):
@@ -64,17 +64,17 @@ class AbstractArguments(object):
try_iter_content(types) try_iter_content(types)
def get_calling_nodes(self): def get_calling_nodes(self):
raise NotImplementedError return []
def unpack(self, funcdef=None): def unpack(self, funcdef=None):
raise NotImplementedError raise NotImplementedError
def get_params(self, execution_context): def get_executed_params(self, execution_context):
return get_params(execution_context, self) return get_executed_params(execution_context, self)
class AnonymousArguments(AbstractArguments): class AnonymousArguments(AbstractArguments):
def get_params(self, execution_context): def get_executed_params(self, execution_context):
from jedi.evaluate.dynamic import search_params from jedi.evaluate.dynamic import search_params
return search_params( return search_params(
execution_context.evaluator, execution_context.evaluator,
@@ -218,9 +218,6 @@ class ValuesArguments(AbstractArguments):
for values in self._values_list: for values in self._values_list:
yield None, LazyKnownContexts(values) yield None, LazyKnownContexts(values)
def get_calling_nodes(self):
return []
def __repr__(self): def __repr__(self):
return '<%s: %s>' % (self.__class__.__name__, self._values_list) return '<%s: %s>' % (self.__class__.__name__, self._values_list)

View File

@@ -22,7 +22,7 @@ except ImportError:
from Queue import Queue, Empty # python 2.7 from Queue import Queue, Empty # python 2.7
from jedi._compatibility import queue, is_py3, force_unicode, \ from jedi._compatibility import queue, is_py3, force_unicode, \
pickle_dump, pickle_load, GeneralizedPopen pickle_dump, pickle_load, GeneralizedPopen, print_to_stderr
from jedi import debug from jedi import debug
from jedi.cache import memoize_method from jedi.cache import memoize_method
from jedi.evaluate.compiled.subprocess import functions from jedi.evaluate.compiled.subprocess import functions
@@ -40,6 +40,18 @@ def _enqueue_output(out, queue):
out.close() out.close()
def _add_stderr_to_debug(stderr_queue):
while True:
# Try to do some error reporting from the subprocess and print its
# stderr contents.
try:
line = stderr_queue.get_nowait()
line = line.decode('utf-8', 'replace')
debug.warning('stderr output: %s' % line.rstrip('\n'))
except Empty:
break
def _get_function(name): def _get_function(name):
return getattr(functions, name) return getattr(functions, name)
@@ -229,10 +241,11 @@ class CompiledSubprocess(object):
is_exception, traceback, result = pickle_load(self._process.stdout) is_exception, traceback, result = pickle_load(self._process.stdout)
except EOFError as eof_error: except EOFError as eof_error:
try: try:
stderr = self._process.stderr.read() stderr = self._process.stderr.read().decode('utf-8', 'replace')
except Exception as exc: except Exception as exc:
stderr = '<empty/not available (%r)>' % exc stderr = '<empty/not available (%r)>' % exc
self._kill() self._kill()
_add_stderr_to_debug(self._stderr_queue)
raise InternalError( raise InternalError(
"The subprocess %s has crashed (%r, stderr=%s)." % ( "The subprocess %s has crashed (%r, stderr=%s)." % (
self._executable, self._executable,
@@ -240,15 +253,7 @@ class CompiledSubprocess(object):
stderr, stderr,
)) ))
while True: _add_stderr_to_debug(self._stderr_queue)
# Try to do some error reporting from the subprocess and print its
# stderr contents.
try:
line = self._stderr_queue.get_nowait()
line = line.decode('utf-8', 'replace')
debug.warning('stderr output: %s' % line.rstrip('\n'))
except Empty:
break
if is_exception: if is_exception:
# Replace the attribute error message with a the traceback. It's # Replace the attribute error message with a the traceback. It's

View File

@@ -94,6 +94,9 @@ class AbstractFunction(TreeContext):
else: else:
return function_execution.get_return_values() return function_execution.get_return_values()
def py__name__(self):
return self.name.string_name
class FunctionContext(use_metaclass(CachedMetaClass, AbstractFunction)): class FunctionContext(use_metaclass(CachedMetaClass, AbstractFunction)):
""" """
@@ -250,5 +253,5 @@ class FunctionExecutionContext(TreeContext):
origin_scope=origin_scope) origin_scope=origin_scope)
@evaluator_method_cache() @evaluator_method_cache()
def get_params(self): def get_executed_params(self):
return self.var_args.get_params(self) return self.var_args.get_executed_params(self)

View File

@@ -1,6 +1,7 @@
from abc import abstractproperty from abc import abstractproperty
from jedi import debug from jedi import debug
from jedi import settings
from jedi.evaluate import compiled from jedi.evaluate import compiled
from jedi.evaluate import filters from jedi.evaluate import filters
from jedi.evaluate.base_context import Context, NO_CONTEXTS, ContextSet, \ from jedi.evaluate.base_context import Context, NO_CONTEXTS, ContextSet, \
@@ -8,7 +9,6 @@ from jedi.evaluate.base_context import Context, NO_CONTEXTS, ContextSet, \
from jedi.evaluate.lazy_context import LazyKnownContext, LazyKnownContexts from jedi.evaluate.lazy_context import LazyKnownContext, LazyKnownContexts
from jedi.evaluate.cache import evaluator_method_cache from jedi.evaluate.cache import evaluator_method_cache
from jedi.evaluate.arguments import AbstractArguments, AnonymousArguments from jedi.evaluate.arguments import AbstractArguments, AnonymousArguments
from jedi.cache import memoize_method
from jedi.evaluate.context.function import FunctionExecutionContext, \ from jedi.evaluate.context.function import FunctionExecutionContext, \
FunctionContext, AbstractFunction FunctionContext, AbstractFunction
from jedi.evaluate.context.klass import ClassContext, apply_py__get__, ClassFilter from jedi.evaluate.context.klass import ClassContext, apply_py__get__, ClassFilter
@@ -16,27 +16,27 @@ from jedi.evaluate.context import iterable
from jedi.parser_utils import get_parent_scope from jedi.parser_utils import get_parent_scope
class BaseInstanceFunctionExecution(FunctionExecutionContext): class InstanceExecutedParam(object):
def __init__(self, instance, *args, **kwargs): def __init__(self, instance):
self.instance = instance self._instance = instance
super(BaseInstanceFunctionExecution, self).__init__(
instance.evaluator, *args, **kwargs) def infer(self):
return ContextSet(self._instance)
class InstanceFunctionExecution(BaseInstanceFunctionExecution): class AnonymousInstanceArguments(AnonymousArguments):
def __init__(self, instance, parent_context, function_context, var_args): def __init__(self, instance):
var_args = InstanceVarArgs(self, var_args) self._instance = instance
super(InstanceFunctionExecution, self).__init__( def get_executed_params(self, execution_context):
instance, parent_context, function_context, var_args) from jedi.evaluate.dynamic import search_params
executed_params = list(search_params(
execution_context.evaluator,
class AnonymousInstanceFunctionExecution(BaseInstanceFunctionExecution): execution_context,
function_execution_filter = filters.AnonymousInstanceFunctionExecutionFilter execution_context.tree_node
))
def __init__(self, instance, parent_context, function_context, var_args): executed_params[0] = InstanceExecutedParam(self._instance)
super(AnonymousInstanceFunctionExecution, self).__init__( return executed_params
instance, parent_context, function_context, var_args)
class AbstractInstanceContext(Context): class AbstractInstanceContext(Context):
@@ -44,7 +44,6 @@ class AbstractInstanceContext(Context):
This class is used to evaluate instances. This class is used to evaluate instances.
""" """
api_type = u'instance' api_type = u'instance'
function_execution_cls = InstanceFunctionExecution
def __init__(self, evaluator, parent_context, class_context, var_args): def __init__(self, evaluator, parent_context, class_context, var_args):
super(AbstractInstanceContext, self).__init__(evaluator, parent_context) super(AbstractInstanceContext, self).__init__(evaluator, parent_context)
@@ -160,12 +159,7 @@ class AbstractInstanceContext(Context):
pass pass
def _create_init_execution(self, class_context, bound_method): def _create_init_execution(self, class_context, bound_method):
return self.function_execution_cls( return bound_method.get_function_execution(self.var_args)
self,
class_context.parent_context,
bound_method,
self.var_args
)
def create_init_executions(self): def create_init_executions(self):
for name in self.get_function_slot_names(u'__init__'): for name in self.get_function_slot_names(u'__init__'):
@@ -212,16 +206,18 @@ class AbstractInstanceContext(Context):
class CompiledInstance(AbstractInstanceContext): class CompiledInstance(AbstractInstanceContext):
def __init__(self, *args, **kwargs): def __init__(self, evaluator, parent_context, class_context, var_args):
super(CompiledInstance, self).__init__(*args, **kwargs) self._original_var_args = var_args
# I don't think that dynamic append lookups should happen here. That # I don't think that dynamic append lookups should happen here. That
# sounds more like something that should go to py__iter__. # sounds more like something that should go to py__iter__.
self._original_var_args = self.var_args if class_context.py__name__() in ['list', 'set'] \
and parent_context.get_root_context() == evaluator.builtins_module:
if self.class_context.name.string_name in ['list', 'set'] \
and self.parent_context.get_root_context() == self.evaluator.builtins_module:
# compare the module path with the builtin name. # compare the module path with the builtin name.
self.var_args = iterable.get_dynamic_array_instance(self) if settings.dynamic_array_additions:
var_args = iterable.get_dynamic_array_instance(self, var_args)
super(CompiledInstance, self).__init__(evaluator, parent_context, class_context, var_args)
@property @property
def name(self): def name(self):
@@ -253,14 +249,12 @@ class TreeInstance(AbstractInstanceContext):
class AnonymousInstance(TreeInstance): class AnonymousInstance(TreeInstance):
function_execution_cls = AnonymousInstanceFunctionExecution
def __init__(self, evaluator, parent_context, class_context): def __init__(self, evaluator, parent_context, class_context):
super(AnonymousInstance, self).__init__( super(AnonymousInstance, self).__init__(
evaluator, evaluator,
parent_context, parent_context,
class_context, class_context,
var_args=AnonymousArguments(), var_args=AnonymousInstanceArguments(self),
) )
@@ -327,12 +321,21 @@ class BoundMethod(AbstractFunction):
def get_function_execution(self, arguments=None): def get_function_execution(self, arguments=None):
if arguments is None: if arguments is None:
arguments = AnonymousArguments() arguments = AnonymousInstanceArguments(self._instance)
return AnonymousInstanceFunctionExecution(
self._instance, self.parent_context, self, arguments) arguments = InstanceArguments(self._instance, arguments)
else:
return InstanceFunctionExecution( if isinstance(self._function, compiled.CompiledObject):
self._instance, self.parent_context, self, arguments) # This is kind of weird, because it's coming from a compiled object
# and we're not sure if we want that in the future.
return FunctionExecutionContext(
self.evaluator, self.parent_context, self, arguments
)
return self._function.get_function_execution(arguments)
def __repr__(self):
return '<%s: %s>' % (self.__class__.__name__, self._function)
class CompiledBoundMethod(compiled.CompiledObject): class CompiledBoundMethod(compiled.CompiledObject):
@@ -446,15 +449,11 @@ class SelfAttributeFilter(ClassFilter):
return names return names
class InstanceVarArgs(AbstractArguments): class InstanceArguments(AbstractArguments):
def __init__(self, execution_context, var_args): def __init__(self, instance, var_args):
self._execution_context = execution_context self.instance = instance
self._var_args = var_args self._var_args = var_args
@memoize_method
def _get_var_args(self):
return self._var_args
@property @property
def argument_node(self): def argument_node(self):
return self._var_args.argument_node return self._var_args.argument_node
@@ -464,9 +463,15 @@ class InstanceVarArgs(AbstractArguments):
return self._var_args.trailer return self._var_args.trailer
def unpack(self, func=None): def unpack(self, func=None):
yield None, LazyKnownContext(self._execution_context.instance) yield None, LazyKnownContext(self.instance)
for values in self._get_var_args().unpack(func): for values in self._var_args.unpack(func):
yield values yield values
def get_calling_nodes(self): def get_calling_nodes(self):
return self._get_var_args().get_calling_nodes() return self._var_args.get_calling_nodes()
def get_executed_params(self, execution_context):
if isinstance(self._var_args, AnonymousInstanceArguments):
return self._var_args.get_executed_params(execution_context)
return super(InstanceArguments, self).get_executed_params(execution_context)

View File

@@ -631,12 +631,9 @@ def _check_array_additions(context, sequence):
return added_types return added_types
def get_dynamic_array_instance(instance): def get_dynamic_array_instance(instance, arguments):
"""Used for set() and list() instances.""" """Used for set() and list() instances."""
if not settings.dynamic_array_additions: ai = _ArrayInstance(instance, arguments)
return instance.var_args
ai = _ArrayInstance(instance)
from jedi.evaluate import arguments from jedi.evaluate import arguments
return arguments.ValuesArguments([ContextSet(ai)]) return arguments.ValuesArguments([ContextSet(ai)])
@@ -652,9 +649,9 @@ class _ArrayInstance(object):
and therefore doesn't need filters, `py__bool__` and so on, because and therefore doesn't need filters, `py__bool__` and so on, because
we don't use these operations in `builtins.py`. we don't use these operations in `builtins.py`.
""" """
def __init__(self, instance): def __init__(self, instance, var_args):
self.instance = instance self.instance = instance
self.var_args = instance.var_args self.var_args = var_args
def py__iter__(self): def py__iter__(self):
var_args = self.var_args var_args = self.var_args

View File

@@ -43,7 +43,7 @@ from jedi.evaluate.cache import evaluator_method_cache, CachedMetaClass
from jedi.evaluate import compiled from jedi.evaluate import compiled
from jedi.evaluate.lazy_context import LazyKnownContext from jedi.evaluate.lazy_context import LazyKnownContext
from jedi.evaluate.filters import ParserTreeFilter, TreeNameDefinition, \ from jedi.evaluate.filters import ParserTreeFilter, TreeNameDefinition, \
ContextName, AnonymousInstanceParamName ContextName
from jedi.evaluate.base_context import ContextSet, iterator_to_context_set, \ from jedi.evaluate.base_context import ContextSet, iterator_to_context_set, \
TreeContext TreeContext
@@ -173,11 +173,6 @@ class ClassContext(use_metaclass(CachedMetaClass, TreeContext)):
def py__class__(self): def py__class__(self):
return compiled.builtin_from_name(self.evaluator, u'type') return compiled.builtin_from_name(self.evaluator, u'type')
def get_params(self):
from jedi.evaluate.context import AnonymousInstance
anon = AnonymousInstance(self.evaluator, self.parent_context, self)
return [AnonymousInstanceParamName(anon, param.name) for param in self.funcdef.get_params()]
def get_filters(self, search_global, until_position=None, origin_scope=None, is_instance=False): def get_filters(self, search_global, until_position=None, origin_scope=None, is_instance=False):
if search_global: if search_global:
yield ParserTreeFilter( yield ParserTreeFilter(

View File

@@ -267,7 +267,8 @@ def _execute_array_values(evaluator, array):
@evaluator_method_cache() @evaluator_method_cache()
def infer_param(execution_context, param): def infer_param(execution_context, param):
from jedi.evaluate.context.instance import AnonymousInstanceFunctionExecution from jedi.evaluate.context.instance import InstanceArguments
from jedi.evaluate.context import FunctionExecutionContext
def eval_docstring(docstring): def eval_docstring(docstring):
return ContextSet.from_iterable( return ContextSet.from_iterable(
@@ -281,9 +282,10 @@ def infer_param(execution_context, param):
return NO_CONTEXTS return NO_CONTEXTS
types = eval_docstring(execution_context.py__doc__()) types = eval_docstring(execution_context.py__doc__())
if isinstance(execution_context, AnonymousInstanceFunctionExecution) and \ if isinstance(execution_context, FunctionExecutionContext) \
execution_context.function_context.name.string_name == '__init__': and isinstance(execution_context.var_args, InstanceArguments) \
class_context = execution_context.instance.class_context and execution_context.function_context.py__name__() == '__init__':
class_context = execution_context.var_args.instance.class_context
types |= eval_docstring(class_context.py__doc__()) types |= eval_docstring(class_context.py__doc__())
return types return types

View File

@@ -99,7 +99,7 @@ def search_params(evaluator, execution_context, funcdef):
) )
if function_executions: if function_executions:
zipped_params = zip(*list( zipped_params = zip(*list(
function_execution.get_params() function_execution.get_executed_params()
for function_execution in function_executions for function_execution in function_executions
)) ))
params = [DynamicExecutedParams(evaluator, executed_params) for executed_params in zipped_params] params = [DynamicExecutedParams(evaluator, executed_params) for executed_params in zipped_params]
@@ -208,7 +208,7 @@ def _check_name_for_execution(evaluator, context, compare_node, name, trailer):
# Here we're trying to find decorators by checking the first # Here we're trying to find decorators by checking the first
# parameter. It's not very generic though. Should find a better # parameter. It's not very generic though. Should find a better
# solution that also applies to nested decorators. # solution that also applies to nested decorators.
params = value.parent_context.get_params() params = value.parent_context.get_executed_params()
if len(params) != 1: if len(params) != 1:
continue continue
values = params[0].infer() values = params[0].infer()

View File

@@ -136,24 +136,11 @@ class ParamName(AbstractTreeName):
return self.get_param().infer() return self.get_param().infer()
def get_param(self): def get_param(self):
params = self.parent_context.get_params() params = self.parent_context.get_executed_params()
param_node = search_ancestor(self.tree_name, 'param') param_node = search_ancestor(self.tree_name, 'param')
return params[param_node.position_index] return params[param_node.position_index]
class AnonymousInstanceParamName(ParamName):
def infer(self):
param_node = search_ancestor(self.tree_name, 'param')
# TODO I think this should not belong here. It's not even really true,
# because classmethod and other descriptors can change it.
if param_node.position_index == 0:
# This is a speed optimization, to return the self param (because
# it's known). This only affects anonymous instances.
return ContextSet(self.parent_context.instance)
else:
return self.get_param().infer()
class AbstractFilter(object): class AbstractFilter(object):
_until_position = None _until_position = None
@@ -266,10 +253,6 @@ class FunctionExecutionFilter(ParserTreeFilter):
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): def __init__(self, context, parser_scope):
super(GlobalNameFilter, self).__init__(context, parser_scope) super(GlobalNameFilter, self).__init__(context, parser_scope)

View File

@@ -41,7 +41,7 @@ class ExecutedParam(object):
return '<%s: %s>' % (self.__class__.__name__, self.string_name) return '<%s: %s>' % (self.__class__.__name__, self.string_name)
def get_params(execution_context, var_args): def get_executed_params(execution_context, var_args):
result_params = [] result_params = []
param_dict = {} param_dict = {}
funcdef = execution_context.tree_node funcdef = execution_context.tree_node

View File

@@ -157,8 +157,8 @@ def infer_param(execution_context, param):
"Comments length != Params length %s %s", "Comments length != Params length %s %s",
params_comments, all_params params_comments, all_params
) )
from jedi.evaluate.context.instance import BaseInstanceFunctionExecution from jedi.evaluate.context.instance import InstanceArguments
if isinstance(execution_context, BaseInstanceFunctionExecution): if isinstance(execution_context.var_args, InstanceArguments):
if index == 0: if index == 0:
# Assume it's self, which is already handled # Assume it's self, which is already handled
return NO_CONTEXTS return NO_CONTEXTS

View File

@@ -278,7 +278,7 @@ def eval_expr_stmt(context, stmt, seek_name=None):
# necessary. # necessary.
if not allowed and context.get_root_context() == context.evaluator.builtins_module: if not allowed and context.get_root_context() == context.evaluator.builtins_module:
try: try:
instance = context.instance instance = context.var_args.instance
except AttributeError: except AttributeError:
pass pass
else: else:

View File

@@ -19,12 +19,11 @@ from jedi import debug
from jedi.evaluate.arguments import ValuesArguments from jedi.evaluate.arguments import ValuesArguments
from jedi.evaluate import analysis from jedi.evaluate import analysis
from jedi.evaluate import compiled from jedi.evaluate import compiled
from jedi.evaluate.context.instance import InstanceFunctionExecution, \ from jedi.evaluate.context.instance import \
AbstractInstanceContext, CompiledInstance, BoundMethod, \ AbstractInstanceContext, CompiledInstance, BoundMethod, InstanceArguments
AnonymousInstanceFunctionExecution
from jedi.evaluate.base_context import ContextualizedNode, \ from jedi.evaluate.base_context import ContextualizedNode, \
NO_CONTEXTS, ContextSet NO_CONTEXTS, ContextSet
from jedi.evaluate.context import ClassContext, ModuleContext from jedi.evaluate.context import ClassContext, ModuleContext, FunctionExecutionContext
from jedi.evaluate.context import iterable from jedi.evaluate.context import iterable
from jedi.evaluate.lazy_context import LazyTreeContext from jedi.evaluate.lazy_context import LazyTreeContext
from jedi.evaluate.syntax_tree import is_string from jedi.evaluate.syntax_tree import is_string
@@ -202,10 +201,11 @@ class SuperInstance(AbstractInstanceContext):
@argument_clinic('[type[, obj]], /', want_context=True) @argument_clinic('[type[, obj]], /', want_context=True)
def builtins_super(evaluator, types, objects, context): def builtins_super(evaluator, types, objects, context):
# TODO make this able to detect multiple inheritance super # TODO make this able to detect multiple inheritance super
if isinstance(context, (InstanceFunctionExecution, if isinstance(context, FunctionExecutionContext):
AnonymousInstanceFunctionExecution)): if isinstance(context.var_args, InstanceArguments):
su = context.instance.py__class__().py__bases__() su = context.var_args.instance.py__class__().py__bases__()
return su[0].infer().execute_evaluated() return su[0].infer().execute_evaluated()
return NO_CONTEXTS return NO_CONTEXTS