Merge branch 'master' into typeshed

This commit is contained in:
Dave Halter
2018-08-03 00:26:09 +02:00
18 changed files with 101 additions and 109 deletions

View File

@@ -122,7 +122,7 @@ Tips on how to use Jedi efficiently can be found `here
API API
--- ---
You can find the documentation for the `API here <https://jedi.readthedocs.org/en/latest/docs/plugin-api.html>`_. You can find the documentation for the `API here <https://jedi.readthedocs.org/en/latest/docs/api.html>`_.
Autocompletion / Goto / Pydoc Autocompletion / Goto / Pydoc

View File

@@ -14,7 +14,7 @@ from jedi.evaluate import imports
from jedi.evaluate import compiled from jedi.evaluate import compiled
from jedi.evaluate.imports import ImportName from jedi.evaluate.imports import ImportName
from jedi.evaluate.context import instance from jedi.evaluate.context import instance
from jedi.evaluate.context import ClassContext, FunctionContext, FunctionExecutionContext from jedi.evaluate.context import ClassContext, FunctionExecutionContext
from jedi.api.keywords import KeywordName from jedi.api.keywords import KeywordName
@@ -353,10 +353,7 @@ class BaseDefinition(object):
return None return None
if isinstance(context, FunctionExecutionContext): if isinstance(context, FunctionExecutionContext):
# TODO the function context should be a part of the function context = context.function_context
# execution context.
context = FunctionContext(
self._evaluator, context.parent_context, context.tree_node)
return Definition(self._evaluator, context.name) return Definition(self._evaluator, context.name)
def __repr__(self): def __repr__(self):

View File

@@ -237,7 +237,7 @@ class Evaluator(object):
if type_ == 'classdef': if type_ == 'classdef':
return [ClassContext(self, context, name.parent)] return [ClassContext(self, context, name.parent)]
elif type_ == 'funcdef': elif type_ == 'funcdef':
return [FunctionContext(self, context, name.parent)] return [FunctionContext.from_context(context, name.parent)]
if type_ == 'expr_stmt': if type_ == 'expr_stmt':
is_simple_name = name.parent.type not in ('power', 'trailer') is_simple_name = name.parent.type not in ('power', 'trailer')
@@ -355,16 +355,15 @@ class Evaluator(object):
parent_context = from_scope_node(parent_scope, child_is_funcdef=is_funcdef) parent_context = from_scope_node(parent_scope, child_is_funcdef=is_funcdef)
if is_funcdef: if is_funcdef:
func = FunctionContext.from_context(
parent_context,
scope_node
)
if isinstance(parent_context, AnonymousInstance): if isinstance(parent_context, AnonymousInstance):
func = BoundMethod( func = BoundMethod(
self, parent_context, parent_context.class_context, instance=parent_context,
parent_context.parent_context, scope_node klass=parent_context.class_context,
) function=func
else:
func = FunctionContext(
self,
parent_context,
scope_node
) )
if is_nested and not node_is_object: if is_nested and not node_is_object:
return func.get_function_execution() return func.get_function_execution()

View File

@@ -168,9 +168,10 @@ def iterate_contexts(contexts, contextualized_node=None, is_async=False):
class TreeContext(Context): class TreeContext(Context):
def __init__(self, evaluator, parent_context=None): def __init__(self, evaluator, parent_context, tree_node):
super(TreeContext, self).__init__(evaluator, parent_context) super(TreeContext, self).__init__(evaluator, parent_context)
self.predefined_names = {} self.predefined_names = {}
self.tree_node = tree_node
def __repr__(self): def __repr__(self):
return '<%s: %s>' % (self.__class__.__name__, self.tree_node) return '<%s: %s>' % (self.__class__.__name__, self.tree_node)

View File

@@ -470,7 +470,7 @@ else:
class _SPECIAL_OBJECTS(object): class _SPECIAL_OBJECTS(object):
FUNCTION_CLASS = types.FunctionType FUNCTION_CLASS = types.FunctionType
METHOD_CLASS = type(DirectObjectAccess.py__bool__) BOUND_METHOD_CLASS = type(DirectObjectAccess(None, None).py__bool__)
MODULE_CLASS = types.ModuleType MODULE_CLASS = types.ModuleType
GENERATOR_OBJECT = _a_generator(1.0) GENERATOR_OBJECT = _a_generator(1.0)
BUILTINS = builtins BUILTINS = builtins

View File

@@ -55,7 +55,7 @@ class CompiledObject(Context):
return FunctionContext( return FunctionContext(
self.evaluator, self.evaluator,
parent_context=self.parent_context, parent_context=self.parent_context,
funcdef=self.tree_node tree_node=self.tree_node
).py__call__(params) ).py__call__(params)
if self.access_handle.is_class(): if self.access_handle.is_class():
from jedi.evaluate.context import CompiledInstance from jedi.evaluate.context import CompiledInstance

View File

@@ -38,17 +38,9 @@ class LambdaName(AbstractNameDefinition):
return ContextSet(self._lambda_context) return ContextSet(self._lambda_context)
class FunctionContext(use_metaclass(CachedMetaClass, TreeContext)): class AbstractFunction(TreeContext):
"""
Needed because of decorators. Decorators are evaluated here.
"""
api_type = u'function' api_type = u'function'
def __init__(self, evaluator, parent_context, funcdef):
""" This should not be called directly """
super(FunctionContext, self).__init__(evaluator, parent_context)
self.tree_node = funcdef
def get_filters(self, search_global, until_position=None, origin_scope=None): def get_filters(self, search_global, until_position=None, origin_scope=None):
if search_global: if search_global:
yield ParserTreeFilter( yield ParserTreeFilter(
@@ -62,6 +54,24 @@ class FunctionContext(use_metaclass(CachedMetaClass, TreeContext)):
for filter in scope.get_filters(search_global=False, origin_scope=origin_scope): for filter in scope.get_filters(search_global=False, origin_scope=origin_scope):
yield filter yield filter
def get_param_names(self):
function_execution = self.get_function_execution()
return [ParamName(function_execution, param.name)
for param in self.tree_node.get_params()]
@property
def name(self):
if self.tree_node.type == 'lambdef':
return LambdaName(self)
return ContextName(self, self.tree_node.name)
def get_function_execution(self, arguments=None):
raise NotImplementedError
def py__call__(self, arguments):
function_execution = self.get_function_execution(arguments)
return self.infer_function_execution(function_execution)
def infer_function_execution(self, function_execution): def infer_function_execution(self, function_execution):
""" """
Created to be used by inheritance. Created to be used by inheritance.
@@ -84,35 +94,28 @@ class FunctionContext(use_metaclass(CachedMetaClass, TreeContext)):
else: else:
return function_execution.get_return_values() return function_execution.get_return_values()
class FunctionContext(use_metaclass(CachedMetaClass, AbstractFunction)):
"""
Needed because of decorators. Decorators are evaluated here.
"""
@classmethod
def from_context(cls, context, tree_node):
from jedi.evaluate.context import AbstractInstanceContext
while context.is_class() or isinstance(context, AbstractInstanceContext):
context = context.parent_context
return cls(context.evaluator, parent_context=context, tree_node=tree_node)
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 = AnonymousArguments()
return FunctionExecutionContext(self.evaluator, self.parent_context, self, arguments) return FunctionExecutionContext(self.evaluator, self.parent_context, self, arguments)
def py__call__(self, arguments):
function_execution = self.get_function_execution(arguments)
return self.infer_function_execution(function_execution)
def py__class__(self): def py__class__(self):
# This differentiation is only necessary for Python2. Python3 does not return compiled.get_special_object(self.evaluator, u'FUNCTION_CLASS')
# use a different method class.
if isinstance(parser_utils.get_parent_scope(self.tree_node), tree.Class):
name = u'METHOD_CLASS'
else:
name = u'FUNCTION_CLASS'
return compiled.get_special_object(self.evaluator, name)
@property
def name(self):
if self.tree_node.type == 'lambdef':
return LambdaName(self)
return ContextName(self, self.tree_node.name)
def get_param_names(self):
function_execution = self.get_function_execution()
return [ParamName(function_execution, param.name)
for param in self.tree_node.get_params()]
class FunctionExecutionContext(TreeContext): class FunctionExecutionContext(TreeContext):
@@ -127,9 +130,12 @@ class FunctionExecutionContext(TreeContext):
function_execution_filter = FunctionExecutionFilter function_execution_filter = FunctionExecutionFilter
def __init__(self, evaluator, parent_context, function_context, var_args): def __init__(self, evaluator, parent_context, function_context, var_args):
super(FunctionExecutionContext, self).__init__(evaluator, parent_context) super(FunctionExecutionContext, self).__init__(
evaluator,
parent_context,
function_context.tree_node,
)
self.function_context = function_context self.function_context = function_context
self.tree_node = function_context.tree_node
self.var_args = var_args self.var_args = var_args
@evaluator_method_cache(default=NO_CONTEXTS) @evaluator_method_cache(default=NO_CONTEXTS)

View File

@@ -9,7 +9,8 @@ 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.cache import memoize_method
from jedi.evaluate.context.function import FunctionExecutionContext, FunctionContext from jedi.evaluate.context.function import FunctionExecutionContext, \
FunctionContext, AbstractFunction
from jedi.evaluate.context.klass import ClassContext, apply_py__get__ from jedi.evaluate.context.klass import ClassContext, apply_py__get__
from jedi.evaluate.context import iterable from jedi.evaluate.context import iterable
from jedi.parser_utils import get_parent_scope from jedi.parser_utils import get_parent_scope
@@ -158,10 +159,7 @@ class AbstractInstanceContext(Context):
def name(self): def name(self):
pass pass
def _create_init_execution(self, class_context, func_node): def _create_init_execution(self, class_context, bound_method):
bound_method = BoundMethod(
self.evaluator, self, class_context, self.parent_context, func_node
)
return self.function_execution_cls( return self.function_execution_cls(
self, self,
class_context.parent_context, class_context.parent_context,
@@ -172,7 +170,12 @@ class AbstractInstanceContext(Context):
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__'):
if isinstance(name, SelfName): if isinstance(name, SelfName):
yield self._create_init_execution(name.class_context, name.tree_name.parent) function = FunctionContext.from_context(
self.parent_context,
name.tree_name.parent
)
bound_method = BoundMethod(self, name.class_context, function)
yield self._create_init_execution(name.class_context, bound_method)
@evaluator_method_cache() @evaluator_method_cache()
def create_instance_context(self, class_context, node): def create_instance_context(self, class_context, node):
@@ -184,13 +187,14 @@ class AbstractInstanceContext(Context):
else: else:
parent_context = self.create_instance_context(class_context, scope) parent_context = self.create_instance_context(class_context, scope)
if scope.type == 'funcdef': if scope.type == 'funcdef':
func = FunctionContext.from_context(
parent_context,
scope,
)
bound_method = BoundMethod(self, class_context, func)
if scope.name.value == '__init__' and parent_context == class_context: if scope.name.value == '__init__' and parent_context == class_context:
return self._create_init_execution(class_context, scope) return self._create_init_execution(class_context, bound_method)
else: else:
bound_method = BoundMethod(
self.evaluator, self, class_context,
parent_context, scope
)
return bound_method.get_function_execution() return bound_method.get_function_execution()
elif scope.type == 'classdef': elif scope.type == 'classdef':
class_context = ClassContext(self.evaluator, parent_context, scope) class_context = ClassContext(self.evaluator, parent_context, scope)
@@ -270,14 +274,8 @@ class CompiledInstanceName(compiled.CompiledName):
for result_context in super(CompiledInstanceName, self).infer(): for result_context in super(CompiledInstanceName, self).infer():
is_function = result_context.api_type == 'function' is_function = result_context.api_type == 'function'
if result_context.tree_node is not None and is_function: if result_context.tree_node is not None and is_function:
parent_context = result_context.parent_context
while parent_context.is_class():
parent_context = parent_context.parent_context
yield BoundMethod( yield BoundMethod(self._instance, self.parent_context, result_context)
result_context.evaluator, self._instance, self.parent_context,
parent_context, result_context.tree_node
)
else: else:
if is_function: if is_function:
yield CompiledBoundMethod(result_context) yield CompiledBoundMethod(result_context)
@@ -301,11 +299,19 @@ class CompiledInstanceClassFilter(compiled.CompiledObjectFilter):
self._evaluator, self._instance, self._compiled_object, name) self._evaluator, self._instance, self._compiled_object, name)
class BoundMethod(FunctionContext): class BoundMethod(AbstractFunction):
def __init__(self, evaluator, instance, class_context, *args, **kwargs): def __init__(self, instance, klass, function):
super(BoundMethod, self).__init__(evaluator, *args, **kwargs) super(BoundMethod, self).__init__(
function.evaluator,
function.parent_context,
function.tree_node,
)
self._instance = instance self._instance = instance
self._class_context = class_context self._class = klass
self._function = function
def py__class__(self):
return compiled.get_special_object(self.evaluator, u'BOUND_METHOD_CLASS')
def get_function_execution(self, arguments=None): def get_function_execution(self, arguments=None):
if arguments is None: if arguments is None:
@@ -353,14 +359,7 @@ class LazyInstanceClassName(SelfName):
# Classes are never used to resolve anything within the # Classes are never used to resolve anything within the
# functions. Only other functions and modules will resolve # functions. Only other functions and modules will resolve
# those things. # those things.
parent_context = result_context.parent_context yield BoundMethod(self._instance, self.class_context, result_context)
while parent_context.is_class():
parent_context = parent_context.parent_context
yield BoundMethod(
result_context.evaluator, self._instance, self.class_context,
parent_context, result_context.tree_node
)
else: else:
for c in apply_py__get__(result_context, self._instance): for c in apply_py__get__(result_context, self._instance):
yield c yield c

View File

@@ -83,10 +83,6 @@ class CompForContext(TreeContext):
def from_comp_for(cls, parent_context, comp_for): def from_comp_for(cls, parent_context, comp_for):
return cls(parent_context.evaluator, parent_context, comp_for) return cls(parent_context.evaluator, parent_context, comp_for)
def __init__(self, evaluator, parent_context, comp_for):
super(CompForContext, self).__init__(evaluator, parent_context)
self.tree_node = comp_for
def get_node(self): def get_node(self):
return self.tree_node return self.tree_node

View File

@@ -89,10 +89,6 @@ class ClassContext(use_metaclass(CachedMetaClass, TreeContext)):
""" """
api_type = u'class' api_type = u'class'
def __init__(self, evaluator, parent_context, classdef):
super(ClassContext, self).__init__(evaluator, parent_context=parent_context)
self.tree_node = classdef
@evaluator_method_cache(default=()) @evaluator_method_cache(default=())
def py__mro__(self): def py__mro__(self):
def add(cls): def add(cls):

View File

@@ -43,8 +43,11 @@ class ModuleContext(TreeContext):
parent_context = None parent_context = None
def __init__(self, evaluator, module_node, path, code_lines): def __init__(self, evaluator, module_node, path, code_lines):
super(ModuleContext, self).__init__(evaluator, parent_context=None) super(ModuleContext, self).__init__(
self.tree_node = module_node evaluator,
parent_context=None,
tree_node=module_node
)
self._path = path self._path = path
self.code_lines = code_lines self.code_lines = code_lines

View File

@@ -4,7 +4,7 @@ from itertools import chain
from jedi.evaluate.cache import evaluator_method_cache from jedi.evaluate.cache import evaluator_method_cache
from jedi.evaluate import imports from jedi.evaluate import imports
from jedi.evaluate.filters import DictFilter, AbstractNameDefinition, ContextNameMixin from jedi.evaluate.filters import DictFilter, AbstractNameDefinition, ContextNameMixin
from jedi.evaluate.base_context import TreeContext, ContextSet from jedi.evaluate.base_context import Context
class ImplicitNSName(ContextNameMixin, AbstractNameDefinition): class ImplicitNSName(ContextNameMixin, AbstractNameDefinition):
@@ -17,7 +17,7 @@ class ImplicitNSName(ContextNameMixin, AbstractNameDefinition):
self.string_name = string_name self.string_name = string_name
class ImplicitNamespaceContext(TreeContext): class ImplicitNamespaceContext(Context):
""" """
Provides support for implicit namespace packages Provides support for implicit namespace packages
""" """

View File

@@ -1,6 +1,7 @@
from jedi.evaluate.base_context import ContextSet, NO_CONTEXTS from jedi.evaluate.base_context import ContextSet, NO_CONTEXTS
from jedi.common.utils import monkeypatch from jedi.common.utils import monkeypatch
class AbstractLazyContext(object): class AbstractLazyContext(object):
def __init__(self, data): def __init__(self, data):
self.data = data self.data = data

View File

@@ -71,7 +71,7 @@ def eval_node(context, element):
if typ in ('name', 'number', 'string', 'atom', 'strings', 'keyword'): if typ in ('name', 'number', 'string', 'atom', 'strings', 'keyword'):
return eval_atom(context, element) return eval_atom(context, element)
elif typ == 'lambdef': elif typ == 'lambdef':
return ContextSet(FunctionContext(evaluator, context, element)) return ContextSet(FunctionContext.from_context(context, element))
elif typ == 'expr_stmt': elif typ == 'expr_stmt':
return eval_expr_stmt(context, element) return eval_expr_stmt(context, element)
elif typ in ('power', 'atom_expr'): elif typ in ('power', 'atom_expr'):
@@ -603,14 +603,10 @@ def _apply_decorators(context, node):
decoratee_context = ClassContext( decoratee_context = ClassContext(
context.evaluator, context.evaluator,
parent_context=context, parent_context=context,
classdef=node tree_node=node
) )
else: else:
decoratee_context = FunctionContext( decoratee_context = FunctionContext.from_context(context, node)
context.evaluator,
parent_context=context,
funcdef=node
)
initial = values = ContextSet(decoratee_context) initial = values = ContextSet(decoratee_context)
for dec in reversed(node.get_decorators()): for dec in reversed(node.get_decorators()):
debug.dbg('decorator: %s %s', dec, values) debug.dbg('decorator: %s %s', dec, values)

View File

@@ -132,7 +132,6 @@ def test_async(Script, environment):
hey = 3 hey = 3
ho''' ho'''
) )
print(code)
comps = Script(code, column=4).completions() comps = Script(code, column=4).completions()
names = [c.name for c in comps] names = [c.name for c in comps]
assert 'foo' in names assert 'foo' in names

View File

@@ -70,11 +70,7 @@ def test_method_completion(Script, environment):
foo = Foo() foo = Foo()
foo.bar.__func__''') foo.bar.__func__''')
if environment.version_info.major > 2: assert [c.name for c in Script(code).completions()] == ['__func__']
result = []
else:
result = ['__func__']
assert [c.name for c in Script(code).completions()] == result
def test_time_docstring(Script): def test_time_docstring(Script):

View File

@@ -77,10 +77,13 @@ def test_nested_namespace_package(Script):
assert len(result) == 1 assert len(result) == 1
def test_relative_import(Script, tmpdir): def test_relative_import(Script, environment, tmpdir):
""" """
Attempt a relative import in a very simple namespace package. Attempt a relative import in a very simple namespace package.
""" """
if environment.version_info < (3, 4):
pytest.skip()
directory = get_example_dir('namespace_package_relative_import') directory = get_example_dir('namespace_package_relative_import')
# Need to copy the content in a directory where there's no __init__.py. # Need to copy the content in a directory where there's no __init__.py.
py.path.local(directory).copy(tmpdir) py.path.local(directory).copy(tmpdir)

View File

@@ -9,8 +9,8 @@ deps =
# coloroma for colored debug output # coloroma for colored debug output
colorama colorama
# Overwrite the parso version (only used sometimes). # Overwrite the parso version (only used sometimes).
git+https://github.com/davidhalter/parso.git # git+https://github.com/davidhalter/parso.git
# -rrequirements.txt -rrequirements.txt
passenv = JEDI_TEST_ENVIRONMENT passenv = JEDI_TEST_ENVIRONMENT
setenv = setenv =
# https://github.com/tomchristie/django-rest-framework/issues/1957 # https://github.com/tomchristie/django-rest-framework/issues/1957