forked from VimPlug/jedi
Merge branch 'pytest', fixes parts of #791
This commit is contained in:
@@ -21,6 +21,8 @@ Changelog
|
|||||||
- ``usages`` deprecated, use ``find_references`` instead
|
- ``usages`` deprecated, use ``find_references`` instead
|
||||||
- ``jedi.names`` deprecated, use ``jedi.Script(...).names()``
|
- ``jedi.names`` deprecated, use ``jedi.Script(...).names()``
|
||||||
- ``BaseDefinition.goto_assignments`` renamed to ``BaseDefinition.goto``
|
- ``BaseDefinition.goto_assignments`` renamed to ``BaseDefinition.goto``
|
||||||
|
- Python 2 support deprecated. For this release it is best effort. Python 2 has
|
||||||
|
reached the end of its life and now it's just about a smooth transition.
|
||||||
|
|
||||||
0.15.2 (2019-12-20)
|
0.15.2 (2019-12-20)
|
||||||
+++++++++++++++++++
|
+++++++++++++++++++
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ from jedi.inference.context import get_global_filters
|
|||||||
from jedi.inference.value import TreeInstance
|
from jedi.inference.value import TreeInstance
|
||||||
from jedi.inference.gradual.conversion import convert_values
|
from jedi.inference.gradual.conversion import convert_values
|
||||||
from jedi.parser_utils import cut_value_at_position
|
from jedi.parser_utils import cut_value_at_position
|
||||||
|
from jedi.plugins import plugin_manager
|
||||||
|
|
||||||
|
|
||||||
def get_signature_param_names(signatures):
|
def get_signature_param_names(signatures):
|
||||||
@@ -74,6 +75,13 @@ def get_flow_scope_node(module_node, position):
|
|||||||
return node
|
return node
|
||||||
|
|
||||||
|
|
||||||
|
@plugin_manager.decorate()
|
||||||
|
def complete_param_names(context, function_name, decorator_nodes):
|
||||||
|
# Basically there's no way to do param completion. The plugins are
|
||||||
|
# responsible for this.
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
class Completion:
|
class Completion:
|
||||||
def __init__(self, inference_state, module_context, code_lines, position,
|
def __init__(self, inference_state, module_context, code_lines, position,
|
||||||
signatures_callback, fuzzy=False):
|
signatures_callback, fuzzy=False):
|
||||||
@@ -216,6 +224,8 @@ class Completion:
|
|||||||
elif nonterminals[-1] in ('trailer', 'dotted_name') and nodes[-1] == '.':
|
elif nonterminals[-1] in ('trailer', 'dotted_name') and nodes[-1] == '.':
|
||||||
dot = self._module_node.get_leaf_for_position(self._position)
|
dot = self._module_node.get_leaf_for_position(self._position)
|
||||||
completion_names += self._complete_trailer(dot.get_previous_leaf())
|
completion_names += self._complete_trailer(dot.get_previous_leaf())
|
||||||
|
elif self._is_parameter_completion():
|
||||||
|
completion_names += self._complete_params(leaf)
|
||||||
else:
|
else:
|
||||||
completion_names += self._complete_global_scope()
|
completion_names += self._complete_global_scope()
|
||||||
completion_names += self._complete_inherited(is_function=False)
|
completion_names += self._complete_inherited(is_function=False)
|
||||||
@@ -234,6 +244,41 @@ class Completion:
|
|||||||
|
|
||||||
return completion_names
|
return completion_names
|
||||||
|
|
||||||
|
def _is_parameter_completion(self):
|
||||||
|
tos = self.stack[-1]
|
||||||
|
if tos.nonterminal == 'lambdef' and len(tos.nodes) == 1:
|
||||||
|
# We are at the position `lambda `, where basically the next node
|
||||||
|
# is a param.
|
||||||
|
return True
|
||||||
|
if tos.nonterminal in 'parameters':
|
||||||
|
# Basically we are at the position `foo(`, there's nothing there
|
||||||
|
# yet, so we have no `typedargslist`.
|
||||||
|
return True
|
||||||
|
# var args is for lambdas and typed args for normal functions
|
||||||
|
return tos.nonterminal in ('typedargslist', 'varargslist') and tos.nodes[-1] == ','
|
||||||
|
|
||||||
|
def _complete_params(self, leaf):
|
||||||
|
stack_node = self.stack[-2]
|
||||||
|
if stack_node.nonterminal == 'parameters':
|
||||||
|
stack_node = self.stack[-3]
|
||||||
|
if stack_node.nonterminal == 'funcdef':
|
||||||
|
context = get_user_context(self._module_context, self._position)
|
||||||
|
node = search_ancestor(leaf, 'error_node', 'funcdef')
|
||||||
|
if node.type == 'error_node':
|
||||||
|
n = node.children[0]
|
||||||
|
if n.type == 'decorators':
|
||||||
|
decorators = n.children
|
||||||
|
elif n.type == 'decorator':
|
||||||
|
decorators = [n]
|
||||||
|
else:
|
||||||
|
decorators = []
|
||||||
|
else:
|
||||||
|
decorators = node.get_decorators()
|
||||||
|
function_name = stack_node.nodes[1]
|
||||||
|
|
||||||
|
return complete_param_names(context, function_name.value, decorators)
|
||||||
|
return []
|
||||||
|
|
||||||
def _complete_keywords(self, allowed_transitions):
|
def _complete_keywords(self, allowed_transitions):
|
||||||
for k in allowed_transitions:
|
for k in allowed_transitions:
|
||||||
if isinstance(k, str) and k.isalpha():
|
if isinstance(k, str) and k.isalpha():
|
||||||
|
|||||||
@@ -13,6 +13,12 @@ class AbstractFolderIO(object):
|
|||||||
def get_file_io(self, name):
|
def get_file_io(self, name):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def get_parent_folder(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<%s: %s>' % (self.__class__.__name__, self.path)
|
||||||
|
|
||||||
|
|
||||||
class FolderIO(AbstractFolderIO):
|
class FolderIO(AbstractFolderIO):
|
||||||
def list(self):
|
def list(self):
|
||||||
@@ -21,6 +27,9 @@ class FolderIO(AbstractFolderIO):
|
|||||||
def get_file_io(self, name):
|
def get_file_io(self, name):
|
||||||
return FileIO(os.path.join(self.path, name))
|
return FileIO(os.path.join(self.path, name))
|
||||||
|
|
||||||
|
def get_parent_folder(self):
|
||||||
|
return FolderIO(os.path.dirname(self.path))
|
||||||
|
|
||||||
|
|
||||||
class FileIOFolderMixin(object):
|
class FileIOFolderMixin(object):
|
||||||
def get_parent_folder(self):
|
def get_parent_folder(self):
|
||||||
|
|||||||
@@ -169,6 +169,8 @@ class InferenceState(object):
|
|||||||
return imports.infer_import(context, name)
|
return imports.infer_import(context, name)
|
||||||
if type_ == 'with_stmt':
|
if type_ == 'with_stmt':
|
||||||
return tree_name_to_values(self, context, name)
|
return tree_name_to_values(self, context, name)
|
||||||
|
elif type_ == 'param':
|
||||||
|
return context.py__getattribute__(name.value, position=name.end_pos)
|
||||||
else:
|
else:
|
||||||
result = follow_error_node_imports_if_possible(context, name)
|
result = follow_error_node_imports_if_possible(context, name)
|
||||||
if result is not None:
|
if result is not None:
|
||||||
|
|||||||
@@ -246,24 +246,18 @@ class MergedFilter(object):
|
|||||||
return '%s(%s)' % (self.__class__.__name__, ', '.join(str(f) for f in self._filters))
|
return '%s(%s)' % (self.__class__.__name__, ', '.join(str(f) for f in self._filters))
|
||||||
|
|
||||||
|
|
||||||
class _BuiltinMappedMethod(Value):
|
class _BuiltinMappedMethod(ValueWrapper):
|
||||||
"""``Generator.__next__`` ``dict.values`` methods and so on."""
|
"""``Generator.__next__`` ``dict.values`` methods and so on."""
|
||||||
api_type = u'function'
|
api_type = u'function'
|
||||||
|
|
||||||
def __init__(self, builtin_value, method, builtin_func):
|
def __init__(self, value, method, builtin_func):
|
||||||
super(_BuiltinMappedMethod, self).__init__(
|
super(_BuiltinMappedMethod, self).__init__(builtin_func)
|
||||||
builtin_value.inference_state,
|
self._value = value
|
||||||
parent_context=builtin_value
|
|
||||||
)
|
|
||||||
self._method = method
|
self._method = method
|
||||||
self._builtin_func = builtin_func
|
|
||||||
|
|
||||||
def py__call__(self, arguments):
|
def py__call__(self, arguments):
|
||||||
# TODO add TypeError if params are given/or not correct.
|
# TODO add TypeError if params are given/or not correct.
|
||||||
return self._method(self.parent_context)
|
return self._method(self._value)
|
||||||
|
|
||||||
def __getattr__(self, name):
|
|
||||||
return getattr(self._builtin_func, name)
|
|
||||||
|
|
||||||
|
|
||||||
class SpecialMethodFilter(DictFilter):
|
class SpecialMethodFilter(DictFilter):
|
||||||
|
|||||||
@@ -322,6 +322,11 @@ class NewType(Value):
|
|||||||
def py__call__(self, arguments):
|
def py__call__(self, arguments):
|
||||||
return self._type_value_set.execute_annotation()
|
return self._type_value_set.execute_annotation()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
from jedi.inference.compiled.value import CompiledValueName
|
||||||
|
return CompiledValueName(self, 'NewType')
|
||||||
|
|
||||||
|
|
||||||
class CastFunction(BaseTypingValue):
|
class CastFunction(BaseTypingValue):
|
||||||
@repack_with_argument_clinic('type, object, /')
|
@repack_with_argument_clinic('type, object, /')
|
||||||
|
|||||||
@@ -505,7 +505,7 @@ def _load_builtin_module(inference_state, import_names=None, sys_path=None):
|
|||||||
return module
|
return module
|
||||||
|
|
||||||
|
|
||||||
def _load_module_from_path(inference_state, file_io, base_names):
|
def load_module_from_path(inference_state, file_io, base_names=None):
|
||||||
"""
|
"""
|
||||||
This should pretty much only be used for get_modules_containing_name. It's
|
This should pretty much only be used for get_modules_containing_name. It's
|
||||||
here to ensure that a random path is still properly loaded into the Jedi
|
here to ensure that a random path is still properly loaded into the Jedi
|
||||||
@@ -552,7 +552,7 @@ def get_module_contexts_containing_name(inference_state, module_contexts, name):
|
|||||||
if name not in code:
|
if name not in code:
|
||||||
return None
|
return None
|
||||||
new_file_io = KnownContentFileIO(file_io.path, code)
|
new_file_io = KnownContentFileIO(file_io.path, code)
|
||||||
m = _load_module_from_path(inference_state, new_file_io, base_names)
|
m = load_module_from_path(inference_state, new_file_io, base_names)
|
||||||
if isinstance(m, compiled.CompiledObject):
|
if isinstance(m, compiled.CompiledObject):
|
||||||
return None
|
return None
|
||||||
return m.as_context()
|
return m.as_context()
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from jedi.inference.base_value import ValueSet, NO_VALUES
|
|||||||
from jedi.inference import docstrings
|
from jedi.inference import docstrings
|
||||||
from jedi.cache import memoize_method
|
from jedi.cache import memoize_method
|
||||||
from jedi.inference.helpers import deep_ast_copy, infer_call_of_leaf
|
from jedi.inference.helpers import deep_ast_copy, infer_call_of_leaf
|
||||||
|
from jedi.plugins import plugin_manager
|
||||||
|
|
||||||
|
|
||||||
def _merge_name_docs(names):
|
def _merge_name_docs(names):
|
||||||
@@ -482,6 +483,11 @@ class _ActualTreeParamName(BaseTreeParamName):
|
|||||||
|
|
||||||
|
|
||||||
class AnonymousParamName(_ActualTreeParamName):
|
class AnonymousParamName(_ActualTreeParamName):
|
||||||
|
@plugin_manager.decorate(name='goto_anonymous_param')
|
||||||
|
def goto(self):
|
||||||
|
return super(AnonymousParamName, self).goto()
|
||||||
|
|
||||||
|
@plugin_manager.decorate(name='infer_anonymous_param')
|
||||||
def infer(self):
|
def infer(self):
|
||||||
values = super(AnonymousParamName, self).infer()
|
values = super(AnonymousParamName, self).infer()
|
||||||
if values:
|
if values:
|
||||||
|
|||||||
@@ -277,17 +277,19 @@ class BaseFunctionExecutionContext(ValueContext, TreeContextMixin):
|
|||||||
for lazy_value in self.get_yield_lazy_values()
|
for lazy_value in self.get_yield_lazy_values()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def is_generator(self):
|
||||||
|
return bool(get_yield_exprs(self.inference_state, self.tree_node))
|
||||||
|
|
||||||
def infer(self):
|
def infer(self):
|
||||||
"""
|
"""
|
||||||
Created to be used by inheritance.
|
Created to be used by inheritance.
|
||||||
"""
|
"""
|
||||||
inference_state = self.inference_state
|
inference_state = self.inference_state
|
||||||
is_coroutine = self.tree_node.parent.type in ('async_stmt', 'async_funcdef')
|
is_coroutine = self.tree_node.parent.type in ('async_stmt', 'async_funcdef')
|
||||||
is_generator = bool(get_yield_exprs(inference_state, self.tree_node))
|
|
||||||
from jedi.inference.gradual.base import GenericClass
|
from jedi.inference.gradual.base import GenericClass
|
||||||
|
|
||||||
if is_coroutine:
|
if is_coroutine:
|
||||||
if is_generator:
|
if self.is_generator():
|
||||||
if inference_state.environment.version_info < (3, 6):
|
if inference_state.environment.version_info < (3, 6):
|
||||||
return NO_VALUES
|
return NO_VALUES
|
||||||
async_generator_classes = inference_state.typing_module \
|
async_generator_classes = inference_state.typing_module \
|
||||||
@@ -312,7 +314,7 @@ class BaseFunctionExecutionContext(ValueContext, TreeContextMixin):
|
|||||||
GenericClass(c, TupleGenericManager(generics)) for c in async_classes
|
GenericClass(c, TupleGenericManager(generics)) for c in async_classes
|
||||||
).execute_annotation()
|
).execute_annotation()
|
||||||
else:
|
else:
|
||||||
if is_generator:
|
if self.is_generator():
|
||||||
return ValueSet([iterable.Generator(inference_state, self)])
|
return ValueSet([iterable.Generator(inference_state, self)])
|
||||||
else:
|
else:
|
||||||
return self.get_return_values()
|
return self.get_return_values()
|
||||||
|
|||||||
@@ -14,18 +14,18 @@ class _PluginManager(object):
|
|||||||
self._registered_plugins.extend(plugins)
|
self._registered_plugins.extend(plugins)
|
||||||
self._build_functions()
|
self._build_functions()
|
||||||
|
|
||||||
def decorate(self):
|
def decorate(self, name=None):
|
||||||
def decorator(callback):
|
def decorator(callback):
|
||||||
@wraps(callback)
|
@wraps(callback)
|
||||||
def wrapper(*args, **kwargs):
|
def wrapper(*args, **kwargs):
|
||||||
return built_functions[name](*args, **kwargs)
|
return built_functions[public_name](*args, **kwargs)
|
||||||
|
|
||||||
name = callback.__name__
|
public_name = name or callback.__name__
|
||||||
|
|
||||||
assert name not in self._built_functions
|
assert public_name not in self._built_functions
|
||||||
built_functions = self._built_functions
|
built_functions = self._built_functions
|
||||||
built_functions[name] = callback
|
built_functions[public_name] = callback
|
||||||
self._cached_base_callbacks[name] = callback
|
self._cached_base_callbacks[public_name] = callback
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,133 @@
|
|||||||
|
from parso.python.tree import search_ancestor
|
||||||
|
from jedi._compatibility import FileNotFoundError
|
||||||
|
from jedi.inference.cache import inference_state_method_cache
|
||||||
|
from jedi.inference.imports import load_module_from_path
|
||||||
|
from jedi.inference.filters import ParserTreeFilter
|
||||||
|
from jedi.inference.base_value import NO_VALUES, ValueSet
|
||||||
|
|
||||||
|
|
||||||
|
def execute(callback):
|
||||||
|
def wrapper(value, arguments):
|
||||||
|
# This might not be necessary anymore in pytest 4/5, definitely needed
|
||||||
|
# for pytest 3.
|
||||||
|
if value.py__name__() == 'fixture' \
|
||||||
|
and value.parent_context.py__name__() == '_pytest.fixtures':
|
||||||
|
return NO_VALUES
|
||||||
|
|
||||||
|
return callback(value, arguments)
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
def infer_anonymous_param(func):
|
||||||
|
def get_returns(value):
|
||||||
|
if value.tree_node.annotation is not None:
|
||||||
|
return value.execute_with_values()
|
||||||
|
|
||||||
|
# In pytest we need to differentiate between generators and normal
|
||||||
|
# returns.
|
||||||
|
# Parameters still need to be anonymous, .as_context() ensures that.
|
||||||
|
function_context = value.as_context()
|
||||||
|
if function_context.is_generator():
|
||||||
|
return function_context.merge_yield_values()
|
||||||
|
else:
|
||||||
|
return function_context.get_return_values()
|
||||||
|
|
||||||
|
def wrapper(param_name):
|
||||||
|
if _is_a_pytest_param(param_name):
|
||||||
|
module = param_name.get_root_context()
|
||||||
|
fixtures = _goto_pytest_fixture(module, param_name.string_name)
|
||||||
|
if fixtures:
|
||||||
|
return ValueSet.from_sets(
|
||||||
|
get_returns(value)
|
||||||
|
for fixture in fixtures
|
||||||
|
for value in fixture.infer()
|
||||||
|
)
|
||||||
|
return func(param_name)
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
def goto_anonymous_param(func):
|
||||||
|
def wrapper(param_name):
|
||||||
|
if _is_a_pytest_param(param_name):
|
||||||
|
names = _goto_pytest_fixture(param_name.get_root_context(), param_name.string_name)
|
||||||
|
if names:
|
||||||
|
return names
|
||||||
|
return func(param_name)
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
def complete_param_names(func):
|
||||||
|
def wrapper(context, func_name, decorator_nodes):
|
||||||
|
module_context = context.get_root_context()
|
||||||
|
if _is_pytest_func(func_name, decorator_nodes):
|
||||||
|
names = []
|
||||||
|
for module_context in _iter_pytest_modules(module_context):
|
||||||
|
names += FixtureFilter(module_context).values()
|
||||||
|
if names:
|
||||||
|
return names
|
||||||
|
return func(context, func_name, decorator_nodes)
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
def _goto_pytest_fixture(module_context, name):
|
||||||
|
for module_context in _iter_pytest_modules(module_context):
|
||||||
|
names = FixtureFilter(module_context).get(name)
|
||||||
|
if names:
|
||||||
|
return names
|
||||||
|
|
||||||
|
|
||||||
|
def _is_a_pytest_param(param_name):
|
||||||
|
"""
|
||||||
|
Pytest params are either in a `test_*` function or have a pytest fixture
|
||||||
|
with the decorator @pytest.fixture.
|
||||||
|
|
||||||
|
This is a heuristic and will work in most cases.
|
||||||
|
"""
|
||||||
|
funcdef = search_ancestor(param_name.tree_name, 'funcdef')
|
||||||
|
if funcdef is None: # A lambda
|
||||||
|
return False
|
||||||
|
decorators = funcdef.get_decorators()
|
||||||
|
return _is_pytest_func(funcdef.name.value, decorators)
|
||||||
|
|
||||||
|
|
||||||
|
def _is_pytest_func(func_name, decorator_nodes):
|
||||||
|
return func_name.startswith('test_') \
|
||||||
|
or any('fixture' in n.get_code() for n in decorator_nodes)
|
||||||
|
|
||||||
|
|
||||||
|
@inference_state_method_cache()
|
||||||
|
def _iter_pytest_modules(module_context):
|
||||||
|
yield module_context
|
||||||
|
|
||||||
|
folder = module_context.get_value().file_io.get_parent_folder()
|
||||||
|
sys_path = module_context.inference_state.get_sys_path()
|
||||||
|
while any(folder.path.startswith(p) for p in sys_path):
|
||||||
|
file_io = folder.get_file_io('conftest.py')
|
||||||
|
try:
|
||||||
|
m = load_module_from_path(module_context.inference_state, file_io)
|
||||||
|
yield m.as_context()
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
folder = folder.get_parent_folder()
|
||||||
|
|
||||||
|
|
||||||
|
class FixtureFilter(ParserTreeFilter):
|
||||||
|
def _filter(self, names):
|
||||||
|
for name in super(FixtureFilter, self)._filter(names):
|
||||||
|
funcdef = name.parent
|
||||||
|
if funcdef.type == 'funcdef':
|
||||||
|
# Class fixtures are not supported
|
||||||
|
decorated = funcdef.parent
|
||||||
|
if decorated.type == 'decorated' and self._is_fixture(decorated):
|
||||||
|
yield name
|
||||||
|
|
||||||
|
def _is_fixture(self, decorated):
|
||||||
|
for decorator in decorated.children:
|
||||||
|
dotted_name = decorator.children[1]
|
||||||
|
# A heuristic, this makes it faster.
|
||||||
|
if 'fixture' in dotted_name.get_code():
|
||||||
|
for value in self.parent_context.infer_node(dotted_name):
|
||||||
|
if value.name.get_qualified_names(include_module_names=True) \
|
||||||
|
== ('_pytest', 'fixtures', 'fixture'):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
@@ -4,7 +4,8 @@ This is not a plugin, this is just the place were plugins are registered.
|
|||||||
|
|
||||||
from jedi.plugins import stdlib
|
from jedi.plugins import stdlib
|
||||||
from jedi.plugins import flask
|
from jedi.plugins import flask
|
||||||
|
from jedi.plugins import pytest
|
||||||
from jedi.plugins import plugin_manager
|
from jedi.plugins import plugin_manager
|
||||||
|
|
||||||
|
|
||||||
plugin_manager.register(stdlib, flask)
|
plugin_manager.register(stdlib, flask, pytest)
|
||||||
|
|||||||
@@ -299,6 +299,56 @@ except MyException as e:
|
|||||||
for x in e.my_attr:
|
for x in e.my_attr:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# -----------------
|
||||||
|
# params
|
||||||
|
# -----------------
|
||||||
|
|
||||||
|
my_param = 1
|
||||||
|
#? 9 str()
|
||||||
|
def foo1(my_param):
|
||||||
|
my_param = 3.0
|
||||||
|
foo1("")
|
||||||
|
|
||||||
|
my_type = float()
|
||||||
|
#? 20 float()
|
||||||
|
def foo2(my_param: my_type):
|
||||||
|
pass
|
||||||
|
foo2("")
|
||||||
|
#? 20 int()
|
||||||
|
def foo3(my_param=my_param):
|
||||||
|
pass
|
||||||
|
foo3("")
|
||||||
|
|
||||||
|
some_default = ''
|
||||||
|
#? []
|
||||||
|
def foo(my_t
|
||||||
|
#? []
|
||||||
|
def foo(my_t, my_ty
|
||||||
|
#? ['some_default']
|
||||||
|
def foo(my_t=some_defa
|
||||||
|
#? ['some_default']
|
||||||
|
def foo(my_t=some_defa, my_t2=some_defa
|
||||||
|
|
||||||
|
# python > 2.7
|
||||||
|
|
||||||
|
#? ['my_type']
|
||||||
|
def foo(my_t: lala=some_defa, my_t2: my_typ
|
||||||
|
#? ['my_type']
|
||||||
|
def foo(my_t: lala=some_defa, my_t2: my_typ
|
||||||
|
#? []
|
||||||
|
def foo(my_t: lala=some_defa, my_t
|
||||||
|
|
||||||
|
#? []
|
||||||
|
lambda my_t
|
||||||
|
#? []
|
||||||
|
lambda my_, my_t
|
||||||
|
#? ['some_default']
|
||||||
|
lambda x=some_defa
|
||||||
|
#? ['some_default']
|
||||||
|
lambda y, x=some_defa
|
||||||
|
|
||||||
|
# Just make sure we're not in some weird parsing recovery after opening brackets
|
||||||
|
def
|
||||||
|
|
||||||
# -----------------
|
# -----------------
|
||||||
# continuations
|
# continuations
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ tuple
|
|||||||
class MyClass:
|
class MyClass:
|
||||||
@pass_decorator
|
@pass_decorator
|
||||||
def x(foo,
|
def x(foo,
|
||||||
#? 5 ["tuple"]
|
#? 5 []
|
||||||
tuple,
|
tuple,
|
||||||
):
|
):
|
||||||
return 1
|
return 1
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# Exists only for completion/pytest.py
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def my_other_conftest_fixture():
|
||||||
|
return 1.0
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def my_conftest_fixture(my_other_conftest_fixture):
|
||||||
|
return my_other_conftest_fixture
|
||||||
|
|
||||||
|
|
||||||
|
def my_not_existing_fixture():
|
||||||
|
return 3 # Just a normal function
|
||||||
@@ -40,4 +40,4 @@ str(def
|
|||||||
class Foo(object):
|
class Foo(object):
|
||||||
@property
|
@property
|
||||||
#? ['str']
|
#? ['str']
|
||||||
def bar(str
|
def bar(x=str
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
# python > 2.7
|
||||||
|
import pytest
|
||||||
|
from pytest import fixture
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope='module')
|
||||||
|
def my_fixture() -> str:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@fixture
|
||||||
|
def my_simple_fixture():
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
@fixture
|
||||||
|
def my_yield_fixture():
|
||||||
|
yield 1
|
||||||
|
|
||||||
|
|
||||||
|
@fixture
|
||||||
|
class MyClassFixture():
|
||||||
|
pass
|
||||||
|
|
||||||
|
# -----------------
|
||||||
|
# goto/infer
|
||||||
|
# -----------------
|
||||||
|
|
||||||
|
#! 18 ['def my_conftest_fixture']
|
||||||
|
def test_x(my_conftest_fixture, my_fixture, my_not_existing_fixture, my_yield_fixture):
|
||||||
|
#? str()
|
||||||
|
my_fixture
|
||||||
|
#? int()
|
||||||
|
my_yield_fixture
|
||||||
|
#?
|
||||||
|
my_not_existing_fixture
|
||||||
|
#? float()
|
||||||
|
return my_conftest_fixture
|
||||||
|
|
||||||
|
#? 18 float()
|
||||||
|
def test_x(my_conftest_fixture, my_fixture):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
#! 18 ['param MyClassFixture']
|
||||||
|
def test_x(MyClassFixture):
|
||||||
|
#?
|
||||||
|
MyClassFixture
|
||||||
|
|
||||||
|
#? 15
|
||||||
|
def lala(my_fixture):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
#? 15 str()
|
||||||
|
def lala(my_fixture):
|
||||||
|
pass
|
||||||
|
|
||||||
|
#! 15 ['param my_fixture']
|
||||||
|
def lala(my_fixture):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
#! 15 ['def my_fixture']
|
||||||
|
def lala(my_fixture):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# -----------------
|
||||||
|
# completion
|
||||||
|
# -----------------
|
||||||
|
|
||||||
|
#? 34 ['my_fixture']
|
||||||
|
def test_x(my_simple_fixture, my_fixture):
|
||||||
|
return
|
||||||
|
#? 34 ['my_fixture']
|
||||||
|
def test_x(my_simple_fixture, my_fixture):
|
||||||
|
return
|
||||||
|
#? ['my_fixture']
|
||||||
|
def test_x(my_simple_fixture, my_f
|
||||||
|
return
|
||||||
|
#? 18 ['my_simple_fixture']
|
||||||
|
def test_x(my_simple_fixture):
|
||||||
|
return
|
||||||
|
#? ['my_simple_fixture']
|
||||||
|
def test_x(my_simp
|
||||||
|
return
|
||||||
|
#? ['my_conftest_fixture']
|
||||||
|
def test_x(my_con
|
||||||
|
return
|
||||||
|
#? 18 ['my_conftest_fixture']
|
||||||
|
def test_x(my_conftest_fixture):
|
||||||
|
return
|
||||||
|
|
||||||
|
#? []
|
||||||
|
def lala(my_con
|
||||||
|
return
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
#? ['my_conftest_fixture']
|
||||||
|
def lala(my_con
|
||||||
|
return
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
#? 15 ['my_conftest_fixture']
|
||||||
|
def lala(my_con):
|
||||||
|
return
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
@some_decorator
|
||||||
|
#? ['my_conftest_fixture']
|
||||||
|
def lala(my_con
|
||||||
|
return
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
@some_decorator
|
||||||
|
#? 15 ['my_conftest_fixture']
|
||||||
|
def lala(my_con):
|
||||||
|
return
|
||||||
@@ -342,7 +342,7 @@ def test_get_modules_containing_name(inference_state, path, goal, is_package):
|
|||||||
)
|
)
|
||||||
def test_load_module_from_path(inference_state, path, base_names, is_package, names):
|
def test_load_module_from_path(inference_state, path, base_names, is_package, names):
|
||||||
file_io = KnownContentFileIO(path, '')
|
file_io = KnownContentFileIO(path, '')
|
||||||
m = imports._load_module_from_path(inference_state, file_io, base_names)
|
m = imports.load_module_from_path(inference_state, file_io, base_names)
|
||||||
assert m.is_package() == is_package
|
assert m.is_package() == is_package
|
||||||
assert m.string_names == names
|
assert m.string_names == names
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user