1
0
forked from VimPlug/jedi

Merge branch 'master' into dict

This commit is contained in:
Dave Halter
2019-12-28 12:17:04 +01:00
153 changed files with 4231 additions and 1858 deletions

View File

@@ -1,4 +1,4 @@
"""
An import tree, for testing usages.
An import tree, for testing references.
"""

View File

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

View File

@@ -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']

View File

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

View File

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

View File

@@ -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() == []

View 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

View File

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

View 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

View File

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

View File

@@ -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']

View File

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

View File

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

View File

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

View File

@@ -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 == '('

View File

@@ -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])'

View File

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

View File

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