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

View File

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

View File

@@ -237,7 +237,7 @@ class Evaluator(object):
if type_ == 'classdef':
return [ClassContext(self, context, name.parent)]
elif type_ == 'funcdef':
return [FunctionContext(self, context, name.parent)]
return [FunctionContext.from_context(context, name.parent)]
if type_ == 'expr_stmt':
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)
if is_funcdef:
func = FunctionContext.from_context(
parent_context,
scope_node
)
if isinstance(parent_context, AnonymousInstance):
func = BoundMethod(
self, parent_context, parent_context.class_context,
parent_context.parent_context, scope_node
)
else:
func = FunctionContext(
self,
parent_context,
scope_node
instance=parent_context,
klass=parent_context.class_context,
function=func
)
if is_nested and not node_is_object:
return func.get_function_execution()

View File

@@ -168,9 +168,10 @@ def iterate_contexts(contexts, contextualized_node=None, is_async=False):
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)
self.predefined_names = {}
self.tree_node = tree_node
def __repr__(self):
return '<%s: %s>' % (self.__class__.__name__, self.tree_node)

View File

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

View File

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

View File

@@ -38,17 +38,9 @@ class LambdaName(AbstractNameDefinition):
return ContextSet(self._lambda_context)
class FunctionContext(use_metaclass(CachedMetaClass, TreeContext)):
"""
Needed because of decorators. Decorators are evaluated here.
"""
class AbstractFunction(TreeContext):
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):
if search_global:
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):
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):
"""
Created to be used by inheritance.
@@ -84,35 +94,28 @@ class FunctionContext(use_metaclass(CachedMetaClass, TreeContext)):
else:
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):
if arguments is None:
arguments = AnonymousArguments()
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):
# This differentiation is only necessary for Python2. Python3 does not
# 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()]
return compiled.get_special_object(self.evaluator, u'FUNCTION_CLASS')
class FunctionExecutionContext(TreeContext):
@@ -127,9 +130,12 @@ class FunctionExecutionContext(TreeContext):
function_execution_filter = FunctionExecutionFilter
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.tree_node = function_context.tree_node
self.var_args = var_args
@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.arguments import AbstractArguments, AnonymousArguments
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 import iterable
from jedi.parser_utils import get_parent_scope
@@ -158,10 +159,7 @@ class AbstractInstanceContext(Context):
def name(self):
pass
def _create_init_execution(self, class_context, func_node):
bound_method = BoundMethod(
self.evaluator, self, class_context, self.parent_context, func_node
)
def _create_init_execution(self, class_context, bound_method):
return self.function_execution_cls(
self,
class_context.parent_context,
@@ -172,7 +170,12 @@ class AbstractInstanceContext(Context):
def create_init_executions(self):
for name in self.get_function_slot_names(u'__init__'):
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()
def create_instance_context(self, class_context, node):
@@ -184,13 +187,14 @@ class AbstractInstanceContext(Context):
else:
parent_context = self.create_instance_context(class_context, scope)
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:
return self._create_init_execution(class_context, scope)
return self._create_init_execution(class_context, bound_method)
else:
bound_method = BoundMethod(
self.evaluator, self, class_context,
parent_context, scope
)
return bound_method.get_function_execution()
elif scope.type == 'classdef':
class_context = ClassContext(self.evaluator, parent_context, scope)
@@ -270,14 +274,8 @@ class CompiledInstanceName(compiled.CompiledName):
for result_context in super(CompiledInstanceName, self).infer():
is_function = result_context.api_type == '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(
result_context.evaluator, self._instance, self.parent_context,
parent_context, result_context.tree_node
)
yield BoundMethod(self._instance, self.parent_context, result_context)
else:
if is_function:
yield CompiledBoundMethod(result_context)
@@ -301,11 +299,19 @@ class CompiledInstanceClassFilter(compiled.CompiledObjectFilter):
self._evaluator, self._instance, self._compiled_object, name)
class BoundMethod(FunctionContext):
def __init__(self, evaluator, instance, class_context, *args, **kwargs):
super(BoundMethod, self).__init__(evaluator, *args, **kwargs)
class BoundMethod(AbstractFunction):
def __init__(self, instance, klass, function):
super(BoundMethod, self).__init__(
function.evaluator,
function.parent_context,
function.tree_node,
)
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):
if arguments is None:
@@ -353,14 +359,7 @@ class LazyInstanceClassName(SelfName):
# Classes are never used to resolve anything within the
# functions. Only other functions and modules will resolve
# those things.
parent_context = result_context.parent_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
)
yield BoundMethod(self._instance, self.class_context, result_context)
else:
for c in apply_py__get__(result_context, self._instance):
yield c

View File

@@ -83,10 +83,6 @@ class CompForContext(TreeContext):
def from_comp_for(cls, 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):
return self.tree_node

View File

@@ -89,10 +89,6 @@ class ClassContext(use_metaclass(CachedMetaClass, TreeContext)):
"""
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=())
def py__mro__(self):
def add(cls):

View File

@@ -43,8 +43,11 @@ class ModuleContext(TreeContext):
parent_context = None
def __init__(self, evaluator, module_node, path, code_lines):
super(ModuleContext, self).__init__(evaluator, parent_context=None)
self.tree_node = module_node
super(ModuleContext, self).__init__(
evaluator,
parent_context=None,
tree_node=module_node
)
self._path = path
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 import imports
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):
@@ -17,7 +17,7 @@ class ImplicitNSName(ContextNameMixin, AbstractNameDefinition):
self.string_name = string_name
class ImplicitNamespaceContext(TreeContext):
class ImplicitNamespaceContext(Context):
"""
Provides support for implicit namespace packages
"""

View File

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

View File

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

View File

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

View File

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

View File

@@ -77,10 +77,13 @@ def test_nested_namespace_package(Script):
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.
"""
if environment.version_info < (3, 4):
pytest.skip()
directory = get_example_dir('namespace_package_relative_import')
# Need to copy the content in a directory where there's no __init__.py.
py.path.local(directory).copy(tmpdir)

View File

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