forked from VimPlug/jedi
Merge branch 'master' into dict
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
"""
|
||||
An import tree, for testing usages.
|
||||
An import tree, for testing references.
|
||||
"""
|
||||
|
||||
|
||||
@@ -10,8 +10,10 @@ import pytest
|
||||
from pytest import raises
|
||||
from parso import cache
|
||||
|
||||
from jedi._compatibility import unicode
|
||||
from jedi import preload_module
|
||||
from jedi.inference.gradual import typeshed
|
||||
from test.helpers import test_dir, get_example_dir
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info[0] == 2, reason="Ignore Python 2, EoL")
|
||||
@@ -54,29 +56,29 @@ def test_line_number_errors(Script):
|
||||
s = 'hello'
|
||||
# lines
|
||||
with raises(ValueError):
|
||||
Script(s, 2, 0)
|
||||
Script(s).complete(2, 0)
|
||||
with raises(ValueError):
|
||||
Script(s, 0, 0)
|
||||
Script(s).complete(0, 0)
|
||||
|
||||
# columns
|
||||
with raises(ValueError):
|
||||
Script(s, 1, len(s) + 1)
|
||||
Script(s).infer(1, len(s) + 1)
|
||||
with raises(ValueError):
|
||||
Script(s, 1, -1)
|
||||
Script(s).goto(1, -1)
|
||||
|
||||
# ok
|
||||
Script(s, 1, 0)
|
||||
Script(s, 1, len(s))
|
||||
Script(s).find_signatures(1, 0)
|
||||
Script(s).find_references(1, len(s))
|
||||
|
||||
|
||||
def _check_number(Script, source, result='float'):
|
||||
completions = Script(source).completions()
|
||||
completions = Script(source).complete()
|
||||
assert completions[0].parent().name == result
|
||||
|
||||
|
||||
def test_completion_on_number_literals(Script):
|
||||
# No completions on an int literal (is a float).
|
||||
assert [c.name for c in Script('1. ').completions()] \
|
||||
assert [c.name for c in Script('1. ').complete()] \
|
||||
== ['and', 'if', 'in', 'is', 'not', 'or']
|
||||
|
||||
# Multiple points after an int literal basically mean that there's a float
|
||||
@@ -88,27 +90,27 @@ def test_completion_on_number_literals(Script):
|
||||
_check_number(Script, '1.e14.')
|
||||
_check_number(Script, '1.e-3.')
|
||||
_check_number(Script, '9e3.')
|
||||
assert Script('1.e3..').completions() == []
|
||||
assert Script('1.e-13..').completions() == []
|
||||
assert Script('1.e3..').complete() == []
|
||||
assert Script('1.e-13..').complete() == []
|
||||
|
||||
|
||||
def test_completion_on_hex_literals(Script):
|
||||
assert Script('0x1..').completions() == []
|
||||
assert Script('0x1..').complete() == []
|
||||
_check_number(Script, '0x1.', 'int') # hexdecimal
|
||||
# Completing binary literals doesn't work if they are not actually binary
|
||||
# (invalid statements).
|
||||
assert Script('0b2.b').completions() == []
|
||||
assert Script('0b2.b').complete() == []
|
||||
_check_number(Script, '0b1.', 'int') # binary
|
||||
|
||||
_check_number(Script, '0x2e.', 'int')
|
||||
_check_number(Script, '0xE7.', 'int')
|
||||
_check_number(Script, '0xEa.', 'int')
|
||||
# theoretically, but people can just check for syntax errors:
|
||||
assert Script('0x.').completions() == []
|
||||
assert Script('0x.').complete() == []
|
||||
|
||||
|
||||
def test_completion_on_complex_literals(Script):
|
||||
assert Script('1j..').completions() == []
|
||||
assert Script('1j..').complete() == []
|
||||
_check_number(Script, '1j.', 'complex')
|
||||
_check_number(Script, '44.j.', 'complex')
|
||||
_check_number(Script, '4.0j.', 'complex')
|
||||
@@ -116,24 +118,24 @@ def test_completion_on_complex_literals(Script):
|
||||
# which a keyword like or is allowed. Good times, haha!
|
||||
# However this has been disabled again, because it apparently annoyed
|
||||
# users. So no completion after j without a space :)
|
||||
assert not Script('4j').completions()
|
||||
assert ({c.name for c in Script('4j ').completions()} ==
|
||||
assert not Script('4j').complete()
|
||||
assert ({c.name for c in Script('4j ').complete()} ==
|
||||
{'if', 'and', 'in', 'is', 'not', 'or'})
|
||||
|
||||
|
||||
def test_goto_assignments_on_non_name(Script, environment):
|
||||
assert Script('for').goto_assignments() == []
|
||||
def test_goto_non_name(Script, environment):
|
||||
assert Script('for').goto() == []
|
||||
|
||||
assert Script('assert').goto_assignments() == []
|
||||
assert Script('True').goto_assignments() == []
|
||||
assert Script('assert').goto() == []
|
||||
assert Script('True').goto() == []
|
||||
|
||||
|
||||
def test_goto_definitions_on_non_name(Script):
|
||||
assert Script('import x', column=0).goto_definitions() == []
|
||||
def test_infer_on_non_name(Script):
|
||||
assert Script('import x').infer(column=0) == []
|
||||
|
||||
|
||||
def test_goto_definitions_on_generator(Script):
|
||||
def_, = Script('def x(): yield 1\ny=x()\ny').goto_definitions()
|
||||
def test_infer_on_generator(Script):
|
||||
def_, = Script('def x(): yield 1\ny=x()\ny').infer()
|
||||
assert def_.name == 'Generator'
|
||||
|
||||
|
||||
@@ -157,20 +159,20 @@ def test_goto_definition_not_multiple(Script):
|
||||
else:
|
||||
a = A(1)
|
||||
a''')
|
||||
assert len(Script(s).goto_definitions()) == 1
|
||||
assert len(Script(s).infer()) == 1
|
||||
|
||||
|
||||
def test_usage_description(Script):
|
||||
descs = [u.description for u in Script("foo = ''; foo").usages()]
|
||||
def test_reference_description(Script):
|
||||
descs = [u.description for u in Script("foo = ''; foo").find_references()]
|
||||
assert set(descs) == {"foo = ''", 'foo'}
|
||||
|
||||
|
||||
def test_get_line_code(Script):
|
||||
def get_line_code(source, line=None, **kwargs):
|
||||
return Script(source, line=line).completions()[0].get_line_code(**kwargs)
|
||||
return Script(source).complete(line=line)[0].get_line_code(**kwargs)
|
||||
|
||||
# On builtin
|
||||
assert get_line_code('') == ''
|
||||
assert get_line_code('abs') == 'def abs(__n: SupportsAbs[_T]) -> _T: ...\n'
|
||||
|
||||
# On custom code
|
||||
first_line = 'def foo():\n'
|
||||
@@ -188,43 +190,50 @@ def test_get_line_code(Script):
|
||||
assert get_line_code(code, line=2, after=3, before=3) == code
|
||||
|
||||
|
||||
def test_goto_assignments_follow_imports(Script):
|
||||
def test_get_line_code_on_builtin(Script, disable_typeshed):
|
||||
abs_ = Script('abs').complete()[0]
|
||||
assert abs_.name == 'abs'
|
||||
assert abs_.get_line_code() == ''
|
||||
assert abs_.line is None
|
||||
|
||||
|
||||
def test_goto_follow_imports(Script):
|
||||
code = dedent("""
|
||||
import inspect
|
||||
inspect.isfunction""")
|
||||
definition, = Script(code, column=0).goto_assignments(follow_imports=True)
|
||||
definition, = Script(code).goto(column=0, follow_imports=True)
|
||||
assert 'inspect.py' in definition.module_path
|
||||
assert (definition.line, definition.column) == (1, 0)
|
||||
|
||||
definition, = Script(code).goto_assignments(follow_imports=True)
|
||||
definition, = Script(code).goto(follow_imports=True)
|
||||
assert 'inspect.py' in definition.module_path
|
||||
assert (definition.line, definition.column) > (1, 0)
|
||||
|
||||
code = '''def param(p): pass\nparam(1)'''
|
||||
start_pos = 1, len('def param(')
|
||||
|
||||
script = Script(code, *start_pos)
|
||||
definition, = script.goto_assignments(follow_imports=True)
|
||||
script = Script(code)
|
||||
definition, = script.goto(*start_pos, follow_imports=True)
|
||||
assert (definition.line, definition.column) == start_pos
|
||||
assert definition.name == 'p'
|
||||
result, = definition.goto_assignments()
|
||||
result, = definition.goto()
|
||||
assert result.name == 'p'
|
||||
result, = definition.infer()
|
||||
assert result.name == 'int'
|
||||
result, = result.infer()
|
||||
assert result.name == 'int'
|
||||
|
||||
definition, = script.goto_assignments()
|
||||
definition, = script.goto(*start_pos)
|
||||
assert (definition.line, definition.column) == start_pos
|
||||
|
||||
d, = Script('a = 1\na').goto_assignments(follow_imports=True)
|
||||
d, = Script('a = 1\na').goto(follow_imports=True)
|
||||
assert d.name == 'a'
|
||||
|
||||
|
||||
def test_goto_module(Script):
|
||||
def check(line, expected, follow_imports=False):
|
||||
script = Script(path=path, line=line)
|
||||
module, = script.goto_assignments(follow_imports=follow_imports)
|
||||
script = Script(path=path)
|
||||
module, = script.goto(line=line, follow_imports=follow_imports)
|
||||
assert module.module_path == expected
|
||||
|
||||
base_path = os.path.join(os.path.dirname(__file__), 'simple_import')
|
||||
@@ -255,7 +264,7 @@ def test_goto_definition_cursor(Script):
|
||||
should2 = 8, 10
|
||||
|
||||
def get_def(pos):
|
||||
return [d.description for d in Script(s, *pos).goto_definitions()]
|
||||
return [d.description for d in Script(s).infer(*pos)]
|
||||
|
||||
in_name = get_def(in_name)
|
||||
under_score = get_def(under_score)
|
||||
@@ -281,7 +290,7 @@ def test_no_statement_parent(Script):
|
||||
pass
|
||||
|
||||
variable = f if random.choice([0, 1]) else C""")
|
||||
defs = Script(source, column=3).goto_definitions()
|
||||
defs = Script(source).infer(column=3)
|
||||
defs = sorted(defs, key=lambda d: d.line)
|
||||
assert [d.description for d in defs] == ['def f', 'class C']
|
||||
|
||||
@@ -294,13 +303,66 @@ def test_backslash_continuation_and_bracket(Script):
|
||||
|
||||
lines = code.splitlines()
|
||||
column = lines[-1].index('(')
|
||||
def_, = Script(code, line=len(lines), column=column).goto_definitions()
|
||||
def_, = Script(code).infer(line=len(lines), column=column)
|
||||
assert def_.name == 'int'
|
||||
|
||||
|
||||
def test_goto_follow_builtin_imports(Script):
|
||||
s = Script('import sys; sys')
|
||||
d, = s.goto_assignments(follow_imports=True)
|
||||
d, = s.goto(follow_imports=True)
|
||||
assert d.in_builtin_module() is True
|
||||
d, = s.goto_assignments(follow_imports=True, follow_builtin_imports=True)
|
||||
d, = s.goto(follow_imports=True, follow_builtin_imports=True)
|
||||
assert d.in_builtin_module() is True
|
||||
|
||||
|
||||
def test_docstrings_for_completions(Script):
|
||||
for c in Script('').complete():
|
||||
assert isinstance(c.docstring(), (str, unicode))
|
||||
|
||||
|
||||
def test_fuzzy_completion(Script):
|
||||
script = Script('string = "hello"\nstring.upper')
|
||||
assert ['isupper',
|
||||
'upper'] == [comp.name for comp in script.complete(fuzzy=True)]
|
||||
|
||||
|
||||
def test_math_fuzzy_completion(Script, environment):
|
||||
script = Script('import math\nmath.og')
|
||||
expected = ['copysign', 'log', 'log10', 'log1p']
|
||||
if environment.version_info.major >= 3:
|
||||
expected.append('log2')
|
||||
completions = script.complete(fuzzy=True)
|
||||
assert expected == [comp.name for comp in completions]
|
||||
for c in completions:
|
||||
assert c.complete is None
|
||||
|
||||
|
||||
def test_file_fuzzy_completion(Script):
|
||||
path = os.path.join(test_dir, 'completion')
|
||||
script = Script('"{}/ep08_i'.format(path))
|
||||
assert ['pep0484_basic.py"', 'pep0484_typing.py"'] \
|
||||
== [comp.name for comp in script.complete(fuzzy=True)]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'code, column', [
|
||||
('"foo"', 0),
|
||||
('"foo"', 3),
|
||||
('"foo"', None),
|
||||
('"""foo"""', 5),
|
||||
('"""foo"""', 1),
|
||||
('"""foo"""', 2),
|
||||
]
|
||||
)
|
||||
def test_goto_on_string(Script, code, column):
|
||||
script = Script(code)
|
||||
assert not script.infer(column=column)
|
||||
assert not script.goto(column=column)
|
||||
|
||||
|
||||
def test_multi_goto(Script):
|
||||
script = Script('x = 1\ny = 1.0\nx\ny')
|
||||
x, = script.goto(line=3)
|
||||
y, = script.goto(line=4)
|
||||
assert x.line == 1
|
||||
assert y.line == 2
|
||||
|
||||
@@ -6,14 +6,14 @@ from ..helpers import cwd_at
|
||||
|
||||
def test_import_empty(Script):
|
||||
""" github #340, return the full word. """
|
||||
completion = Script("import ").completions()[0]
|
||||
completion = Script("import ").complete()[0]
|
||||
definition = completion.infer()[0]
|
||||
assert definition
|
||||
|
||||
|
||||
def check_follow_definition_types(Script, source):
|
||||
# nested import
|
||||
completions = Script(source, path='some_path.py').completions()
|
||||
completions = Script(source, path='some_path.py').complete()
|
||||
defs = chain.from_iterable(c.infer() for c in completions)
|
||||
return [d.type for d in defs]
|
||||
|
||||
@@ -27,7 +27,7 @@ def test_follow_import_incomplete(Script, environment):
|
||||
assert datetime == ['module']
|
||||
|
||||
# empty `from * import` parts
|
||||
itert = jedi.Script("from itertools import ").completions()
|
||||
itert = jedi.Script("from itertools import ").complete()
|
||||
definitions = [d for d in itert if d.name == 'chain']
|
||||
assert len(definitions) == 1
|
||||
assert [d.type for d in definitions[0].infer()] == ['class']
|
||||
|
||||
@@ -6,12 +6,12 @@ import pytest
|
||||
|
||||
from ..helpers import TestCase
|
||||
from jedi import cache
|
||||
from jedi.parser_utils import get_call_signature
|
||||
from jedi.parser_utils import get_signature
|
||||
from jedi import Interpreter
|
||||
|
||||
|
||||
def assert_signature(Script, source, expected_name, expected_index=0, line=None, column=None):
|
||||
signatures = Script(source, line, column).call_signatures()
|
||||
signatures = Script(source).find_signatures(line, column)
|
||||
|
||||
assert len(signatures) <= 1
|
||||
|
||||
@@ -28,7 +28,7 @@ def test_valid_call(Script):
|
||||
assert_signature(Script, 'bool()', 'bool', column=5)
|
||||
|
||||
|
||||
class TestCallSignatures(TestCase):
|
||||
class TestSignatures(TestCase):
|
||||
@pytest.fixture(autouse=True)
|
||||
def init(self, Script):
|
||||
self.Script = Script
|
||||
@@ -96,12 +96,12 @@ class TestCallSignatures(TestCase):
|
||||
|
||||
def test_with(Script):
|
||||
# jedi-vim #9
|
||||
sigs = Script("with open(").call_signatures()
|
||||
sigs = Script("with open(").find_signatures()
|
||||
assert sigs
|
||||
assert all(sig.name == 'open' for sig in sigs)
|
||||
|
||||
|
||||
def test_call_signatures_empty_parentheses_pre_space(Script):
|
||||
def test_find_signatures_empty_parentheses_pre_space(Script):
|
||||
s = dedent("""\
|
||||
def f(a, b):
|
||||
pass
|
||||
@@ -118,10 +118,10 @@ def test_multiple_signatures(Script):
|
||||
def f(a, b):
|
||||
pass
|
||||
f(""")
|
||||
assert len(Script(s).call_signatures()) == 2
|
||||
assert len(Script(s).find_signatures()) == 2
|
||||
|
||||
|
||||
def test_call_signatures_whitespace(Script):
|
||||
def test_find_signatures_whitespace(Script):
|
||||
s = dedent("""\
|
||||
abs(
|
||||
def x():
|
||||
@@ -148,7 +148,7 @@ def test_decorator_in_class(Script):
|
||||
|
||||
C().test(""")
|
||||
|
||||
signatures = Script(s).call_signatures()
|
||||
signatures = Script(s).find_signatures()
|
||||
assert len(signatures) == 1
|
||||
x = [p.description for p in signatures[0].params]
|
||||
assert x == ['param *args']
|
||||
@@ -176,14 +176,14 @@ def test_brackets_in_string_literals(Script):
|
||||
def test_function_definitions_should_break(Script):
|
||||
"""
|
||||
Function definitions (and other tokens that cannot exist within call
|
||||
signatures) should break and not be able to return a call signature.
|
||||
signatures) should break and not be able to return a signature.
|
||||
"""
|
||||
assert_signature(Script, 'abs(\ndef x', 'abs', 0)
|
||||
assert not Script('abs(\ndef x(): pass').call_signatures()
|
||||
assert not Script('abs(\ndef x(): pass').find_signatures()
|
||||
|
||||
|
||||
def test_flow_call(Script):
|
||||
assert not Script('if (1').call_signatures()
|
||||
assert not Script('if (1').find_signatures()
|
||||
|
||||
|
||||
def test_chained_calls(Script):
|
||||
@@ -209,11 +209,11 @@ def test_return(Script):
|
||||
assert_signature(Script, source, 'join', 0, column=len(" return '.'.join("))
|
||||
|
||||
|
||||
def test_call_signature_on_module(Script):
|
||||
def test_find_signature_on_module(Script):
|
||||
"""github issue #240"""
|
||||
s = 'import datetime; datetime('
|
||||
# just don't throw an exception (if numpy doesn't exist, just ignore it)
|
||||
assert Script(s).call_signatures() == []
|
||||
assert Script(s).find_signatures() == []
|
||||
|
||||
|
||||
def test_complex(Script, environment):
|
||||
@@ -234,7 +234,7 @@ def test_complex(Script, environment):
|
||||
re.compile(
|
||||
return it * 2
|
||||
"""
|
||||
sig1, sig2 = sorted(Script(s, line=4, column=27).call_signatures(), key=lambda s: s.line)
|
||||
sig1, sig2 = sorted(Script(s).find_signatures(line=4, column=27), key=lambda s: s.line)
|
||||
assert sig1.name == sig2.name == 'compile'
|
||||
assert sig1.index == sig2.index == 0
|
||||
func1, = sig1._name.infer()
|
||||
@@ -243,14 +243,14 @@ def test_complex(Script, environment):
|
||||
if environment.version_info.major == 3:
|
||||
# Do these checks just for Python 3, I'm too lazy to deal with this
|
||||
# legacy stuff. ~ dave.
|
||||
assert get_call_signature(func1.tree_node) \
|
||||
assert get_signature(func1.tree_node) \
|
||||
== 'compile(pattern: AnyStr, flags: _FlagsType = ...) -> Pattern[AnyStr]'
|
||||
assert get_call_signature(func2.tree_node) \
|
||||
assert get_signature(func2.tree_node) \
|
||||
== 'compile(pattern: Pattern[AnyStr], flags: _FlagsType = ...) ->\nPattern[AnyStr]'
|
||||
|
||||
# jedi-vim #70
|
||||
s = """def foo("""
|
||||
assert Script(s).call_signatures() == []
|
||||
assert Script(s).find_signatures() == []
|
||||
|
||||
# jedi-vim #116
|
||||
s = """import itertools; test = getattr(itertools, 'chain'); test("""
|
||||
@@ -258,13 +258,13 @@ def test_complex(Script, environment):
|
||||
|
||||
|
||||
def _params(Script, source, line=None, column=None):
|
||||
signatures = Script(source, line, column).call_signatures()
|
||||
signatures = Script(source, line, column).find_signatures()
|
||||
assert len(signatures) == 1
|
||||
return signatures[0].params
|
||||
|
||||
|
||||
def test_int_params(Script):
|
||||
sig1, sig2 = Script('int(').call_signatures()
|
||||
sig1, sig2 = Script('int(').find_signatures()
|
||||
# int is defined as: `int(x[, base])`
|
||||
assert len(sig1.params) == 1
|
||||
assert sig1.params[0].name == 'x'
|
||||
@@ -275,13 +275,13 @@ def test_int_params(Script):
|
||||
|
||||
def test_pow_params(Script):
|
||||
# See Github #1357.
|
||||
for sig in Script('pow(').call_signatures():
|
||||
for sig in Script('pow(').find_signatures():
|
||||
param_names = [p.name for p in sig.params]
|
||||
assert param_names in (['x', 'y'], ['x', 'y', 'z'])
|
||||
|
||||
|
||||
def test_param_name(Script):
|
||||
sigs = Script('open(something,').call_signatures()
|
||||
sigs = Script('open(something,').find_signatures()
|
||||
for sig in sigs:
|
||||
# All of the signatures (in Python the function is overloaded),
|
||||
# contain the same param names.
|
||||
@@ -304,19 +304,19 @@ def test_builtins(Script):
|
||||
|
||||
def test_signature_is_definition(Script):
|
||||
"""
|
||||
Through inheritance, a call signature is a sub class of Definition.
|
||||
Through inheritance, a signature is a sub class of Definition.
|
||||
Check if the attributes match.
|
||||
"""
|
||||
s = """class Spam(): pass\nSpam"""
|
||||
signature = Script(s + '(').call_signatures()[0]
|
||||
definition = Script(s + '(', column=0).goto_definitions()[0]
|
||||
signature = Script(s + '(').find_signatures()[0]
|
||||
definition = Script(s + '(').infer(column=0)[0]
|
||||
signature.line == 1
|
||||
signature.column == 6
|
||||
|
||||
# Now compare all the attributes that a CallSignature must also have.
|
||||
# Now compare all the attributes that a Signature must also have.
|
||||
for attr_name in dir(definition):
|
||||
dont_scan = ['defined_names', 'parent', 'goto_assignments', 'infer',
|
||||
'params', 'get_signatures', 'execute']
|
||||
'params', 'get_signatures', 'execute', 'goto']
|
||||
if attr_name.startswith('_') or attr_name in dont_scan:
|
||||
continue
|
||||
|
||||
@@ -330,15 +330,15 @@ def test_signature_is_definition(Script):
|
||||
|
||||
def test_no_signature(Script):
|
||||
# str doesn't have a __call__ method
|
||||
assert Script('str()(').call_signatures() == []
|
||||
assert Script('str()(').find_signatures() == []
|
||||
|
||||
s = dedent("""\
|
||||
class X():
|
||||
pass
|
||||
X()(""")
|
||||
assert Script(s).call_signatures() == []
|
||||
assert len(Script(s, column=2).call_signatures()) == 1
|
||||
assert Script('').call_signatures() == []
|
||||
assert Script(s).find_signatures() == []
|
||||
assert len(Script(s).find_signatures(column=2)) == 1
|
||||
assert Script('').find_signatures() == []
|
||||
|
||||
|
||||
def test_dict_literal_in_incomplete_call(Script):
|
||||
@@ -354,24 +354,24 @@ def test_dict_literal_in_incomplete_call(Script):
|
||||
c = Foo()
|
||||
"""
|
||||
|
||||
script = Script(dedent(source), line=4, column=15)
|
||||
assert script.call_signatures()
|
||||
script = Script(dedent(source))
|
||||
assert script.find_signatures(line=4, column=15)
|
||||
|
||||
|
||||
def test_completion_interference(Script):
|
||||
"""Seems to cause problems, see also #396."""
|
||||
cache.parser_cache.pop(None, None)
|
||||
assert Script('open(').call_signatures()
|
||||
assert Script('open(').find_signatures()
|
||||
|
||||
# complete something usual, before doing the same call_signatures again.
|
||||
assert Script('from datetime import ').completions()
|
||||
# complete something usual, before doing the same find_signatures again.
|
||||
assert Script('from datetime import ').complete()
|
||||
|
||||
assert Script('open(').call_signatures()
|
||||
assert Script('open(').find_signatures()
|
||||
|
||||
|
||||
def test_keyword_argument_index(Script, environment):
|
||||
def get(source, column=None):
|
||||
return Script(source, column=column).call_signatures()[0]
|
||||
return Script(source).find_signatures(column=column)[0]
|
||||
|
||||
# The signature of sorted changed from 2 to 3.
|
||||
py2_offset = int(environment.version_info.major == 2)
|
||||
@@ -491,6 +491,13 @@ _calls = [
|
||||
(code4, 'i(?b,*r,c', 1),
|
||||
(code4, 'i(?*', 0),
|
||||
(code4, 'i(?**', (0, 1)),
|
||||
|
||||
# Random
|
||||
(code4, 'i(()', 0),
|
||||
(code4, 'i((),', 1),
|
||||
(code4, 'i([(),', 0),
|
||||
(code4, 'i([(,', 1),
|
||||
(code4, 'i(x,()', 1),
|
||||
]
|
||||
|
||||
|
||||
@@ -502,7 +509,7 @@ def test_signature_index(skip_python2, Script, environment, code, call, expected
|
||||
if environment.version_info < (3, 8):
|
||||
code = code.replace('/,', '')
|
||||
|
||||
sig, = Script(code + '\n' + call + ending, column=len(call)).call_signatures()
|
||||
sig, = Script(code + '\n' + call + ending).find_signatures(column=len(call))
|
||||
index = sig.index
|
||||
assert expected_index == index
|
||||
|
||||
@@ -540,14 +547,14 @@ def test_arg_defaults(Script, environment, code):
|
||||
yield Interpreter(code + '2(', namespaces=[executed_locals])
|
||||
|
||||
for script in iter_scripts():
|
||||
signatures = script.call_signatures()
|
||||
signatures = script.find_signatures()
|
||||
assert signatures[0].params[0].description in ('param arg="bla"', "param arg='bla'")
|
||||
assert signatures[0].params[1].description == 'param arg1=1'
|
||||
|
||||
|
||||
def test_bracket_start(Script):
|
||||
def bracket_start(src):
|
||||
signatures = Script(src).call_signatures()
|
||||
signatures = Script(src).find_signatures()
|
||||
assert len(signatures) == 1
|
||||
return signatures[0].bracket_start
|
||||
|
||||
@@ -557,7 +564,7 @@ def test_bracket_start(Script):
|
||||
def test_different_caller(Script):
|
||||
"""
|
||||
It's possible to not use names, but another function result or an array
|
||||
index and then get the call signature of it.
|
||||
index and then get the signature of it.
|
||||
"""
|
||||
|
||||
assert_signature(Script, '[abs][0](', 'abs', 0)
|
||||
@@ -572,14 +579,14 @@ def test_in_function(Script):
|
||||
class X():
|
||||
@property
|
||||
def func(''')
|
||||
assert not Script(code).call_signatures()
|
||||
assert not Script(code).find_signatures()
|
||||
|
||||
|
||||
def test_lambda_params(Script):
|
||||
code = dedent('''\
|
||||
my_lambda = lambda x: x+1
|
||||
my_lambda(1)''')
|
||||
sig, = Script(code, column=11).call_signatures()
|
||||
sig, = Script(code).find_signatures(column=11)
|
||||
assert sig.index == 0
|
||||
assert sig.name == '<lambda>'
|
||||
assert [p.name for p in sig.params] == ['x']
|
||||
@@ -594,19 +601,19 @@ class X():
|
||||
|
||||
def test_class_creation(Script):
|
||||
|
||||
sig, = Script(CLASS_CODE + 'X(').call_signatures()
|
||||
sig, = Script(CLASS_CODE + 'X(').find_signatures()
|
||||
assert sig.index == 0
|
||||
assert sig.name == 'X'
|
||||
assert [p.name for p in sig.params] == ['foo', 'bar']
|
||||
|
||||
|
||||
def test_call_init_on_class(Script):
|
||||
sig, = Script(CLASS_CODE + 'X.__init__(').call_signatures()
|
||||
sig, = Script(CLASS_CODE + 'X.__init__(').find_signatures()
|
||||
assert [p.name for p in sig.params] == ['self', 'foo', 'bar']
|
||||
|
||||
|
||||
def test_call_init_on_instance(Script):
|
||||
sig, = Script(CLASS_CODE + 'X().__init__(').call_signatures()
|
||||
sig, = Script(CLASS_CODE + 'X().__init__(').find_signatures()
|
||||
assert [p.name for p in sig.params] == ['foo', 'bar']
|
||||
|
||||
|
||||
@@ -616,12 +623,45 @@ def test_call_magic_method(Script):
|
||||
def __call__(self, baz):
|
||||
pass
|
||||
''')
|
||||
sig, = Script(code + 'X()(').call_signatures()
|
||||
sig, = Script(code + 'X()(').find_signatures()
|
||||
assert sig.index == 0
|
||||
assert sig.name == 'X'
|
||||
assert [p.name for p in sig.params] == ['baz']
|
||||
|
||||
sig, = Script(code + 'X.__call__(').call_signatures()
|
||||
sig, = Script(code + 'X.__call__(').find_signatures()
|
||||
assert [p.name for p in sig.params] == ['self', 'baz']
|
||||
sig, = Script(code + 'X().__call__(').call_signatures()
|
||||
sig, = Script(code + 'X().__call__(').find_signatures()
|
||||
assert [p.name for p in sig.params] == ['baz']
|
||||
|
||||
|
||||
@pytest.mark.parametrize('column', [6, 9])
|
||||
def test_cursor_after_signature(Script, column):
|
||||
source = dedent("""
|
||||
def foo(*args):
|
||||
pass
|
||||
foo() # _
|
||||
""")
|
||||
|
||||
script = Script(source)
|
||||
|
||||
assert not script.find_signatures(4, column)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'code, line, column, name, index', [
|
||||
('abs(()\ndef foo(): pass', 1, None, 'abs', 0),
|
||||
('abs(chr() \ndef foo(): pass', 1, 10, 'abs', 0),
|
||||
('abs(chr()\ndef foo(): pass', 1, None, 'abs', 0),
|
||||
('abs(chr()\ndef foo(): pass', 1, 8, 'chr', 0),
|
||||
('abs(chr()\ndef foo(): pass', 1, 7, 'abs', 0),
|
||||
('abs(chr ( \nclass y: pass', 1, None, 'chr', 0),
|
||||
('abs(chr ( \nclass y: pass', 1, 8, 'abs', 0),
|
||||
('abs(chr ( \nclass y: pass', 1, 9, 'abs', 0),
|
||||
('abs(chr ( \nclass y: pass', 1, 10, 'chr', 0),
|
||||
]
|
||||
)
|
||||
def test_base_signatures(Script, code, line, column, name, index):
|
||||
sig, = Script(code).find_signatures(line=line, column=column)
|
||||
|
||||
assert sig.name == name
|
||||
assert sig.index == index
|
||||
|
||||
@@ -3,16 +3,18 @@
|
||||
|
||||
from textwrap import dedent
|
||||
from inspect import cleandoc
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
import jedi
|
||||
from jedi import __doc__ as jedi_doc
|
||||
from jedi.inference.compiled import CompiledValueName
|
||||
from ..helpers import get_example_dir
|
||||
|
||||
|
||||
def test_is_keyword(Script):
|
||||
results = Script('str', 1, 1, None).goto_definitions()
|
||||
results = Script('str', path=None).infer(1, 1)
|
||||
assert len(results) == 1 and results[0].is_keyword is False
|
||||
|
||||
|
||||
@@ -46,15 +48,15 @@ def test_basedefinition_type(Script, names):
|
||||
source += dedent("""
|
||||
variable = sys or C or x or f or g or g() or h""")
|
||||
lines = source.splitlines()
|
||||
script = Script(source, len(lines), len('variable'), None)
|
||||
definitions += script.goto_definitions()
|
||||
script = Script(source, path=None)
|
||||
definitions += script.infer(len(lines), len('variable'))
|
||||
|
||||
script2 = Script(source, 4, len('class C'), None)
|
||||
definitions += script2.usages()
|
||||
script2 = Script(source, path=None)
|
||||
definitions += script2.find_references(4, len('class C'))
|
||||
|
||||
source_param = "def f(a): return a"
|
||||
script_param = Script(source_param, 1, len(source_param), None)
|
||||
definitions += script_param.goto_assignments()
|
||||
script_param = Script(source_param, path=None)
|
||||
definitions += script_param.goto(1, len(source_param))
|
||||
|
||||
return definitions
|
||||
|
||||
@@ -86,15 +88,15 @@ def test_basedefinition_type(Script, names):
|
||||
|
||||
)
|
||||
def test_basedefinition_type_import(Script, src, expected_result, column):
|
||||
types = {t.type for t in Script(src, column=column).completions()}
|
||||
types = {t.type for t in Script(src).complete(column=column)}
|
||||
assert types == {expected_result}
|
||||
|
||||
|
||||
def test_function_call_signature_in_doc(Script):
|
||||
def test_function_signature_in_doc(Script):
|
||||
defs = Script("""
|
||||
def f(x, y=1, z='a'):
|
||||
pass
|
||||
f""").goto_definitions()
|
||||
f""").infer()
|
||||
doc = defs[0].docstring()
|
||||
assert "f(x, y=1, z='a')" in str(doc)
|
||||
|
||||
@@ -105,18 +107,18 @@ def test_param_docstring(names):
|
||||
assert param.docstring() == ''
|
||||
|
||||
|
||||
def test_class_call_signature(Script):
|
||||
def test_class_signature(Script):
|
||||
defs = Script("""
|
||||
class Foo:
|
||||
def __init__(self, x, y=1, z='a'):
|
||||
pass
|
||||
Foo""").goto_definitions()
|
||||
Foo""").infer()
|
||||
doc = defs[0].docstring()
|
||||
assert doc == "Foo(x, y=1, z='a')"
|
||||
|
||||
|
||||
def test_position_none_if_builtin(Script):
|
||||
gotos = Script('import sys; sys.path').goto_assignments()
|
||||
gotos = Script('import sys; sys.path').goto()
|
||||
assert gotos[0].in_builtin_module()
|
||||
assert gotos[0].line is not None
|
||||
assert gotos[0].column is not None
|
||||
@@ -127,10 +129,10 @@ def test_completion_docstring(Script, jedi_path):
|
||||
Jedi should follow imports in certain conditions
|
||||
"""
|
||||
def docstr(src, result):
|
||||
c = Script(src, sys_path=[jedi_path]).completions()[0]
|
||||
c = Script(src, sys_path=[jedi_path]).complete()[0]
|
||||
assert c.docstring(raw=True, fast=False) == cleandoc(result)
|
||||
|
||||
c = Script('import jedi\njed', sys_path=[jedi_path]).completions()[0]
|
||||
c = Script('import jedi\njed', sys_path=[jedi_path]).complete()[0]
|
||||
assert c.docstring(fast=False) == cleandoc(jedi_doc)
|
||||
|
||||
docstr('import jedi\njedi.Scr', cleandoc(jedi.Script.__doc__))
|
||||
@@ -172,12 +174,12 @@ def test_completion_docstring(Script, jedi_path):
|
||||
|
||||
|
||||
def test_completion_params(Script):
|
||||
c = Script('import string; string.capwords').completions()[0]
|
||||
c = Script('import string; string.capwords').complete()[0]
|
||||
assert [p.name for p in c.params] == ['s', 'sep']
|
||||
|
||||
|
||||
def test_functions_should_have_params(Script):
|
||||
for c in Script('bool.').completions():
|
||||
for c in Script('bool.').complete():
|
||||
if c.type == 'function':
|
||||
assert isinstance(c.params, list)
|
||||
|
||||
@@ -187,7 +189,7 @@ def test_hashlib_params(Script, environment):
|
||||
pytest.skip()
|
||||
|
||||
script = Script(source='from hashlib import sha256')
|
||||
c, = script.completions()
|
||||
c, = script.complete()
|
||||
assert [p.name for p in c.params] == ['arg']
|
||||
|
||||
|
||||
@@ -202,10 +204,10 @@ def test_signature_params(Script):
|
||||
pass
|
||||
foo''')
|
||||
|
||||
check(Script(s).goto_definitions())
|
||||
check(Script(s).infer())
|
||||
|
||||
check(Script(s).goto_assignments())
|
||||
check(Script(s + '\nbar=foo\nbar').goto_assignments())
|
||||
check(Script(s).goto())
|
||||
check(Script(s + '\nbar=foo\nbar').goto())
|
||||
|
||||
|
||||
def test_param_endings(Script):
|
||||
@@ -213,7 +215,7 @@ def test_param_endings(Script):
|
||||
Params should be represented without the comma and whitespace they have
|
||||
around them.
|
||||
"""
|
||||
sig = Script('def x(a, b=5, c=""): pass\n x(').call_signatures()[0]
|
||||
sig = Script('def x(a, b=5, c=""): pass\n x(').find_signatures()[0]
|
||||
assert [p.description for p in sig.params] == ['param a', 'param b=5', 'param c=""']
|
||||
|
||||
|
||||
@@ -251,7 +253,7 @@ def test_is_definition_import(names, code, expected):
|
||||
|
||||
def test_parent(Script):
|
||||
def _parent(source, line=None, column=None):
|
||||
def_, = Script(dedent(source), line, column).goto_assignments()
|
||||
def_, = Script(dedent(source)).goto(line, column)
|
||||
return def_.parent()
|
||||
|
||||
parent = _parent('foo=1\nfoo')
|
||||
@@ -268,30 +270,71 @@ def test_parent(Script):
|
||||
|
||||
def test_parent_on_function(Script):
|
||||
code = 'def spam():\n pass'
|
||||
def_, = Script(code, line=1, column=len('def spam')).goto_assignments()
|
||||
def_, = Script(code).goto(line=1, column=len('def spam'))
|
||||
parent = def_.parent()
|
||||
assert parent.name == ''
|
||||
assert parent.type == 'module'
|
||||
|
||||
|
||||
def test_parent_on_completion(Script):
|
||||
parent = Script(dedent('''\
|
||||
def test_parent_on_completion_and_else(Script):
|
||||
script = Script(dedent('''\
|
||||
class Foo():
|
||||
def bar(): pass
|
||||
Foo().bar''')).completions()[0].parent()
|
||||
def bar(name): name
|
||||
Foo().bar'''))
|
||||
|
||||
bar, = script.complete()
|
||||
parent = bar.parent()
|
||||
assert parent.name == 'Foo'
|
||||
assert parent.type == 'class'
|
||||
|
||||
parent = Script('str.join').completions()[0].parent()
|
||||
param, name, = [d for d in script.names(all_scopes=True, references=True)
|
||||
if d.name == 'name']
|
||||
parent = name.parent()
|
||||
assert parent.name == 'bar'
|
||||
assert parent.type == 'function'
|
||||
parent = name.parent().parent()
|
||||
assert parent.name == 'Foo'
|
||||
assert parent.type == 'class'
|
||||
|
||||
parent = param.parent()
|
||||
assert parent.name == 'bar'
|
||||
assert parent.type == 'function'
|
||||
parent = param.parent().parent()
|
||||
assert parent.name == 'Foo'
|
||||
assert parent.type == 'class'
|
||||
|
||||
parent = Script('str.join').complete()[0].parent()
|
||||
assert parent.name == 'str'
|
||||
assert parent.type == 'class'
|
||||
|
||||
|
||||
def test_parent_on_comprehension():
|
||||
ns = jedi.names('''\
|
||||
def test_parent_on_closure(Script):
|
||||
script = Script(dedent('''\
|
||||
class Foo():
|
||||
def bar(name):
|
||||
def inner(): foo
|
||||
return inner'''))
|
||||
|
||||
names = script.names(all_scopes=True, references=True)
|
||||
inner_func, inner_reference = filter(lambda d: d.name == 'inner', names)
|
||||
foo, = filter(lambda d: d.name == 'foo', names)
|
||||
|
||||
assert foo.parent().name == 'inner'
|
||||
assert foo.parent().parent().name == 'bar'
|
||||
assert foo.parent().parent().parent().name == 'Foo'
|
||||
assert foo.parent().parent().parent().parent().name == ''
|
||||
|
||||
assert inner_func.parent().name == 'bar'
|
||||
assert inner_func.parent().parent().name == 'Foo'
|
||||
assert inner_reference.parent().name == 'bar'
|
||||
assert inner_reference.parent().parent().name == 'Foo'
|
||||
|
||||
|
||||
def test_parent_on_comprehension(Script):
|
||||
ns = Script('''\
|
||||
def spam():
|
||||
return [i for i in range(5)]
|
||||
''', all_scopes=True)
|
||||
''').names(all_scopes=True)
|
||||
|
||||
assert [name.name for name in ns] == ['spam', 'i']
|
||||
|
||||
@@ -302,17 +345,17 @@ def test_parent_on_comprehension():
|
||||
|
||||
|
||||
def test_type(Script):
|
||||
for c in Script('a = [str()]; a[0].').completions():
|
||||
for c in Script('a = [str()]; a[0].').complete():
|
||||
if c.name == '__class__' and False: # TODO fix.
|
||||
assert c.type == 'class'
|
||||
else:
|
||||
assert c.type in ('function', 'statement')
|
||||
|
||||
for c in Script('list.').completions():
|
||||
for c in Script('list.').complete():
|
||||
assert c.type
|
||||
|
||||
# Github issue #397, type should never raise an error.
|
||||
for c in Script('import os; os.path.').completions():
|
||||
for c in Script('import os; os.path.').complete():
|
||||
assert c.type
|
||||
|
||||
|
||||
@@ -320,36 +363,36 @@ def test_type_II(Script):
|
||||
"""
|
||||
GitHub Issue #833, `keyword`s are seen as `module`s
|
||||
"""
|
||||
for c in Script('f').completions():
|
||||
for c in Script('f').complete():
|
||||
if c.name == 'for':
|
||||
assert c.type == 'keyword'
|
||||
|
||||
|
||||
"""
|
||||
This tests the BaseDefinition.goto_assignments function, not the jedi
|
||||
This tests the BaseDefinition.goto function, not the jedi
|
||||
function. They are not really different in functionality, but really
|
||||
different as an implementation.
|
||||
"""
|
||||
|
||||
|
||||
def test_goto_assignment_repetition(names):
|
||||
def test_goto_repetition(names):
|
||||
defs = names('a = 1; a', references=True, definitions=False)
|
||||
# Repeat on the same variable. Shouldn't change once we're on a
|
||||
# definition.
|
||||
for _ in range(3):
|
||||
assert len(defs) == 1
|
||||
ass = defs[0].goto_assignments()
|
||||
ass = defs[0].goto()
|
||||
assert ass[0].description == 'a = 1'
|
||||
|
||||
|
||||
def test_goto_assignments_named_params(names):
|
||||
def test_goto_named_params(names):
|
||||
src = """\
|
||||
def foo(a=1, bar=2):
|
||||
pass
|
||||
foo(bar=1)
|
||||
"""
|
||||
bar = names(dedent(src), references=True)[-1]
|
||||
param = bar.goto_assignments()[0]
|
||||
param = bar.goto()[0]
|
||||
assert (param.line, param.column) == (1, 13)
|
||||
assert param.type == 'param'
|
||||
|
||||
@@ -358,46 +401,46 @@ def test_class_call(names):
|
||||
src = 'from threading import Thread; Thread(group=1)'
|
||||
n = names(src, references=True)[-1]
|
||||
assert n.name == 'group'
|
||||
param_def = n.goto_assignments()[0]
|
||||
param_def = n.goto()[0]
|
||||
assert param_def.name == 'group'
|
||||
assert param_def.type == 'param'
|
||||
|
||||
|
||||
def test_parentheses(names):
|
||||
n = names('("").upper', references=True)[-1]
|
||||
assert n.goto_assignments()[0].name == 'upper'
|
||||
assert n.goto()[0].name == 'upper'
|
||||
|
||||
|
||||
def test_import(names):
|
||||
nms = names('from json import load', references=True)
|
||||
assert nms[0].name == 'json'
|
||||
assert nms[0].type == 'module'
|
||||
n = nms[0].goto_assignments()[0]
|
||||
n = nms[0].goto()[0]
|
||||
assert n.name == 'json'
|
||||
assert n.type == 'module'
|
||||
|
||||
assert nms[1].name == 'load'
|
||||
assert nms[1].type == 'function'
|
||||
n = nms[1].goto_assignments()[0]
|
||||
n = nms[1].goto()[0]
|
||||
assert n.name == 'load'
|
||||
assert n.type == 'function'
|
||||
|
||||
nms = names('import os; os.path', references=True)
|
||||
assert nms[0].name == 'os'
|
||||
assert nms[0].type == 'module'
|
||||
n = nms[0].goto_assignments()[0]
|
||||
n = nms[0].goto()[0]
|
||||
assert n.name == 'os'
|
||||
assert n.type == 'module'
|
||||
|
||||
n = nms[2].goto_assignments()[0]
|
||||
n = nms[2].goto()[0]
|
||||
assert n.name == 'path'
|
||||
assert n.type == 'module'
|
||||
|
||||
nms = names('import os.path', references=True)
|
||||
n = nms[0].goto_assignments()[0]
|
||||
n = nms[0].goto()[0]
|
||||
assert n.name == 'os'
|
||||
assert n.type == 'module'
|
||||
n = nms[1].goto_assignments()[0]
|
||||
n = nms[1].goto()[0]
|
||||
# This is very special, normally the name doesn't chance, but since
|
||||
# os.path is a sys.modules hack, it does.
|
||||
assert n.name in ('macpath', 'ntpath', 'posixpath', 'os2emxpath')
|
||||
@@ -409,7 +452,7 @@ def test_import_alias(names):
|
||||
assert nms[0].name == 'json'
|
||||
assert nms[0].type == 'module'
|
||||
assert nms[0]._name.tree_name.parent.type == 'dotted_as_name'
|
||||
n = nms[0].goto_assignments()[0]
|
||||
n = nms[0].goto()[0]
|
||||
assert n.name == 'json'
|
||||
assert n.type == 'module'
|
||||
assert n._name._value.tree_node.type == 'file_input'
|
||||
@@ -417,7 +460,7 @@ def test_import_alias(names):
|
||||
assert nms[1].name == 'foo'
|
||||
assert nms[1].type == 'module'
|
||||
assert nms[1]._name.tree_name.parent.type == 'dotted_as_name'
|
||||
ass = nms[1].goto_assignments()
|
||||
ass = nms[1].goto()
|
||||
assert len(ass) == 1
|
||||
assert ass[0].name == 'json'
|
||||
assert ass[0].type == 'module'
|
||||
@@ -430,7 +473,7 @@ def test_added_equals_to_params(Script):
|
||||
def foo(bar, baz):
|
||||
pass
|
||||
""")
|
||||
results = Script(source + rest_source).completions()
|
||||
results = Script(source + rest_source).complete()
|
||||
assert len(results) == 1
|
||||
return results[0]
|
||||
|
||||
@@ -449,7 +492,7 @@ def test_builtin_module_with_path(Script):
|
||||
a path or not. It shouldn't have a module_path, because that is just
|
||||
confusing.
|
||||
"""
|
||||
semlock, = Script('from _multiprocessing import SemLock').goto_definitions()
|
||||
semlock, = Script('from _multiprocessing import SemLock').infer()
|
||||
assert isinstance(semlock._name, CompiledValueName)
|
||||
assert semlock.module_path is None
|
||||
assert semlock.in_builtin_module() is True
|
||||
@@ -466,10 +509,32 @@ def test_builtin_module_with_path(Script):
|
||||
]
|
||||
)
|
||||
def test_execute(Script, code, description):
|
||||
definition, = Script(code).goto_assignments()
|
||||
definition, = Script(code).goto()
|
||||
definitions = definition.execute()
|
||||
if description is None:
|
||||
assert not definitions
|
||||
else:
|
||||
d, = definitions
|
||||
assert d.description == description
|
||||
|
||||
|
||||
@pytest.mark.parametrize('goto', [False, True, None])
|
||||
@pytest.mark.parametrize(
|
||||
'code, name, file_name', [
|
||||
('from pkg import Foo; Foo.foo', 'foo', '__init__.py'),
|
||||
('from pkg import Foo; Foo().foo', 'foo', '__init__.py'),
|
||||
('from pkg import Foo; Foo.bar', 'bar', 'module.py'),
|
||||
('from pkg import Foo; Foo().bar', 'bar', 'module.py'),
|
||||
])
|
||||
def test_inheritance_module_path(Script, goto, code, name, file_name):
|
||||
base_path = os.path.join(get_example_dir('inheritance'), 'pkg')
|
||||
whatever_path = os.path.join(base_path, 'NOT_EXISTING.py')
|
||||
|
||||
script = Script(code, path=whatever_path)
|
||||
if goto is None:
|
||||
func, = script.infer()
|
||||
else:
|
||||
func, = script.goto(follow_imports=goto)
|
||||
assert func.type == 'function'
|
||||
assert func.name == name
|
||||
assert func.module_path == os.path.join(base_path, file_name)
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
from os.path import join, sep as s
|
||||
from os.path import join, sep as s, dirname
|
||||
import os
|
||||
import sys
|
||||
from textwrap import dedent
|
||||
|
||||
import pytest
|
||||
|
||||
from ..helpers import root_dir
|
||||
from jedi.api.helpers import start_match, fuzzy_match
|
||||
|
||||
|
||||
def test_in_whitespace(Script):
|
||||
code = dedent('''
|
||||
def x():
|
||||
pass''')
|
||||
assert len(Script(code, column=2).completions()) > 20
|
||||
assert len(Script(code).complete(column=2)) > 20
|
||||
|
||||
|
||||
def test_empty_init(Script):
|
||||
@@ -18,7 +21,7 @@ def test_empty_init(Script):
|
||||
code = dedent('''\
|
||||
class X(object): pass
|
||||
X(''')
|
||||
assert Script(code).completions()
|
||||
assert Script(code).complete()
|
||||
|
||||
|
||||
def test_in_empty_space(Script):
|
||||
@@ -27,7 +30,7 @@ def test_in_empty_space(Script):
|
||||
def __init__(self):
|
||||
hello
|
||||
''')
|
||||
comps = Script(code, 3, 7).completions()
|
||||
comps = Script(code).complete(3, 7)
|
||||
self, = [c for c in comps if c.name == 'self']
|
||||
assert self.name == 'self'
|
||||
def_, = self.infer()
|
||||
@@ -40,13 +43,13 @@ def test_indent_value(Script):
|
||||
complete.
|
||||
"""
|
||||
code = 'if 1:\nisinstanc'
|
||||
comp, = Script(code).completions()
|
||||
comp, = Script(code).complete()
|
||||
assert comp.name == 'isinstance'
|
||||
|
||||
|
||||
def test_keyword_value(Script):
|
||||
def get_names(*args, **kwargs):
|
||||
return [d.name for d in Script(*args, **kwargs).completions()]
|
||||
return [d.name for d in Script(*args, **kwargs).complete()]
|
||||
|
||||
names = get_names('if 1:\n pass\n')
|
||||
assert 'if' in names
|
||||
@@ -55,7 +58,7 @@ def test_keyword_value(Script):
|
||||
|
||||
def test_os_nowait(Script):
|
||||
""" github issue #45 """
|
||||
s = Script("import os; os.P_").completions()
|
||||
s = Script("import os; os.P_").complete()
|
||||
assert 'P_NOWAIT' in [i.name for i in s]
|
||||
|
||||
|
||||
@@ -63,7 +66,7 @@ def test_points_in_completion(Script):
|
||||
"""At some point, points were inserted into the completions, this
|
||||
caused problems, sometimes.
|
||||
"""
|
||||
c = Script("if IndentationErr").completions()
|
||||
c = Script("if IndentationErr").complete()
|
||||
assert c[0].name == 'IndentationError'
|
||||
assert c[0].complete == 'or'
|
||||
|
||||
@@ -79,9 +82,8 @@ def test_loading_unicode_files_with_bad_global_charset(Script, monkeypatch, tmpd
|
||||
|
||||
with open(filename1, "wb") as f:
|
||||
f.write(data)
|
||||
s = Script("from test1 import foo\nfoo.",
|
||||
line=2, column=4, path=filename2)
|
||||
s.completions()
|
||||
s = Script("from test1 import foo\nfoo.", path=filename2)
|
||||
s.complete(line=2, column=4)
|
||||
|
||||
|
||||
def test_fake_subnodes(Script):
|
||||
@@ -99,7 +101,7 @@ def test_fake_subnodes(Script):
|
||||
return c
|
||||
limit = None
|
||||
for i in range(2):
|
||||
completions = Script('').completions()
|
||||
completions = Script('').complete()
|
||||
c = get_str_completion(completions)
|
||||
str_value, = c._name.infer()
|
||||
n = len(str_value.tree_node.children[-1].children)
|
||||
@@ -115,13 +117,17 @@ def test_generator(Script):
|
||||
s = "def abc():\n" \
|
||||
" yield 1\n" \
|
||||
"abc()."
|
||||
assert Script(s).completions()
|
||||
assert Script(s).complete()
|
||||
|
||||
|
||||
def test_in_comment(Script):
|
||||
assert Script(" # Comment").completions()
|
||||
assert Script(" # Comment").complete()
|
||||
# TODO this is a bit ugly, that the behaviors in comments are different.
|
||||
assert not Script("max_attr_value = int(2) # Cast to int for spe").completions()
|
||||
assert not Script("max_attr_value = int(2) # Cast to int for spe").complete()
|
||||
|
||||
|
||||
def test_in_comment_before_string(Script):
|
||||
assert not Script(" # Foo\n'asdf'").complete(line=1)
|
||||
|
||||
|
||||
def test_async(Script, environment):
|
||||
@@ -132,16 +138,15 @@ def test_async(Script, environment):
|
||||
foo = 3
|
||||
async def x():
|
||||
hey = 3
|
||||
ho'''
|
||||
)
|
||||
comps = Script(code, column=4).completions()
|
||||
ho''')
|
||||
comps = Script(code).complete(column=4)
|
||||
names = [c.name for c in comps]
|
||||
assert 'foo' in names
|
||||
assert 'hey' in names
|
||||
|
||||
|
||||
def test_with_stmt_error_recovery(Script):
|
||||
assert Script('with open('') as foo: foo.\na', line=1).completions()
|
||||
assert Script('with open('') as foo: foo.\na').complete(line=1)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -156,7 +161,7 @@ def test_with_stmt_error_recovery(Script):
|
||||
)
|
||||
)
|
||||
def test_keyword_completion(Script, code, has_keywords):
|
||||
assert has_keywords == any(x.is_keyword for x in Script(code).completions())
|
||||
assert has_keywords == any(x.is_keyword for x in Script(code).complete())
|
||||
|
||||
|
||||
f1 = join(root_dir, 'example.py')
|
||||
@@ -164,6 +169,7 @@ f2 = join(root_dir, 'test', 'example.py')
|
||||
os_path = 'from os.path import *\n'
|
||||
# os.path.sep escaped
|
||||
se = s * 2 if s == '\\' else s
|
||||
current_dirname = os.path.basename(dirname(dirname(dirname(__file__))))
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -181,7 +187,7 @@ se = s * 2 if s == '\\' else s
|
||||
('test%sexample.py' % se, 'r"test%scomp"' % s, 5, ['t' + s]),
|
||||
('test%sexample.py' % se, 'r"test%scomp"' % s, 11, ['letion' + s]),
|
||||
('test%sexample.py' % se, '"%s"' % join('test', 'completion', 'basi'), 21, ['c.py']),
|
||||
('example.py', 'rb"' + join('..', 'jedi', 'tes'), None, ['t' + s]),
|
||||
('example.py', 'rb"' + join('..', current_dirname, 'tes'), None, ['t' + s]),
|
||||
|
||||
# Absolute paths
|
||||
(None, '"' + join(root_dir, 'test', 'test_ca'), None, ['che.py"']),
|
||||
@@ -260,7 +266,7 @@ def test_file_path_completions(Script, file, code, column, expected):
|
||||
line = None
|
||||
if isinstance(column, tuple):
|
||||
line, column = column
|
||||
comps = Script(code, path=file, line=line, column=column).completions()
|
||||
comps = Script(code, path=file).complete(line=line, column=column)
|
||||
if expected == "A LOT":
|
||||
assert len(comps) > 100 # This is basically global completions.
|
||||
else:
|
||||
@@ -329,3 +335,19 @@ def test_dict_keys_completions(Script, added_code, column, expected, skip_pre_py
|
||||
expected = [e for e in expected if e is not Ellipsis]
|
||||
|
||||
assert [c.complete for c in comps] == expected
|
||||
|
||||
|
||||
def test_start_match():
|
||||
assert start_match('Condition', 'C')
|
||||
|
||||
|
||||
def test_fuzzy_match():
|
||||
assert fuzzy_match('Condition', 'i')
|
||||
assert not fuzzy_match('Condition', 'p')
|
||||
assert fuzzy_match('Condition', 'ii')
|
||||
assert not fuzzy_match('Condition', 'Ciito')
|
||||
assert fuzzy_match('Condition', 'Cdiio')
|
||||
|
||||
|
||||
def test_ellipsis_completion(Script):
|
||||
assert Script('...').completions() == []
|
||||
|
||||
115
test/test_api/test_context.py
Normal file
115
test/test_api/test_context.py
Normal file
@@ -0,0 +1,115 @@
|
||||
import pytest
|
||||
|
||||
|
||||
def _iter_hierarchy(context):
|
||||
def iter(context):
|
||||
while context is not None:
|
||||
yield context
|
||||
context = context.parent()
|
||||
|
||||
return reversed(list(iter(context)))
|
||||
|
||||
|
||||
func_code = '''\
|
||||
def func1(x, y):
|
||||
pass
|
||||
|
||||
def func2():
|
||||
what ?
|
||||
i = 3
|
||||
|
||||
def func3():
|
||||
1'''
|
||||
cls_code = '''\
|
||||
class Foo:
|
||||
def x():
|
||||
def y():
|
||||
pass
|
||||
'''
|
||||
cls_nested = '''\
|
||||
class C:
|
||||
class D:
|
||||
def f():
|
||||
pass
|
||||
'''
|
||||
lambda_ = '''\
|
||||
def x():
|
||||
(lambda x:
|
||||
lambda: y
|
||||
)
|
||||
'''
|
||||
comprehension = '''
|
||||
def f(x):
|
||||
[x
|
||||
for
|
||||
x
|
||||
in x
|
||||
]'''
|
||||
|
||||
with_brackets = '''\
|
||||
def x():
|
||||
[
|
||||
|
||||
]
|
||||
'''
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'code, line, column, full_name, expected_parents', [
|
||||
('', None, None, 'myfile', []),
|
||||
(' ', None, 0, 'myfile', []),
|
||||
|
||||
(func_code, 1, 0, 'myfile', []),
|
||||
(func_code, 1, None, 'myfile.func1', ['func1']),
|
||||
(func_code, 1, 1, 'myfile.func1', ['func1']),
|
||||
(func_code, 1, 4, 'myfile.func1', ['func1']),
|
||||
(func_code, 1, 10, 'myfile.func1', ['func1']),
|
||||
|
||||
(func_code, 3, 0, 'myfile', []),
|
||||
(func_code, 5, None, 'myfile.func2', ['func2']),
|
||||
(func_code, 6, None, 'myfile', []),
|
||||
(func_code, 7, None, 'myfile', []),
|
||||
(func_code, 9, None, 'myfile.func3', ['func3']),
|
||||
|
||||
(cls_code, None, None, 'myfile', []),
|
||||
(cls_code + ' ', None, None, 'myfile.Foo', ['Foo']),
|
||||
(cls_code + ' ' * 3, None, None, 'myfile.Foo', ['Foo']),
|
||||
(cls_code + ' ' * 4, None, None, 'myfile.Foo', ['Foo']),
|
||||
(cls_code + ' ' * 5, None, None, 'myfile.Foo.x', ['Foo', 'x']),
|
||||
(cls_code + ' ' * 8, None, None, 'myfile.Foo.x', ['Foo', 'x']),
|
||||
(cls_code + ' ' * 12, None, None, None, ['Foo', 'x', 'y']),
|
||||
|
||||
(cls_code, 4, 0, 'myfile', []),
|
||||
(cls_code, 4, 3, 'myfile.Foo', ['Foo']),
|
||||
(cls_code, 4, 4, 'myfile.Foo', ['Foo']),
|
||||
(cls_code, 4, 5, 'myfile.Foo.x', ['Foo', 'x']),
|
||||
(cls_code, 4, 8, 'myfile.Foo.x', ['Foo', 'x']),
|
||||
(cls_code, 4, 12, None, ['Foo', 'x', 'y']),
|
||||
(cls_code, 1, 1, 'myfile.Foo', ['Foo']),
|
||||
|
||||
(cls_nested, 4, None, 'myfile.C.D.f', ['C', 'D', 'f']),
|
||||
(cls_nested, 4, 3, 'myfile.C', ['C']),
|
||||
|
||||
(lambda_, 2, 9, 'myfile.x', ['x']), # the lambda keyword
|
||||
(lambda_, 2, 13, 'myfile.x', ['x']), # the lambda param
|
||||
(lambda_, 3, 0, 'myfile', []), # Within brackets, but they are ignored.
|
||||
(lambda_, 3, 8, 'myfile.x', ['x']),
|
||||
(lambda_, 3, None, 'myfile.x', ['x']),
|
||||
|
||||
(comprehension, 2, None, 'myfile.f', ['f']),
|
||||
(comprehension, 3, None, 'myfile.f', ['f']),
|
||||
(comprehension, 4, None, 'myfile.f', ['f']),
|
||||
(comprehension, 5, None, 'myfile.f', ['f']),
|
||||
(comprehension, 6, None, 'myfile.f', ['f']),
|
||||
|
||||
# Brackets are just ignored.
|
||||
(with_brackets, 3, None, 'myfile', []),
|
||||
(with_brackets, 4, 4, 'myfile.x', ['x']),
|
||||
(with_brackets, 4, 5, 'myfile.x', ['x']),
|
||||
]
|
||||
)
|
||||
def test_context(Script, code, line, column, full_name, expected_parents):
|
||||
context = Script(code, path='/foo/myfile.py').get_context(line, column)
|
||||
assert context.full_name == full_name
|
||||
parent_names = [d.name for d in _iter_hierarchy(context)]
|
||||
assert parent_names == ['myfile'] + expected_parents
|
||||
@@ -139,12 +139,12 @@ def test_follow_imports(names):
|
||||
|
||||
|
||||
def test_names_twice(names):
|
||||
source = dedent('''
|
||||
code = dedent('''
|
||||
def lol():
|
||||
pass
|
||||
''')
|
||||
|
||||
defs = names(source=source)
|
||||
defs = names(code)
|
||||
assert defs[0].defined_names() == []
|
||||
|
||||
|
||||
@@ -166,4 +166,4 @@ def test_no_error(names):
|
||||
assert a.name == 'a'
|
||||
assert b.name == 'b'
|
||||
assert a20.name == 'a'
|
||||
assert a20.goto_assignments() == [a20]
|
||||
assert a20.goto() == [a20]
|
||||
|
||||
77
test/test_api/test_documentation.py
Normal file
77
test/test_api/test_documentation.py
Normal file
@@ -0,0 +1,77 @@
|
||||
from textwrap import dedent
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
def test_error_leaf_keyword_doc(Script):
|
||||
d, = Script("or").help(1, 1)
|
||||
assert len(d.docstring()) > 100
|
||||
assert d.name == 'or'
|
||||
|
||||
|
||||
def test_error_leaf_operator_doc(Script):
|
||||
d, = Script("==").help()
|
||||
assert len(d.docstring()) > 100
|
||||
assert d.name == '=='
|
||||
|
||||
|
||||
def test_keyword_completion(Script):
|
||||
k = Script("fro").complete()[0]
|
||||
imp_start = 'The "import'
|
||||
assert k.docstring(raw=True).startswith(imp_start)
|
||||
assert k.docstring().startswith(imp_start)
|
||||
|
||||
|
||||
def test_import_keyword(Script):
|
||||
d, = Script("import x").help(column=0)
|
||||
assert d.docstring().startswith('The "import" statement')
|
||||
# unrelated to #44
|
||||
|
||||
|
||||
def test_import_keyword_with_gotos(goto_or_infer):
|
||||
assert not goto_or_infer("import x", column=0)
|
||||
|
||||
|
||||
def test_operator_doc(Script):
|
||||
d, = Script("a == b").help(1, 3)
|
||||
assert len(d.docstring()) > 100
|
||||
|
||||
|
||||
def test_lambda(Script):
|
||||
d, = Script('lambda x: x').help(column=0)
|
||||
assert d.type == 'keyword'
|
||||
assert d.docstring().startswith('Lambdas\n*******')
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'code, kwargs', [
|
||||
('?', {}),
|
||||
('""', {}),
|
||||
('"', {}),
|
||||
]
|
||||
)
|
||||
def test_help_no_returns(Script, code, kwargs):
|
||||
assert not Script(code).help(**kwargs)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'to_execute, expected_doc', [
|
||||
('X.x', 'Yeah '),
|
||||
('X().x', 'Yeah '),
|
||||
('X.y', 'f g '),
|
||||
('X.z', ''),
|
||||
]
|
||||
)
|
||||
def test_attribute_docstrings(goto_or_help, expected_doc, to_execute):
|
||||
code = dedent('''\
|
||||
class X:
|
||||
"ha"
|
||||
x = 3
|
||||
""" Yeah """
|
||||
y = 5
|
||||
"f g "
|
||||
z = lambda: 1
|
||||
''')
|
||||
|
||||
d, = goto_or_help(code + to_execute)
|
||||
assert d.docstring() == expected_doc
|
||||
@@ -66,13 +66,13 @@ def test_error_in_environment(inference_state, Script, environment):
|
||||
with pytest.raises(jedi.InternalError):
|
||||
inference_state.compiled_subprocess._test_raise_error(KeyboardInterrupt)
|
||||
# Jedi should still work.
|
||||
def_, = Script('str').goto_definitions()
|
||||
def_, = Script('str').infer()
|
||||
assert def_.name == 'str'
|
||||
|
||||
|
||||
def test_stdout_in_subprocess(inference_state, Script):
|
||||
inference_state.compiled_subprocess._test_print(stdout='.')
|
||||
Script('1').goto_definitions()
|
||||
Script('1').infer()
|
||||
|
||||
|
||||
def test_killed_subprocess(inference_state, Script, environment):
|
||||
@@ -83,9 +83,9 @@ def test_killed_subprocess(inference_state, Script, environment):
|
||||
# Since the process was terminated (and nobody knows about it) the first
|
||||
# Jedi call fails.
|
||||
with pytest.raises(jedi.InternalError):
|
||||
Script('str').goto_definitions()
|
||||
Script('str').infer()
|
||||
|
||||
def_, = Script('str').goto_definitions()
|
||||
def_, = Script('str').infer()
|
||||
# Jedi should now work again.
|
||||
assert def_.name == 'str'
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ class MixinTestFullName(object):
|
||||
|
||||
def check(self, source, desired):
|
||||
script = self.Script(textwrap.dedent(source))
|
||||
definitions = getattr(script, type(self).operation)()
|
||||
definitions = getattr(script, self.operation)()
|
||||
for d in definitions:
|
||||
self.assertEqual(d.full_name, desired)
|
||||
|
||||
@@ -43,7 +43,7 @@ class MixinTestFullName(object):
|
||||
|
||||
|
||||
class TestFullNameWithGotoDefinitions(MixinTestFullName, TestCase):
|
||||
operation = 'goto_definitions'
|
||||
operation = 'infer'
|
||||
|
||||
def test_tuple_mapping(self):
|
||||
if self.environment.version_info.major == 2:
|
||||
@@ -59,7 +59,7 @@ class TestFullNameWithGotoDefinitions(MixinTestFullName, TestCase):
|
||||
|
||||
|
||||
class TestFullNameWithCompletions(MixinTestFullName, TestCase):
|
||||
operation = 'completions'
|
||||
operation = 'complete'
|
||||
|
||||
|
||||
class TestFullDefinedName(TestCase):
|
||||
@@ -71,7 +71,8 @@ class TestFullDefinedName(TestCase):
|
||||
self.environment = environment
|
||||
|
||||
def check(self, source, desired):
|
||||
definitions = jedi.names(textwrap.dedent(source), environment=self.environment)
|
||||
script = jedi.Script(textwrap.dedent(source), environment=self.environment)
|
||||
definitions = script.names()
|
||||
full_names = [d.full_name for d in definitions]
|
||||
self.assertEqual(full_names, desired)
|
||||
|
||||
@@ -96,19 +97,19 @@ def test_sub_module(Script, jedi_path):
|
||||
path.
|
||||
"""
|
||||
sys_path = [jedi_path]
|
||||
defs = Script('from jedi.api import classes; classes', sys_path=sys_path).goto_definitions()
|
||||
defs = Script('from jedi.api import classes; classes', sys_path=sys_path).infer()
|
||||
assert [d.full_name for d in defs] == ['jedi.api.classes']
|
||||
defs = Script('import jedi.api; jedi.api', sys_path=sys_path).goto_definitions()
|
||||
defs = Script('import jedi.api; jedi.api', sys_path=sys_path).infer()
|
||||
assert [d.full_name for d in defs] == ['jedi.api']
|
||||
|
||||
|
||||
def test_os_path(Script):
|
||||
d, = Script('from os.path import join').completions()
|
||||
d, = Script('from os.path import join').complete()
|
||||
assert d.full_name == 'os.path.join'
|
||||
d, = Script('import os.p').completions()
|
||||
d, = Script('import os.p').complete()
|
||||
assert d.full_name == 'os.path'
|
||||
|
||||
|
||||
def test_os_issues(Script):
|
||||
"""Issue #873"""
|
||||
assert [c.name for c in Script('import os\nos.nt''').completions()] == ['nt']
|
||||
assert [c.name for c in Script('import os\nos.nt''').complete()] == ['nt']
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
Tests of ``jedi.api.Interpreter``.
|
||||
"""
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -25,7 +26,7 @@ class _GlobalNameSpace:
|
||||
|
||||
def get_completion(source, namespace):
|
||||
i = jedi.Interpreter(source, [namespace])
|
||||
completions = i.completions()
|
||||
completions = i.complete()
|
||||
assert len(completions) == 1
|
||||
return completions[0]
|
||||
|
||||
@@ -110,7 +111,7 @@ def test_side_effect_completion():
|
||||
def _assert_interpreter_complete(source, namespace, completions,
|
||||
**kwds):
|
||||
script = jedi.Interpreter(source, [namespace], **kwds)
|
||||
cs = script.completions()
|
||||
cs = script.complete()
|
||||
actual = [c.name for c in cs]
|
||||
assert sorted(actual) == sorted(completions)
|
||||
|
||||
@@ -197,13 +198,62 @@ def test_getitem_side_effects():
|
||||
_assert_interpreter_complete('foo["asdf"].upper', locals(), ['upper'])
|
||||
|
||||
|
||||
@pytest.mark.parametrize('stacklevel', [1, 2])
|
||||
@pytest.mark.filterwarnings("error")
|
||||
def test_property_warnings(stacklevel, allow_unsafe_getattr):
|
||||
class Foo3:
|
||||
@property
|
||||
def prop(self):
|
||||
# Possible side effects here, should therefore not call this.
|
||||
warnings.warn("foo", DeprecationWarning, stacklevel=stacklevel)
|
||||
return ''
|
||||
|
||||
foo = Foo3()
|
||||
expected = ['upper'] if allow_unsafe_getattr else []
|
||||
_assert_interpreter_complete('foo.prop.uppe', locals(), expected)
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info[0] == 2, reason="Ignore Python 2, because EOL")
|
||||
@pytest.mark.parametrize('class_is_findable', [False, True])
|
||||
def test__getattr__completions(allow_unsafe_getattr, class_is_findable):
|
||||
class CompleteGetattr(object):
|
||||
def __getattr__(self, name):
|
||||
if name == 'foo':
|
||||
return self
|
||||
if name == 'fbar':
|
||||
return ''
|
||||
raise AttributeError(name)
|
||||
|
||||
def __dir__(self):
|
||||
return ['foo', 'fbar'] + object.__dir__(self)
|
||||
|
||||
if not class_is_findable:
|
||||
CompleteGetattr.__name__ = "something_somewhere"
|
||||
namespace = {'c': CompleteGetattr()}
|
||||
expected = ['foo', 'fbar']
|
||||
_assert_interpreter_complete('c.f', namespace, expected)
|
||||
|
||||
# Completions don't work for class_is_findable, because __dir__ is checked
|
||||
# for interpreter analysis, but if the static analysis part tries to help
|
||||
# it will not work. However static analysis is pretty good and understands
|
||||
# how gettatr works (even the ifs/comparisons).
|
||||
if not allow_unsafe_getattr:
|
||||
expected = []
|
||||
_assert_interpreter_complete('c.foo.f', namespace, expected)
|
||||
_assert_interpreter_complete('c.foo.foo.f', namespace, expected)
|
||||
_assert_interpreter_complete('c.foo.uppe', namespace, [])
|
||||
|
||||
expected_int = ['upper'] if allow_unsafe_getattr or class_is_findable else []
|
||||
_assert_interpreter_complete('c.foo.fbar.uppe', namespace, expected_int)
|
||||
|
||||
|
||||
@pytest.fixture(params=[False, True])
|
||||
def allow_descriptor_access_or_not(request, monkeypatch):
|
||||
def allow_unsafe_getattr(request, monkeypatch):
|
||||
monkeypatch.setattr(jedi.Interpreter, '_allow_descriptor_getattr_default', request.param)
|
||||
return request.param
|
||||
|
||||
|
||||
def test_property_error_oldstyle(allow_descriptor_access_or_not):
|
||||
def test_property_error_oldstyle(allow_unsafe_getattr):
|
||||
lst = []
|
||||
class Foo3:
|
||||
@property
|
||||
@@ -215,14 +265,14 @@ def test_property_error_oldstyle(allow_descriptor_access_or_not):
|
||||
_assert_interpreter_complete('foo.bar', locals(), ['bar'])
|
||||
_assert_interpreter_complete('foo.bar.baz', locals(), [])
|
||||
|
||||
if allow_descriptor_access_or_not:
|
||||
if allow_unsafe_getattr:
|
||||
assert lst == [1, 1]
|
||||
else:
|
||||
# There should not be side effects
|
||||
assert lst == []
|
||||
|
||||
|
||||
def test_property_error_newstyle(allow_descriptor_access_or_not):
|
||||
def test_property_error_newstyle(allow_unsafe_getattr):
|
||||
lst = []
|
||||
class Foo3(object):
|
||||
@property
|
||||
@@ -234,7 +284,7 @@ def test_property_error_newstyle(allow_descriptor_access_or_not):
|
||||
_assert_interpreter_complete('foo.bar', locals(), ['bar'])
|
||||
_assert_interpreter_complete('foo.bar.baz', locals(), [])
|
||||
|
||||
if allow_descriptor_access_or_not:
|
||||
if allow_unsafe_getattr:
|
||||
assert lst == [1, 1]
|
||||
else:
|
||||
# There should not be side effects
|
||||
@@ -248,7 +298,7 @@ def test_property_content():
|
||||
return 1
|
||||
|
||||
foo = Foo3()
|
||||
def_, = jedi.Interpreter('foo.bar', [locals()]).goto_definitions()
|
||||
def_, = jedi.Interpreter('foo.bar', [locals()]).infer()
|
||||
assert def_.name == 'int'
|
||||
|
||||
|
||||
@@ -260,7 +310,7 @@ def test_param_completion():
|
||||
lambd = lambda xyz: 3
|
||||
|
||||
_assert_interpreter_complete('foo(bar', locals(), ['bar'])
|
||||
assert bool(jedi.Interpreter('lambd(xyz', [locals()]).completions()) == is_py3
|
||||
assert bool(jedi.Interpreter('lambd(xyz', [locals()]).complete()) == is_py3
|
||||
|
||||
|
||||
def test_endless_yield():
|
||||
@@ -275,7 +325,7 @@ def test_completion_params():
|
||||
foo = lambda a, b=3: None
|
||||
|
||||
script = jedi.Interpreter('foo', [locals()])
|
||||
c, = script.completions()
|
||||
c, = script.complete()
|
||||
assert [p.name for p in c.params] == ['a', 'b']
|
||||
assert c.params[0].infer() == []
|
||||
t, = c.params[1].infer()
|
||||
@@ -289,13 +339,13 @@ def test_completion_param_annotations():
|
||||
code = 'def foo(a: 1, b: str, c: int = 1.0) -> bytes: pass'
|
||||
exec_(code, locals())
|
||||
script = jedi.Interpreter('foo', [locals()])
|
||||
c, = script.completions()
|
||||
c, = script.complete()
|
||||
a, b, c = c.params
|
||||
assert a.infer() == []
|
||||
assert [d.name for d in b.infer()] == ['str']
|
||||
assert {d.name for d in c.infer()} == {'int', 'float'}
|
||||
|
||||
d, = jedi.Interpreter('foo()', [locals()]).goto_definitions()
|
||||
d, = jedi.Interpreter('foo()', [locals()]).infer()
|
||||
assert d.name == 'bytes'
|
||||
|
||||
|
||||
@@ -304,7 +354,7 @@ def test_keyword_argument():
|
||||
def f(some_keyword_argument):
|
||||
pass
|
||||
|
||||
c, = jedi.Interpreter("f(some_keyw", [{'f': f}]).completions()
|
||||
c, = jedi.Interpreter("f(some_keyw", [{'f': f}]).complete()
|
||||
assert c.name == 'some_keyword_argument'
|
||||
assert c.complete == 'ord_argument='
|
||||
|
||||
@@ -312,7 +362,7 @@ def test_keyword_argument():
|
||||
if is_py3:
|
||||
# Make it impossible for jedi to find the source of the function.
|
||||
f.__name__ = 'xSOMETHING'
|
||||
c, = jedi.Interpreter("x(some_keyw", [{'x': f}]).completions()
|
||||
c, = jedi.Interpreter("x(some_keyw", [{'x': f}]).complete()
|
||||
assert c.name == 'some_keyword_argument'
|
||||
|
||||
|
||||
@@ -326,12 +376,12 @@ def test_more_complex_instances():
|
||||
return Something()
|
||||
|
||||
#script = jedi.Interpreter('Base().wow().foo', [locals()])
|
||||
#c, = script.completions()
|
||||
#c, = script.complete()
|
||||
#assert c.name == 'foo'
|
||||
|
||||
x = Base()
|
||||
script = jedi.Interpreter('x.wow().foo', [locals()])
|
||||
c, = script.completions()
|
||||
c, = script.complete()
|
||||
assert c.name == 'foo'
|
||||
|
||||
|
||||
@@ -347,12 +397,12 @@ def test_repr_execution_issue():
|
||||
er = ErrorRepr()
|
||||
|
||||
script = jedi.Interpreter('er', [locals()])
|
||||
d, = script.goto_definitions()
|
||||
d, = script.infer()
|
||||
assert d.name == 'ErrorRepr'
|
||||
assert d.type == 'instance'
|
||||
|
||||
|
||||
def test_dir_magic_method():
|
||||
def test_dir_magic_method(allow_unsafe_getattr):
|
||||
class CompleteAttrs(object):
|
||||
def __getattr__(self, name):
|
||||
if name == 'foo':
|
||||
@@ -369,7 +419,7 @@ def test_dir_magic_method():
|
||||
return ['foo', 'bar'] + names
|
||||
|
||||
itp = jedi.Interpreter("ca.", [{'ca': CompleteAttrs()}])
|
||||
completions = itp.completions()
|
||||
completions = itp.complete()
|
||||
names = [c.name for c in completions]
|
||||
assert ('__dir__' in names) == is_py3
|
||||
assert '__class__' in names
|
||||
@@ -377,7 +427,12 @@ def test_dir_magic_method():
|
||||
assert 'bar' in names
|
||||
|
||||
foo = [c for c in completions if c.name == 'foo'][0]
|
||||
assert foo.infer() == []
|
||||
if allow_unsafe_getattr:
|
||||
inst, = foo.infer()
|
||||
assert inst.name == 'int'
|
||||
assert inst.type == 'instance'
|
||||
else:
|
||||
assert foo.infer() == []
|
||||
|
||||
|
||||
def test_name_not_findable():
|
||||
@@ -392,19 +447,19 @@ def test_name_not_findable():
|
||||
|
||||
setattr(X, 'NOT_FINDABLE', X.hidden)
|
||||
|
||||
assert jedi.Interpreter("X.NOT_FINDA", [locals()]).completions()
|
||||
assert jedi.Interpreter("X.NOT_FINDA", [locals()]).complete()
|
||||
|
||||
|
||||
def test_stubs_working():
|
||||
from multiprocessing import cpu_count
|
||||
defs = jedi.Interpreter("cpu_count()", [locals()]).goto_definitions()
|
||||
defs = jedi.Interpreter("cpu_count()", [locals()]).infer()
|
||||
assert [d.name for d in defs] == ['int']
|
||||
|
||||
|
||||
def test_sys_path_docstring(): # Was an issue in #1298
|
||||
import jedi
|
||||
s = jedi.Interpreter("from sys import path\npath", line=2, column=4, namespaces=[locals()])
|
||||
s.completions()[0].docstring()
|
||||
s = jedi.Interpreter("from sys import path\npath", namespaces=[locals()])
|
||||
s.complete(line=2, column=4)[0].docstring()
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info[0] == 2, reason="Ignore Python 2, because EOL")
|
||||
@@ -449,7 +504,7 @@ def test_simple_completions(code, completions):
|
||||
counter = collections.Counter(['asdf'])
|
||||
string = ''
|
||||
|
||||
defs = jedi.Interpreter(code, [locals()]).completions()
|
||||
defs = jedi.Interpreter(code, [locals()]).complete()
|
||||
assert [d.name for d in defs] == completions
|
||||
|
||||
|
||||
@@ -461,15 +516,16 @@ def test__wrapped__():
|
||||
def syslogs_to_df():
|
||||
pass
|
||||
|
||||
c, = jedi.Interpreter('syslogs_to_df', [locals()]).completions()
|
||||
c, = jedi.Interpreter('syslogs_to_df', [locals()]).complete()
|
||||
# Apparently the function starts on the line where the decorator starts.
|
||||
assert c.line == syslogs_to_df.__wrapped__.__code__.co_firstlineno + 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize('module_name', ['sys', 'time'])
|
||||
@pytest.mark.skipif(sys.version_info[0] == 2, reason="Ignore Python 2, because EOL")
|
||||
@pytest.mark.parametrize('module_name', ['sys', 'time', 'unittest.mock'])
|
||||
def test_core_module_completes(module_name):
|
||||
module = import_module(module_name)
|
||||
assert jedi.Interpreter(module_name + '.\n', [locals()]).completions()
|
||||
assert jedi.Interpreter('module.', [locals()]).complete()
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info[0] == 2, reason="Ignore Python 2, because EOL")
|
||||
@@ -492,7 +548,7 @@ def test_partial_signatures(code, expected, index):
|
||||
b = functools.partial(func, 1)
|
||||
c = functools.partial(func, 1, c=2)
|
||||
|
||||
sig, = jedi.Interpreter(code, [locals()]).call_signatures()
|
||||
sig, = jedi.Interpreter(code, [locals()]).find_signatures()
|
||||
assert sig.name == 'partial'
|
||||
assert [p.name for p in sig.params] == expected
|
||||
assert index == sig.index
|
||||
@@ -503,5 +559,19 @@ def test_type_var():
|
||||
"""This was an issue before, see Github #1369"""
|
||||
import typing
|
||||
x = typing.TypeVar('myvar')
|
||||
def_, = jedi.Interpreter('x', [locals()]).goto_definitions()
|
||||
def_, = jedi.Interpreter('x', [locals()]).infer()
|
||||
assert def_.name == 'TypeVar'
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info[0] == 2, reason="Ignore Python 2, because EOL")
|
||||
@pytest.mark.parametrize('class_is_findable', [False, True])
|
||||
def test_param_annotation_completion(class_is_findable):
|
||||
class Foo:
|
||||
bar = 3
|
||||
|
||||
if not class_is_findable:
|
||||
Foo.__name__ = 'asdf'
|
||||
|
||||
code = 'def CallFoo(x: Foo):\n x.ba'
|
||||
def_, = jedi.Interpreter(code, [locals()]).complete()
|
||||
assert def_.name == 'bar'
|
||||
|
||||
@@ -5,38 +5,38 @@ Test of keywords and ``jedi.keywords``
|
||||
import pytest
|
||||
|
||||
|
||||
def test_goto_assignments_keyword(Script):
|
||||
def test_goto_keyword(Script):
|
||||
"""
|
||||
Bug: goto assignments on ``in`` used to raise AttributeError::
|
||||
|
||||
'unicode' object has no attribute 'generate_call_path'
|
||||
"""
|
||||
Script('in').goto_assignments()
|
||||
Script('in').goto()
|
||||
|
||||
|
||||
def test_keyword(Script, environment):
|
||||
""" github jedi-vim issue #44 """
|
||||
defs = Script("print").goto_definitions()
|
||||
defs = Script("print").infer()
|
||||
if environment.version_info.major < 3:
|
||||
assert defs == []
|
||||
else:
|
||||
assert [d.docstring() for d in defs]
|
||||
|
||||
assert Script("import").goto_assignments() == []
|
||||
assert Script("import").goto() == []
|
||||
|
||||
completions = Script("import", 1, 1).completions()
|
||||
completions = Script("import").complete(1, 1)
|
||||
assert len(completions) > 10 and 'if' in [c.name for c in completions]
|
||||
assert Script("assert").goto_definitions() == []
|
||||
assert Script("assert").infer() == []
|
||||
|
||||
|
||||
def test_keyword_attributes(Script):
|
||||
def_, = Script('def').completions()
|
||||
def_, = Script('def').complete()
|
||||
assert def_.name == 'def'
|
||||
assert def_.complete == ''
|
||||
assert def_.is_keyword is True
|
||||
assert def_.is_stub() is False
|
||||
assert def_.goto_assignments(only_stubs=True) == []
|
||||
assert def_.goto_assignments() == []
|
||||
assert def_.goto(only_stubs=True) == []
|
||||
assert def_.goto() == []
|
||||
assert def_.infer() == []
|
||||
assert def_.parent() is None
|
||||
assert def_.docstring()
|
||||
@@ -55,6 +55,6 @@ def test_none_keyword(Script, environment):
|
||||
# Just don't care about Python 2 anymore, it's almost gone.
|
||||
pytest.skip()
|
||||
|
||||
none, = Script('None').completions()
|
||||
none, = Script('None').complete()
|
||||
assert not none.docstring()
|
||||
assert none.name == 'None'
|
||||
|
||||
@@ -11,7 +11,7 @@ def test_django_default_project(Script):
|
||||
"from app import models\nmodels.SomeMo",
|
||||
path=os.path.join(dir, 'models/x.py')
|
||||
)
|
||||
c, = script.completions()
|
||||
c, = script.complete()
|
||||
assert c.name == "SomeModel"
|
||||
assert script._inference_state.project._django is True
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ def test_add_dynamic_mods(Script):
|
||||
src2 = 'from .. import setup; setup.r(1)'
|
||||
script = Script(src1, path='../setup.py')
|
||||
imports.load_module(script._inference_state, os.path.abspath(fname), src2)
|
||||
result = script.goto_definitions()
|
||||
result = script.infer()
|
||||
assert len(result) == 1
|
||||
assert result[0].description == 'class int'
|
||||
|
||||
@@ -30,5 +30,5 @@ def test_add_bracket_after_function(monkeypatch, Script):
|
||||
def foo():
|
||||
pass
|
||||
foo''')
|
||||
completions = script.completions()
|
||||
completions = script.complete()
|
||||
assert completions[0].complete == '('
|
||||
|
||||
@@ -12,7 +12,7 @@ _tuple_code = 'from typing import Tuple\ndef f(x: Tuple[int]): ...\nf'
|
||||
('def f(x: int): ...\nf', ['instance int'], True),
|
||||
('from typing import List\ndef f(x: List[int]): ...\nf', ['instance list'], True),
|
||||
('from typing import List\ndef f(x: List[int]): ...\nf', ['class list'], False),
|
||||
(_tuple_code, ['Tuple: _SpecialForm = ...'], True),
|
||||
(_tuple_code, ['instance tuple'], True),
|
||||
(_tuple_code, ['Tuple: _SpecialForm = ...'], False),
|
||||
('x=str\ndef f(p: x): ...\nx=int\nf', ['instance int'], True),
|
||||
|
||||
@@ -21,7 +21,7 @@ _tuple_code = 'from typing import Tuple\ndef f(x: Tuple[int]): ...\nf'
|
||||
]
|
||||
)
|
||||
def test_param_annotation(Script, code, expected_params, execute_annotation, skip_python2):
|
||||
func, = Script(code).goto_assignments()
|
||||
func, = Script(code).goto()
|
||||
sig, = func.get_signatures()
|
||||
for p, expected in zip(sig.params, expected_params):
|
||||
annotations = p.infer_annotation(execute_annotation=execute_annotation)
|
||||
@@ -40,7 +40,7 @@ def test_param_annotation(Script, code, expected_params, execute_annotation, ski
|
||||
]
|
||||
)
|
||||
def test_param_default(Script, code, expected_params):
|
||||
func, = Script(code).goto_assignments()
|
||||
func, = Script(code).goto()
|
||||
sig, = func.get_signatures()
|
||||
for p, expected in zip(sig.params, expected_params):
|
||||
annotations = p.infer_default()
|
||||
@@ -62,7 +62,7 @@ def test_param_default(Script, code, expected_params):
|
||||
]
|
||||
)
|
||||
def test_param_kind_and_name(code, index, param_code, kind, Script, skip_python2):
|
||||
func, = Script(code).goto_assignments()
|
||||
func, = Script(code).goto()
|
||||
sig, = func.get_signatures()
|
||||
param = sig.params[index]
|
||||
assert param.to_string() == param_code
|
||||
@@ -70,5 +70,5 @@ def test_param_kind_and_name(code, index, param_code, kind, Script, skip_python2
|
||||
|
||||
|
||||
def test_staticmethod(Script):
|
||||
s, = Script('staticmethod(').call_signatures()
|
||||
assert s.to_string() == 'staticmethod(f: Callable)'
|
||||
s, = Script('staticmethod(').find_signatures()
|
||||
assert s.to_string() == 'staticmethod(f: Callable[..., Any])'
|
||||
|
||||
@@ -8,18 +8,18 @@ from jedi._compatibility import u, unicode
|
||||
def test_unicode_script(Script):
|
||||
""" normally no unicode objects are being used. (<=2.7) """
|
||||
s = unicode("import datetime; datetime.timedelta")
|
||||
completions = Script(s).completions()
|
||||
completions = Script(s).complete()
|
||||
assert len(completions)
|
||||
assert type(completions[0].description) is unicode
|
||||
|
||||
s = u("author='öä'; author")
|
||||
completions = Script(s).completions()
|
||||
completions = Script(s).complete()
|
||||
x = completions[0].description
|
||||
assert type(x) is unicode
|
||||
|
||||
s = u("#-*- coding: iso-8859-1 -*-\nauthor='öä'; author")
|
||||
s = s.encode('latin-1')
|
||||
completions = Script(s).completions()
|
||||
completions = Script(s).complete()
|
||||
assert type(completions[0].description) is unicode
|
||||
|
||||
|
||||
@@ -27,11 +27,11 @@ def test_unicode_attribute(Script):
|
||||
""" github jedi-vim issue #94 """
|
||||
s1 = u('#-*- coding: utf-8 -*-\nclass Person():\n'
|
||||
' name = "e"\n\nPerson().name.')
|
||||
completions1 = Script(s1).completions()
|
||||
completions1 = Script(s1).complete()
|
||||
assert 'strip' in [c.name for c in completions1]
|
||||
s2 = u('#-*- coding: utf-8 -*-\nclass Person():\n'
|
||||
' name = "é"\n\nPerson().name.')
|
||||
completions2 = Script(s2).completions()
|
||||
completions2 = Script(s2).complete()
|
||||
assert 'strip' in [c.name for c in completions2]
|
||||
|
||||
|
||||
@@ -44,24 +44,24 @@ def test_multibyte_script(Script):
|
||||
except NameError:
|
||||
pass # python 3 has no unicode method
|
||||
else:
|
||||
assert len(Script(s, 1, len(code)).completions())
|
||||
assert len(Script(s).complete(1, len(code)))
|
||||
|
||||
|
||||
def test_goto_definition_at_zero(Script):
|
||||
"""At zero usually sometimes raises unicode issues."""
|
||||
assert Script("a", 1, 1).goto_definitions() == []
|
||||
s = Script("str", 1, 1).goto_definitions()
|
||||
assert Script("a").infer(1, 1) == []
|
||||
s = Script("str").infer(1, 1)
|
||||
assert len(s) == 1
|
||||
assert list(s)[0].description == 'class str'
|
||||
assert Script("", 1, 0).goto_definitions() == []
|
||||
assert Script("").infer(1, 0) == []
|
||||
|
||||
|
||||
def test_complete_at_zero(Script):
|
||||
s = Script("str", 1, 3).completions()
|
||||
s = Script("str").complete(1, 3)
|
||||
assert len(s) == 1
|
||||
assert list(s)[0].name == 'str'
|
||||
|
||||
s = Script("", 1, 0).completions()
|
||||
s = Script("").complete(1, 0)
|
||||
assert len(s) > 0
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ def test_wrong_encoding(Script, tmpdir):
|
||||
# Use both latin-1 and utf-8 (a really broken file).
|
||||
x.write_binary(u'foobar = 1\nä'.encode('latin-1') + u'ä'.encode('utf-8'))
|
||||
|
||||
c, = Script('import x; x.foo', sys_path=[tmpdir.strpath]).completions()
|
||||
c, = Script('import x; x.foo', sys_path=[tmpdir.strpath]).complete()
|
||||
assert c.name == 'foobar'
|
||||
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
def test_import_usage(Script):
|
||||
s = Script("from .. import foo", line=1, column=18, path="foo.py")
|
||||
assert [usage.line for usage in s.usages()] == [1]
|
||||
def test_import_references(Script):
|
||||
s = Script("from .. import foo", path="foo.py")
|
||||
assert [usage.line for usage in s.find_references(line=1, column=18)] == [1]
|
||||
|
||||
|
||||
def test_exclude_builtin_modules(Script):
|
||||
def get(include):
|
||||
return [(d.line, d.column) for d in Script(source, column=8).usages(include_builtins=include)]
|
||||
references = Script(source).find_references(column=8, include_builtins=include)
|
||||
return [(d.line, d.column) for d in references]
|
||||
source = '''import sys\nprint(sys.path)'''
|
||||
places = get(include=True)
|
||||
assert len(places) > 2 # Includes stubs
|
||||
|
||||
Reference in New Issue
Block a user