mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-07 06:24:27 +08:00
Merge branch 'master' into relative-import
This commit is contained in:
13
.travis.yml
13
.travis.yml
@@ -8,6 +8,7 @@ python:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
- JEDI_TEST_ENVIRONMENT=38
|
- JEDI_TEST_ENVIRONMENT=38
|
||||||
|
- JEDI_TEST_ENVIRONMENT=39
|
||||||
- JEDI_TEST_ENVIRONMENT=37
|
- JEDI_TEST_ENVIRONMENT=37
|
||||||
- JEDI_TEST_ENVIRONMENT=36
|
- JEDI_TEST_ENVIRONMENT=36
|
||||||
- JEDI_TEST_ENVIRONMENT=interpreter
|
- JEDI_TEST_ENVIRONMENT=interpreter
|
||||||
@@ -47,9 +48,15 @@ script:
|
|||||||
# Only required for JEDI_TEST_ENVIRONMENT=38, because it's not always
|
# Only required for JEDI_TEST_ENVIRONMENT=38, because it's not always
|
||||||
# available.
|
# available.
|
||||||
download_name=python-$test_env_version
|
download_name=python-$test_env_version
|
||||||
wget https://s3.amazonaws.com/travis-python-archives/binaries/ubuntu/16.04/x86_64/$download_name.tar.bz2
|
if [ "$JEDI_TEST_ENVIRONMENT" == "39" ]; then
|
||||||
sudo tar xjf $download_name.tar.bz2 --directory / opt/python
|
wget https://storage.googleapis.com/travis-ci-language-archives/python/binaries/ubuntu/16.04/x86_64/python-3.9-dev.tar.bz2
|
||||||
ln -s "/opt/python/${test_env_version}/bin/python" /home/travis/bin/$python_bin
|
sudo tar xjf python-3.9-dev.tar.bz2 --directory / opt/python
|
||||||
|
ln -s "/opt/python/3.9-dev/bin/python" /home/travis/bin/python3.9
|
||||||
|
else
|
||||||
|
wget https://s3.amazonaws.com/travis-python-archives/binaries/ubuntu/16.04/x86_64/$download_name.tar.bz2
|
||||||
|
sudo tar xjf $download_name.tar.bz2 --directory / opt/python
|
||||||
|
ln -s "/opt/python/${test_env_version}/bin/python" /home/travis/bin/$python_bin
|
||||||
|
fi
|
||||||
elif [ "${python_path#/opt/pyenv/shims}" != "$python_path" ]; then
|
elif [ "${python_path#/opt/pyenv/shims}" != "$python_path" ]; then
|
||||||
# Activate pyenv version (required with JEDI_TEST_ENVIRONMENT=36).
|
# Activate pyenv version (required with JEDI_TEST_ENVIRONMENT=36).
|
||||||
pyenv_bin="$(pyenv whence --path "$python_bin" | head -n1)"
|
pyenv_bin="$(pyenv whence --path "$python_bin" | head -n1)"
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ class Script:
|
|||||||
self._module_node, code = self._inference_state.parse_and_get_code(
|
self._module_node, code = self._inference_state.parse_and_get_code(
|
||||||
code=code,
|
code=code,
|
||||||
path=self.path,
|
path=self.path,
|
||||||
use_latest_grammar=path and path.suffix == 'pyi',
|
use_latest_grammar=path and path.suffix == '.pyi',
|
||||||
cache=False, # No disk cache, because the current script often changes.
|
cache=False, # No disk cache, because the current script often changes.
|
||||||
diff_cache=settings.fast_parser,
|
diff_cache=settings.fast_parser,
|
||||||
cache_path=settings.cache_directory,
|
cache_path=settings.cache_directory,
|
||||||
@@ -196,6 +196,7 @@ class Script:
|
|||||||
# We are in a stub file. Try to load the stub properly.
|
# We are in a stub file. Try to load the stub properly.
|
||||||
stub_module = load_proper_stub_module(
|
stub_module = load_proper_stub_module(
|
||||||
self._inference_state,
|
self._inference_state,
|
||||||
|
self._inference_state.latest_grammar,
|
||||||
file_io,
|
file_io,
|
||||||
names,
|
names,
|
||||||
self._module_node
|
self._module_node
|
||||||
@@ -281,6 +282,11 @@ class Script:
|
|||||||
leaf = self._module_node.get_leaf_for_position(pos)
|
leaf = self._module_node.get_leaf_for_position(pos)
|
||||||
if leaf is None or leaf.type == 'string':
|
if leaf is None or leaf.type == 'string':
|
||||||
return []
|
return []
|
||||||
|
if leaf.end_pos == (line, column) and leaf.type == 'operator':
|
||||||
|
next_ = leaf.get_next_leaf()
|
||||||
|
if next_.start_pos == leaf.end_pos \
|
||||||
|
and next_.type in ('number', 'string', 'keyword'):
|
||||||
|
leaf = next_
|
||||||
|
|
||||||
context = self._get_module_context().create_context(leaf)
|
context = self._get_module_context().create_context(leaf)
|
||||||
|
|
||||||
|
|||||||
@@ -749,6 +749,24 @@ class Completion(BaseName):
|
|||||||
|
|
||||||
return super().type
|
return super().type
|
||||||
|
|
||||||
|
def get_completion_prefix_length(self):
|
||||||
|
"""
|
||||||
|
Returns the length of the prefix being completed.
|
||||||
|
For example, completing ``isinstance``::
|
||||||
|
|
||||||
|
isinstan# <-- Cursor is here
|
||||||
|
|
||||||
|
would return 8, because len('isinstan') == 8.
|
||||||
|
|
||||||
|
Assuming the following function definition::
|
||||||
|
|
||||||
|
def foo(param=0):
|
||||||
|
pass
|
||||||
|
|
||||||
|
completing ``foo(par`` would return 3.
|
||||||
|
"""
|
||||||
|
return self._like_name_length
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<%s: %s>' % (type(self).__name__, self._name.get_public_name())
|
return '<%s: %s>' % (type(self).__name__, self._name.get_public_name())
|
||||||
|
|
||||||
|
|||||||
@@ -366,8 +366,11 @@ class Project:
|
|||||||
|
|
||||||
def _is_potential_project(path):
|
def _is_potential_project(path):
|
||||||
for name in _CONTAINS_POTENTIAL_PROJECT:
|
for name in _CONTAINS_POTENTIAL_PROJECT:
|
||||||
if path.joinpath(name).exists():
|
try:
|
||||||
return True
|
if path.joinpath(name).exists():
|
||||||
|
return True
|
||||||
|
except OSError:
|
||||||
|
continue
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -324,8 +324,7 @@ class CompiledName(AbstractNameDefinition):
|
|||||||
self.string_name = name
|
self.string_name = name
|
||||||
|
|
||||||
def py__doc__(self):
|
def py__doc__(self):
|
||||||
value, = self.infer()
|
return self.infer_compiled_value().py__doc__()
|
||||||
return value.py__doc__()
|
|
||||||
|
|
||||||
def _get_qualified_names(self):
|
def _get_qualified_names(self):
|
||||||
parent_qualified_names = self.parent_context.get_qualified_names()
|
parent_qualified_names = self.parent_context.get_qualified_names()
|
||||||
@@ -349,16 +348,12 @@ class CompiledName(AbstractNameDefinition):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def api_type(self):
|
def api_type(self):
|
||||||
api = self.infer()
|
return self.infer_compiled_value().api_type
|
||||||
# If we can't find the type, assume it is an instance variable
|
|
||||||
if not api:
|
|
||||||
return "instance"
|
|
||||||
return next(iter(api)).api_type
|
|
||||||
|
|
||||||
@memoize_method
|
|
||||||
def infer(self):
|
def infer(self):
|
||||||
return ValueSet([self.infer_compiled_value()])
|
return ValueSet([self.infer_compiled_value()])
|
||||||
|
|
||||||
|
@memoize_method
|
||||||
def infer_compiled_value(self):
|
def infer_compiled_value(self):
|
||||||
return create_from_name(self._inference_state, self._parent_value, self.string_name)
|
return create_from_name(self._inference_state, self._parent_value, self.string_name)
|
||||||
|
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ def _expand_typestr(type_str):
|
|||||||
elif type_str.startswith('{'):
|
elif type_str.startswith('{'):
|
||||||
node = parse(type_str, version='3.7').children[0]
|
node = parse(type_str, version='3.7').children[0]
|
||||||
if node.type == 'atom':
|
if node.type == 'atom':
|
||||||
for leaf in node.children[1].children:
|
for leaf in getattr(node.children[1], "children", []):
|
||||||
if leaf.type == 'number':
|
if leaf.type == 'number':
|
||||||
if '.' in leaf.value:
|
if '.' in leaf.value:
|
||||||
yield 'float'
|
yield 'float'
|
||||||
|
|||||||
@@ -279,8 +279,8 @@ def _try_to_load_stub_from_file(inference_state, python_value_set, file_io, impo
|
|||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
return create_stub_module(
|
return create_stub_module(
|
||||||
inference_state, python_value_set, stub_module_node, file_io,
|
inference_state, inference_state.latest_grammar, python_value_set,
|
||||||
import_names
|
stub_module_node, file_io, import_names
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -294,7 +294,8 @@ def parse_stub_module(inference_state, file_io):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def create_stub_module(inference_state, python_value_set, stub_module_node, file_io, import_names):
|
def create_stub_module(inference_state, grammar, python_value_set,
|
||||||
|
stub_module_node, file_io, import_names):
|
||||||
if import_names == ('typing',):
|
if import_names == ('typing',):
|
||||||
module_cls = TypingModuleWrapper
|
module_cls = TypingModuleWrapper
|
||||||
else:
|
else:
|
||||||
@@ -306,7 +307,7 @@ def create_stub_module(inference_state, python_value_set, stub_module_node, file
|
|||||||
string_names=import_names,
|
string_names=import_names,
|
||||||
# The code was loaded with latest_grammar, so use
|
# The code was loaded with latest_grammar, so use
|
||||||
# that.
|
# that.
|
||||||
code_lines=get_cached_code_lines(inference_state.latest_grammar, file_io.path),
|
code_lines=get_cached_code_lines(grammar, file_io.path),
|
||||||
is_package=file_name == '__init__.pyi',
|
is_package=file_name == '__init__.pyi',
|
||||||
)
|
)
|
||||||
return stub_module_value
|
return stub_module_value
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from pathlib import Path
|
|||||||
from jedi.inference.gradual.typeshed import TYPESHED_PATH, create_stub_module
|
from jedi.inference.gradual.typeshed import TYPESHED_PATH, create_stub_module
|
||||||
|
|
||||||
|
|
||||||
def load_proper_stub_module(inference_state, file_io, import_names, module_node):
|
def load_proper_stub_module(inference_state, grammar, file_io, import_names, module_node):
|
||||||
"""
|
"""
|
||||||
This function is given a random .pyi file and should return the proper
|
This function is given a random .pyi file and should return the proper
|
||||||
module.
|
module.
|
||||||
@@ -27,7 +27,8 @@ def load_proper_stub_module(inference_state, file_io, import_names, module_node)
|
|||||||
actual_value_set = inference_state.import_module(import_names, prefer_stubs=False)
|
actual_value_set = inference_state.import_module(import_names, prefer_stubs=False)
|
||||||
|
|
||||||
stub = create_stub_module(
|
stub = create_stub_module(
|
||||||
inference_state, actual_value_set, module_node, file_io, import_names
|
inference_state, grammar, actual_value_set,
|
||||||
|
module_node, file_io, import_names
|
||||||
)
|
)
|
||||||
inference_state.stub_module_cache[import_names] = stub
|
inference_state.stub_module_cache[import_names] = stub
|
||||||
return stub
|
return stub
|
||||||
|
|||||||
@@ -533,8 +533,8 @@ def load_module_from_path(inference_state, file_io, import_names=None, is_packag
|
|||||||
values = NO_VALUES
|
values = NO_VALUES
|
||||||
|
|
||||||
return create_stub_module(
|
return create_stub_module(
|
||||||
inference_state, values, parse_stub_module(inference_state, file_io),
|
inference_state, inference_state.latest_grammar, values,
|
||||||
file_io, import_names
|
parse_stub_module(inference_state, file_io), file_io, import_names
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
module = _load_python_module(
|
module = _load_python_module(
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from parso.tree import search_ancestor
|
|||||||
from jedi.parser_utils import find_statement_documentation, clean_scope_docstring
|
from jedi.parser_utils import find_statement_documentation, clean_scope_docstring
|
||||||
from jedi.inference.utils import unite
|
from jedi.inference.utils import unite
|
||||||
from jedi.inference.base_value import ValueSet, NO_VALUES
|
from jedi.inference.base_value import ValueSet, NO_VALUES
|
||||||
|
from jedi.inference.cache import inference_state_method_cache
|
||||||
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
|
||||||
@@ -331,6 +332,12 @@ class TreeNameDefinition(AbstractTreeName):
|
|||||||
node = node.parent
|
node = node.parent
|
||||||
return indexes
|
return indexes
|
||||||
|
|
||||||
|
@property
|
||||||
|
def inference_state(self):
|
||||||
|
# Used by the cache function below
|
||||||
|
return self.parent_context.inference_state
|
||||||
|
|
||||||
|
@inference_state_method_cache(default='')
|
||||||
def py__doc__(self):
|
def py__doc__(self):
|
||||||
api_type = self.api_type
|
api_type = self.api_type
|
||||||
if api_type in ('function', 'class'):
|
if api_type in ('function', 'class'):
|
||||||
|
|||||||
@@ -171,8 +171,11 @@ def _get_paths_from_buildout_script(inference_state, buildout_script_path):
|
|||||||
|
|
||||||
def _get_parent_dir_with_file(path: Path, filename):
|
def _get_parent_dir_with_file(path: Path, filename):
|
||||||
for parent in path.parents:
|
for parent in path.parents:
|
||||||
if parent.joinpath(filename).is_file():
|
try:
|
||||||
return parent
|
if parent.joinpath(filename).is_file():
|
||||||
|
return parent
|
||||||
|
except OSError:
|
||||||
|
continue
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -401,21 +401,10 @@ class AnonymousInstance(_BaseTreeInstance):
|
|||||||
_arguments = None
|
_arguments = None
|
||||||
|
|
||||||
|
|
||||||
class CompiledInstanceName(compiled.CompiledName):
|
class CompiledInstanceName(NameWrapper):
|
||||||
def __init__(self, inference_state, instance, klass, name):
|
|
||||||
parent_value = klass.parent_context.get_value()
|
|
||||||
assert parent_value is not None, "How? Please reproduce and report"
|
|
||||||
super().__init__(
|
|
||||||
inference_state,
|
|
||||||
parent_value,
|
|
||||||
name.string_name
|
|
||||||
)
|
|
||||||
self._instance = instance
|
|
||||||
self._class_member_name = name
|
|
||||||
|
|
||||||
@iterator_to_value_set
|
@iterator_to_value_set
|
||||||
def infer(self):
|
def infer(self):
|
||||||
for result_value in self._class_member_name.infer():
|
for result_value in self._wrapped_name.infer():
|
||||||
if result_value.api_type == 'function':
|
if result_value.api_type == 'function':
|
||||||
yield CompiledBoundMethod(result_value)
|
yield CompiledBoundMethod(result_value)
|
||||||
else:
|
else:
|
||||||
@@ -434,11 +423,7 @@ class CompiledInstanceClassFilter(AbstractFilter):
|
|||||||
return self._convert(self._class_filter.values())
|
return self._convert(self._class_filter.values())
|
||||||
|
|
||||||
def _convert(self, names):
|
def _convert(self, names):
|
||||||
klass = self._class_filter.compiled_value
|
return [CompiledInstanceName(n) for n in names]
|
||||||
return [
|
|
||||||
CompiledInstanceName(self._instance.inference_state, self._instance, klass, n)
|
|
||||||
for n in names
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class BoundMethod(FunctionMixin, ValueWrapper):
|
class BoundMethod(FunctionMixin, ValueWrapper):
|
||||||
@@ -516,6 +501,18 @@ class SelfName(TreeNameDefinition):
|
|||||||
def get_defining_qualified_value(self):
|
def get_defining_qualified_value(self):
|
||||||
return self._instance
|
return self._instance
|
||||||
|
|
||||||
|
def infer(self):
|
||||||
|
stmt = search_ancestor(self.tree_name, 'expr_stmt')
|
||||||
|
if stmt is not None:
|
||||||
|
if stmt.children[1].type == "annassign":
|
||||||
|
from jedi.inference.gradual.annotation import infer_annotation
|
||||||
|
values = infer_annotation(
|
||||||
|
self.parent_context, stmt.children[1].children[1]
|
||||||
|
).execute_annotation()
|
||||||
|
if values:
|
||||||
|
return values
|
||||||
|
return super().infer()
|
||||||
|
|
||||||
|
|
||||||
class LazyInstanceClassName(NameWrapper):
|
class LazyInstanceClassName(NameWrapper):
|
||||||
def __init__(self, instance, class_member_name):
|
def __init__(self, instance, class_member_name):
|
||||||
|
|||||||
@@ -819,7 +819,8 @@ def get_metaclass_filters(func):
|
|||||||
and metaclass.get_root_context().py__name__() == 'enum':
|
and metaclass.get_root_context().py__name__() == 'enum':
|
||||||
filter_ = ParserTreeFilter(parent_context=cls.as_context())
|
filter_ = ParserTreeFilter(parent_context=cls.as_context())
|
||||||
return [DictFilter({
|
return [DictFilter({
|
||||||
name.string_name: EnumInstance(cls, name).name for name in filter_.values()
|
name.string_name: EnumInstance(cls, name).name
|
||||||
|
for name in filter_.values()
|
||||||
})]
|
})]
|
||||||
return func(cls, metaclasses, is_instance)
|
return func(cls, metaclasses, is_instance)
|
||||||
return wrapper
|
return wrapper
|
||||||
@@ -837,6 +838,14 @@ class EnumInstance(LazyValueWrapper):
|
|||||||
return ValueName(self, self._name.tree_name)
|
return ValueName(self, self._name.tree_name)
|
||||||
|
|
||||||
def _get_wrapped_value(self):
|
def _get_wrapped_value(self):
|
||||||
|
n = self._name.string_name
|
||||||
|
if n.startswith('__') and n.endswith('__') or self._name.api_type == 'function':
|
||||||
|
inferred = self._name.infer()
|
||||||
|
if inferred:
|
||||||
|
return next(iter(inferred))
|
||||||
|
o, = self.inference_state.builtins_module.py__getattribute__('object')
|
||||||
|
return o
|
||||||
|
|
||||||
value, = self._cls.execute_with_values()
|
value, = self._cls.execute_with_values()
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|||||||
@@ -179,3 +179,22 @@ def argskwargs(*args: int, **kwargs: float):
|
|||||||
next(iter(kwargs.keys()))
|
next(iter(kwargs.keys()))
|
||||||
#? float()
|
#? float()
|
||||||
kwargs['']
|
kwargs['']
|
||||||
|
|
||||||
|
|
||||||
|
class NotCalledClass:
|
||||||
|
def __init__(self, x):
|
||||||
|
self.x: int = x
|
||||||
|
self.y: int = ''
|
||||||
|
#? int()
|
||||||
|
self.x
|
||||||
|
#? int()
|
||||||
|
self.y
|
||||||
|
#? int()
|
||||||
|
self.y
|
||||||
|
self.z: int
|
||||||
|
self.z = ''
|
||||||
|
#? str() int()
|
||||||
|
self.z
|
||||||
|
self.w: float
|
||||||
|
#? float()
|
||||||
|
self.w
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
from .cq import selectors
|
||||||
1
test/examples/import-recursion/cadquery_simple/cq.py
Normal file
1
test/examples/import-recursion/cadquery_simple/cq.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from . import selectors
|
||||||
3
test/examples/import-recursion/cq_example.py
Normal file
3
test/examples/import-recursion/cq_example.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import cadquery_simple as cq
|
||||||
|
|
||||||
|
cq.
|
||||||
@@ -370,3 +370,35 @@ def test_multi_goto(Script):
|
|||||||
y, = script.goto(line=4)
|
y, = script.goto(line=4)
|
||||||
assert x.line == 1
|
assert x.line == 1
|
||||||
assert y.line == 2
|
assert y.line == 2
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'code, column, expected', [
|
||||||
|
('str() ', 3, 'str'),
|
||||||
|
('str() ', 4, 'str'),
|
||||||
|
('str() ', 5, 'str'),
|
||||||
|
('str() ', 6, None),
|
||||||
|
('str( ) ', 6, None),
|
||||||
|
(' 1', 1, None),
|
||||||
|
('str(1) ', 3, 'str'),
|
||||||
|
('str(1) ', 4, 'int'),
|
||||||
|
('str(1) ', 5, 'int'),
|
||||||
|
('str(1) ', 6, 'str'),
|
||||||
|
('str(1) ', 7, None),
|
||||||
|
('str( 1) ', 4, 'str'),
|
||||||
|
('str( 1) ', 5, 'int'),
|
||||||
|
('str(+1) ', 4, 'str'),
|
||||||
|
('str(+1) ', 5, 'int'),
|
||||||
|
('str(1, 1.) ', 3, 'str'),
|
||||||
|
('str(1, 1.) ', 4, 'int'),
|
||||||
|
('str(1, 1.) ', 5, 'int'),
|
||||||
|
('str(1, 1.) ', 6, None),
|
||||||
|
('str(1, 1.) ', 7, 'float'),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
def test_infer_after_parentheses(Script, code, column, expected):
|
||||||
|
completions = Script(code).infer(column=column)
|
||||||
|
if expected is None:
|
||||||
|
assert completions == []
|
||||||
|
else:
|
||||||
|
assert [c.name for c in completions] == [expected]
|
||||||
|
|||||||
@@ -513,10 +513,14 @@ def test_added_equals_to_params(Script):
|
|||||||
|
|
||||||
assert run('foo(bar').name_with_symbols == 'bar='
|
assert run('foo(bar').name_with_symbols == 'bar='
|
||||||
assert run('foo(bar').complete == '='
|
assert run('foo(bar').complete == '='
|
||||||
|
assert run('foo(bar').get_completion_prefix_length() == 3
|
||||||
assert run('foo(bar, baz').complete == '='
|
assert run('foo(bar, baz').complete == '='
|
||||||
|
assert run('foo(bar, baz').get_completion_prefix_length() == 3
|
||||||
assert run(' bar').name_with_symbols == 'bar'
|
assert run(' bar').name_with_symbols == 'bar'
|
||||||
assert run(' bar').complete == ''
|
assert run(' bar').complete == ''
|
||||||
|
assert run(' bar').get_completion_prefix_length() == 3
|
||||||
x = run('foo(bar=isins').name_with_symbols
|
x = run('foo(bar=isins').name_with_symbols
|
||||||
|
assert run('foo(bar=isins').get_completion_prefix_length() == 5
|
||||||
assert x == 'isinstance'
|
assert x == 'isinstance'
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import pytest
|
|||||||
from ..helpers import get_example_dir, set_cwd, root_dir, test_dir
|
from ..helpers import get_example_dir, set_cwd, root_dir, test_dir
|
||||||
from jedi import Interpreter
|
from jedi import Interpreter
|
||||||
from jedi.api import Project, get_default_project
|
from jedi.api import Project, get_default_project
|
||||||
|
from jedi.api.project import _is_potential_project, _CONTAINS_POTENTIAL_PROJECT
|
||||||
|
|
||||||
|
|
||||||
def test_django_default_project(Script):
|
def test_django_default_project(Script):
|
||||||
@@ -160,3 +161,21 @@ def test_complete_search(Script, string, completions, all_scopes):
|
|||||||
project = Project(test_dir)
|
project = Project(test_dir)
|
||||||
defs = project.complete_search(string, all_scopes=all_scopes)
|
defs = project.complete_search(string, all_scopes=all_scopes)
|
||||||
assert [d.complete for d in defs] == completions
|
assert [d.complete for d in defs] == completions
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'path,expected', [
|
||||||
|
(Path(__file__).parents[2], True), # The path of the project
|
||||||
|
(Path(__file__).parents[1], False), # The path of the tests, not a project
|
||||||
|
(Path.home(), None)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
def test_is_potential_project(path, expected):
|
||||||
|
|
||||||
|
if expected is None:
|
||||||
|
try:
|
||||||
|
expected = _CONTAINS_POTENTIAL_PROJECT in os.listdir(path)
|
||||||
|
except OSError:
|
||||||
|
expected = False
|
||||||
|
|
||||||
|
assert _is_potential_project(path) == expected
|
||||||
|
|||||||
@@ -206,6 +206,24 @@ def test_numpydoc_parameters_set_of_values():
|
|||||||
assert 'capitalize' in names
|
assert 'capitalize' in names
|
||||||
assert 'numerator' in names
|
assert 'numerator' in names
|
||||||
|
|
||||||
|
@pytest.mark.skipif(numpydoc_unavailable,
|
||||||
|
reason='numpydoc module is unavailable')
|
||||||
|
def test_numpydoc_parameters_set_single_value():
|
||||||
|
"""
|
||||||
|
This is found in numpy masked-array I'm not too sure what this means but should not crash
|
||||||
|
"""
|
||||||
|
s = dedent('''
|
||||||
|
def foobar(x, y):
|
||||||
|
"""
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
x : {var}, optional
|
||||||
|
"""
|
||||||
|
x.''')
|
||||||
|
names = [c.name for c in jedi.Script(s).complete()]
|
||||||
|
# just don't crash
|
||||||
|
assert names == []
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(numpydoc_unavailable,
|
@pytest.mark.skipif(numpydoc_unavailable,
|
||||||
reason='numpydoc module is unavailable')
|
reason='numpydoc module is unavailable')
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
|
from parso.cache import parser_cache
|
||||||
|
|
||||||
from test.helpers import root_dir
|
from test.helpers import root_dir
|
||||||
from jedi.api.project import Project
|
from jedi.api.project import Project
|
||||||
@@ -64,6 +65,17 @@ def test_goto_import(Script):
|
|||||||
assert not d.is_stub()
|
assert not d.is_stub()
|
||||||
|
|
||||||
|
|
||||||
|
def test_stub_get_line_code(Script):
|
||||||
|
code = 'from abc import ABC; ABC'
|
||||||
|
script = Script(code)
|
||||||
|
d, = script.goto(only_stubs=True)
|
||||||
|
assert d.get_line_code() == 'class ABC(metaclass=ABCMeta): ...\n'
|
||||||
|
del parser_cache[script._inference_state.latest_grammar._hashed][d.module_path]
|
||||||
|
d, = Script(path=d.module_path).goto(d.line, d.column, only_stubs=True)
|
||||||
|
assert d.is_stub()
|
||||||
|
assert d.get_line_code() == 'class ABC(metaclass=ABCMeta): ...\n'
|
||||||
|
|
||||||
|
|
||||||
def test_os_stat_result(Script):
|
def test_os_stat_result(Script):
|
||||||
d, = Script('import os; os.stat_result').goto()
|
d, = Script('import os; os.stat_result').goto()
|
||||||
assert d.is_stub()
|
assert d.is_stub()
|
||||||
|
|||||||
@@ -489,3 +489,9 @@ def test_relative_imports_without_path_and_setup_py(
|
|||||||
assert n.name == name
|
assert n.name == name
|
||||||
assert n.type == 'module'
|
assert n.type == 'module'
|
||||||
assert n.line == 1
|
assert n.line == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_import_recursion(Script):
|
||||||
|
path = get_example_dir('import-recursion', "cq_example.py")
|
||||||
|
for c in Script(path=path).complete(3, 3):
|
||||||
|
c.docstring()
|
||||||
|
|||||||
@@ -340,3 +340,20 @@ def test_overload(Script, code):
|
|||||||
x1, x2 = Script(code, path=os.path.join(dir_, 'foo.py')).get_signatures()
|
x1, x2 = Script(code, path=os.path.join(dir_, 'foo.py')).get_signatures()
|
||||||
assert x1.to_string() == 'with_overload(x: int, y: int) -> float'
|
assert x1.to_string() == 'with_overload(x: int, y: int) -> float'
|
||||||
assert x2.to_string() == 'with_overload(x: str, y: list) -> float'
|
assert x2.to_string() == 'with_overload(x: str, y: list) -> float'
|
||||||
|
|
||||||
|
|
||||||
|
def test_enum(Script):
|
||||||
|
script = Script('''\
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
class Planet(Enum):
|
||||||
|
MERCURY = (3.303e+23, 2.4397e6)
|
||||||
|
VENUS = (4.869e+24, 6.0518e6)
|
||||||
|
|
||||||
|
def __init__(self, mass, radius):
|
||||||
|
self.mass = mass # in kilograms
|
||||||
|
self.radius = radius # in meters
|
||||||
|
|
||||||
|
Planet.MERCURY''')
|
||||||
|
completion, = script.complete()
|
||||||
|
assert not completion.get_signatures()
|
||||||
|
|||||||
Reference in New Issue
Block a user