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
-29
View File
@@ -1,29 +0,0 @@
def test_keyword_doc(Script):
r = list(Script("or", 1, 1).goto_definitions())
assert len(r) == 1
assert len(r[0].doc) > 100
r = list(Script("asfdasfd", 1, 1).goto_definitions())
assert len(r) == 0
k = Script("fro").completions()[0]
imp_start = '\nThe ``import'
assert k.raw_doc.startswith(imp_start)
assert k.doc.startswith(imp_start)
def test_blablabla(Script):
defs = Script("import").goto_definitions()
assert len(defs) == 1 and [1 for d in defs if d.doc]
# unrelated to #44
def test_operator_doc(Script):
r = list(Script("a == b", 1, 3).goto_definitions())
assert len(r) == 1
assert len(r[0].doc) > 100
def test_lambda(Script):
defs = Script('lambda x: x', column=0).goto_definitions()
assert [d.type for d in defs] == ['keyword']
+3
View File
@@ -45,6 +45,9 @@ b[int():]
#? list()
b[:]
#? 3
b[:]
#? int()
b[:, 1]
#? int()
+84 -1
View File
@@ -188,14 +188,31 @@ def init_global_var_predefined():
global_var_predefined
def global_as_import():
from import_tree import globals
#? ['foo']
globals.foo
#? int()
globals.foo
global r
r = r[r]
if r:
r += r + 2
#? int()
r
# -----------------
# within docstrs
# -----------------
def a():
"""
#? ['global_define']
#? []
global_define
#?
str
"""
pass
@@ -284,6 +301,56 @@ except MyException as e:
for x in e.my_attr:
pass
# -----------------
# params
# -----------------
my_param = 1
#? 9 str()
def foo1(my_param):
my_param = 3.0
foo1("")
my_type = float()
#? 20 float()
def foo2(my_param: my_type):
pass
foo2("")
#? 20 int()
def foo3(my_param=my_param):
pass
foo3("")
some_default = ''
#? []
def foo(my_t
#? []
def foo(my_t, my_ty
#? ['some_default']
def foo(my_t=some_defa
#? ['some_default']
def foo(my_t=some_defa, my_t2=some_defa
# python > 2.7
#? ['my_type']
def foo(my_t: lala=some_defa, my_t2: my_typ
#? ['my_type']
def foo(my_t: lala=some_defa, my_t2: my_typ
#? []
def foo(my_t: lala=some_defa, my_t
#? []
lambda my_t
#? []
lambda my_, my_t
#? ['some_default']
lambda x=some_defa
#? ['some_default']
lambda y, x=some_defa
# Just make sure we're not in some weird parsing recovery after opening brackets
def
# -----------------
# continuations
@@ -326,3 +393,19 @@ with open('') as f1, open('') as f2:
f1.closed
#? ['closed']
f2.closed
class Foo():
def __enter__(self):
return ''
#? 14 str()
with Foo() as f3:
#? str()
f3
#! 14 ['with Foo() as f3: f3']
with Foo() as f3:
f3
#? 6 Foo
with Foo() as f3:
f3
+23
View File
@@ -382,6 +382,7 @@ getattr(getattr, 1)
getattr(str, [])
# python >= 3.5
class Base():
def ret(self, b):
return b
@@ -399,6 +400,12 @@ class Wrapper2():
#? int()
Wrapper(Base()).ret(3)
#? ['ret']
Wrapper(Base()).ret
#? int()
Wrapper(Wrapper(Base())).ret(3)
#? ['ret']
Wrapper(Wrapper(Base())).ret
#? int()
Wrapper2(Base()).ret(3)
@@ -409,6 +416,8 @@ class GetattrArray():
#? int()
GetattrArray().something[0]
#? []
GetattrArray().something
# -----------------
@@ -607,3 +616,17 @@ DefaultArg().y()
DefaultArg.x()
#? str()
DefaultArg.y()
# -----------------
# Error Recovery
# -----------------
from import_tree.pkg.base import MyBase
class C1(MyBase):
def f3(self):
#! 13 ['def f1']
self.f1() . # hey'''
#? 13 MyBase.f1
self.f1() . # hey'''
+1 -1
View File
@@ -20,7 +20,7 @@ tuple
class MyClass:
@pass_decorator
def x(foo,
#? 5 ["tuple"]
#? 5 []
tuple,
):
return 1
+17
View File
@@ -0,0 +1,17 @@
# Exists only for completion/pytest.py
import pytest
@pytest.fixture()
def my_other_conftest_fixture():
return 1.0
@pytest.fixture()
def my_conftest_fixture(my_other_conftest_fixture):
return my_other_conftest_fixture
def my_not_existing_fixture():
return 3 # Just a normal function
+13
View File
@@ -330,3 +330,16 @@ import abc
#? ['abstractmethod']
@abc.abstractmethod
# -----------------
# Goto
# -----------------
x = 1
#! 5 []
@x.foo()
def f(): pass
#! 1 ['x = 1']
@x.foo()
def f(): pass
+5
View File
@@ -335,6 +335,11 @@ some_lst2[3]
#? int() str()
some_lst2[2]
some_lst3 = []
some_lst3[0] = 3
some_lst3[:] = '' # Is ignored for now.
#? int()
some_lst3[0]
# -----------------
# set setitem/other modifications (should not work)
# -----------------
+8 -1
View File
@@ -1,4 +1,4 @@
# goto_assignments command tests are different in syntax
# goto command tests are different in syntax
definition = 3
#! 0 ['a = definition']
@@ -37,6 +37,7 @@ foo = 10;print(foo)
# classes
# -----------------
class C(object):
x = 3
def b(self):
#! ['b = math']
b
@@ -44,8 +45,14 @@ class C(object):
self.b
#! 14 ['def b']
self.b()
#! 14 ['def b']
self.b.
#! 11 ['param self']
self.b
#! ['x = 3']
self.x
#! 14 ['x = 3']
self.x.
return 1
#! ['def b']
+5
View File
@@ -0,0 +1,5 @@
def something():
global foo
foo = 3
+3
View File
@@ -0,0 +1,3 @@
class MyBase:
def f1(self):
pass
+76
View File
@@ -0,0 +1,76 @@
class Super(object):
attribute = 3
def func(self):
return 1
class Inner():
pass
class Sub(Super):
#? 13 Sub.attribute
def attribute(self):
pass
#! 8 ['attribute = 3']
def attribute(self):
pass
#! 4 ['def func']
func = 3
#! 12 ['def func']
class func(): pass
#! 8 ['class Inner']
def Inner(self): pass
# -----------------
# Finding self
# -----------------
class Test1:
class Test2:
def __init__(self):
self.foo_nested = 0
#? ['foo_nested']
self.foo_
#?
self.foo_here
def __init__(self, self2):
self.foo_here = 3
#? ['foo_here', 'foo_in_func']
self.foo_
#? int()
self.foo_here
#?
self.foo_nested
#?
self.foo_not_on_self
#? float()
self.foo_in_func
self2.foo_on_second = ''
def closure():
self.foo_in_func = 4.
def bar(self):
self = 3
self.foo_not_on_self = 3
class SubTest(Test1):
def __init__(self):
self.foo_sub_class = list
def bar(self):
#? ['foo_here', 'foo_in_func', 'foo_sub_class']
self.foo_
#? int()
self.foo_here
#?
self.foo_nested
#?
self.foo_not_on_self
+29
View File
@@ -60,3 +60,32 @@ Test().test(blub=)
#? 12 []
any(iterable=)
def foo(xyz):
pass
#? 7 ['xyz']
foo(xyz)
# No completion should be possible if it's not a simple name
#? 17 []
x = " "; foo(x.xyz)
#? 17 []
x = " "; foo([xyz)
#? 20 []
x = " "; foo(z[f,xyz)
#? 18 []
x = " "; foo(z[xyz)
#? 20 []
x = " "; foo(xyz[xyz)
#? 20 []
x = " "; foo(xyz[(xyz)
#? 8 ['xyz']
@foo(xyz)
def x(): pass
@str
#? 8 ['xyz']
@foo(xyz)
def x(): pass
+8 -4
View File
@@ -1,5 +1,5 @@
def from_names():
#? ['mod1']
#? ['mod1', 'base']
from import_tree.pkg.
#? ['path']
from os.
@@ -20,8 +20,12 @@ def builtin_test():
#? ['sqlite3']
import sqlite3
#? ['classes']
# classes is a local module that has an __init__.py and can therefore not be
# found. test can be found.
#? []
import classes
#? ['test']
import test
#? ['timedelta']
from datetime import timedel
@@ -69,9 +73,9 @@ from import_tree.pkg import pkg
from import_tree.pkg.mod1 import not_existant, # whitespace before
#? ['a', 'foobar', '__name__', '__doc__', '__file__', '__package__']
from import_tree.pkg.mod1 import not_existant,
#? 22 ['mod1']
#? 22 ['mod1', 'base']
from import_tree.pkg. import mod1
#? 17 ['mod1', 'mod2', 'random', 'pkg', 'rename1', 'rename2', 'classes', 'recurse_class1', 'recurse_class2', 'invisible_pkg', 'flow_import']
#? 17 ['mod1', 'mod2', 'random', 'pkg', 'rename1', 'rename2', 'classes', 'globals', 'recurse_class1', 'recurse_class2', 'invisible_pkg', 'flow_import']
from import_tree. import pkg
#? 18 ['pkg']
+1 -1
View File
@@ -40,4 +40,4 @@ str(def
class Foo(object):
@property
#? ['str']
def bar(str
def bar(x=str
+1 -1
View File
@@ -44,7 +44,7 @@ def return_none() -> None:
"""
pass
#?
#? None
return_none()
+14
View File
@@ -38,6 +38,20 @@ def test(a, b):
#? str()
e
class AA:
class BB:
pass
def test(a):
# type: (AA.BB) -> None
#? AA.BB()
a
def test(a):
# type: (AA.BB,) -> None
#? AA.BB()
a
a,b = 1, 2 # type: str, float
#? str()
a
+74
View File
@@ -0,0 +1,74 @@
# python >= 3.6
from typing import List, Dict, overload
lst: list
list_alias: List
list_str: List[str]
list_str: List[int]
# -------------------------
# With base classes
# -------------------------
@overload
def overload_f2(value: List) -> str: ...
@overload
def overload_f2(value: Dict) -> int: ...
#? str()
overload_f2([''])
#? int()
overload_f2({1.0: 1.0})
#? str()
overload_f2(lst)
#? str()
overload_f2(list_alias)
#? str()
overload_f2(list_str)
@overload
def overload_f3(value: list) -> str: ...
@overload
def overload_f3(value: dict) -> float: ...
#? str()
overload_f3([''])
#? float()
overload_f3({1.0: 1.0})
#? str()
overload_f3(lst)
#? str()
overload_f3(list_alias)
#? str()
overload_f3(list_str)
# -------------------------
# Generics Matching
# -------------------------
@overload
def overload_f1(value: List[str]) -> str: ...
@overload
def overload_f1(value: Dict[str, str]) -> Dict[str, str]: ...
def overload_f1():
pass
#? str()
overload_f1([''])
#? str() dict()
overload_f1(1)
#? dict()
overload_f1({'': ''})
#? str() dict()
overload_f1(lst)
#? str() dict()
overload_f1(list_alias)
#? str()
overload_f1(list_str)
#? str() dict()
overload_f1(list_int)
+57 -1
View File
@@ -99,6 +99,8 @@ def tuple(p, q, r):
"""
#? int()
p[0]
#? ['index']
p.index
#? int()
q[0]
#? str()
@@ -214,7 +216,7 @@ def union(p, q, r, s, t):
r
#? int() str() float() dict()
s
#? int()
#? int() None
t
def optional(p):
@@ -363,6 +365,17 @@ in_out1(str())
#?
in_out1()
def type_in_out1(x: typing.Type[TYPE_VARX]) -> TYPE_VARX: ...
#? int()
type_in_out1(int)
#? str()
type_in_out1(str)
#? float()
type_in_out1(float)
#?
type_in_out1()
def in_out2(x: TYPE_VAR_CONSTRAINTSX) -> TYPE_VAR_CONSTRAINTSX: ...
#? int()
@@ -377,6 +390,49 @@ in_out2()
#? float()
in_out2(1.0)
def type_in_out2(x: typing.Type[TYPE_VAR_CONSTRAINTSX]) -> TYPE_VAR_CONSTRAINTSX: ...
#? int()
type_in_out2(int)
#? str()
type_in_out2(str)
#? str() int()
type_in_out2()
# TODO this should actually be str() int(), because of the constraints.
#? float()
type_in_out2(float)
def ma(a: typing.Callable[[str], TYPE_VARX]) -> typing.Callable[[str], TYPE_VARX]:
return a
def mf(s: str) -> int:
return int(s)
#? int()
ma(mf)('2')
def xxx(x: typing.Iterable[TYPE_VARX]) -> typing.Tuple[str, TYPE_VARX]: ...
#? str()
xxx([0])[0]
#? int()
xxx([0])[1]
#?
xxx([0])[2]
def call_pls() -> typing.Callable[[TYPE_VARX], TYPE_VARX]: ...
#? int()
call_pls()(1)
def call2_pls() -> typing.Callable[[str, typing.Callable[[int], TYPE_VARX]], TYPE_VARX]: ...
#? float()
call2_pls('')(1, lambda x: 3.0)
def call3_pls() -> typing.Callable[[typing.Callable[[int], TYPE_VARX]], typing.List[TYPE_VARX]]: ...
def the_callable() -> float: ...
#? float()
call3_pls()(the_callable)[0]
# -------------------------
# TYPE_CHECKING
# -------------------------
+138
View File
@@ -0,0 +1,138 @@
# python > 2.7
import pytest
from pytest import fixture
@pytest.fixture(scope='module')
def my_fixture() -> str:
pass
@fixture
def my_simple_fixture():
return 1
@fixture
def my_yield_fixture():
yield 1
@fixture
class MyClassFixture():
pass
# -----------------
# goto/infer
# -----------------
#! 18 ['def my_conftest_fixture']
def test_x(my_conftest_fixture, my_fixture, my_not_existing_fixture, my_yield_fixture):
#? str()
my_fixture
#? int()
my_yield_fixture
#?
my_not_existing_fixture
#? float()
return my_conftest_fixture
#? 18 float()
def test_x(my_conftest_fixture, my_fixture):
pass
#! 18 ['param MyClassFixture']
def test_x(MyClassFixture):
#?
MyClassFixture
#? 15
def lala(my_fixture):
pass
@pytest.fixture
#? 15 str()
def lala(my_fixture):
pass
#! 15 ['param my_fixture']
def lala(my_fixture):
pass
@pytest.fixture
#! 15 ['def my_fixture']
def lala(my_fixture):
pass
# -----------------
# completion
# -----------------
#? 34 ['my_fixture']
def test_x(my_simple_fixture, my_fixture):
return
#? 34 ['my_fixture']
def test_x(my_simple_fixture, my_fixture):
return
#? ['my_fixture']
def test_x(my_simple_fixture, my_f
return
#? 18 ['my_simple_fixture']
def test_x(my_simple_fixture):
return
#? ['my_simple_fixture']
def test_x(my_simp
return
#? ['my_conftest_fixture']
def test_x(my_con
return
#? 18 ['my_conftest_fixture']
def test_x(my_conftest_fixture):
return
#? []
def lala(my_con
return
@pytest.fixture
#? ['my_conftest_fixture']
def lala(my_con
return
@pytest.fixture
#? 15 ['my_conftest_fixture']
def lala(my_con):
return
@pytest.fixture
@some_decorator
#? ['my_conftest_fixture']
def lala(my_con
return
@pytest.fixture
@some_decorator
#? 15 ['my_conftest_fixture']
def lala(my_con):
return
# -----------------
# pytest owned fixtures
# -----------------
#? ['monkeypatch']
def test_p(monkeyp
#! 15 ['def monkeypatch']
def test_p(monkeypatch):
#? ['setattr']
monkeypatch.setatt
#? ['capsysbinary']
def test_p(capsysbin
#? ['tmpdir', 'tmpdir_factory']
def test_p(tmpdi
+74
View File
@@ -190,6 +190,10 @@ def huhu(db):
#? sqlite3.Connection()
db
with sqlite3.connect() as c:
#? sqlite3.Connection()
c
# -----------------
# hashlib
# -----------------
@@ -288,6 +292,55 @@ for part in qsplit:
#? str()
part
# -----------------
# staticmethod, classmethod params
# -----------------
class F():
def __init__(self):
self.my_variable = 3
@staticmethod
def my_func(param):
#? []
param.my_
#? ['upper']
param.uppe
#? str()
return param
@staticmethod
def my_func_without_call(param):
#? []
param.my_
#? []
param.uppe
#?
return param
@classmethod
def my_method_without_call(cls, param):
#?
cls.my_variable
#? ['my_method', 'my_method_without_call']
cls.my_meth
#?
return param
@classmethod
def my_method(cls, param):
#?
cls.my_variable
#? ['my_method', 'my_method_without_call']
cls.my_meth
#?
return param
#? str()
F.my_func('')
#? str()
F.my_method('')
# -----------------
# Unknown metaclass
# -----------------
@@ -329,3 +382,24 @@ X.attr_y.value
X().name
#? float()
X().attr_x.attr_y.value
# -----------------
# functools Python 3.8
# -----------------
# python >= 3.8
@functools.lru_cache
def x() -> int: ...
@functools.lru_cache()
def y() -> float: ...
@functools.lru_cache(8)
def z() -> str: ...
#? int()
x()
#? float()
y()
#? str()
z()
@@ -1 +1,9 @@
in_stub_only: int
class Foo(Bar):
pass
class Bar:
pass
+1 -1
View File
@@ -1,7 +1,7 @@
from jedi import functions, inference, parsing
el = functions.completions()[0]
el = functions.complete()[0]
#? ['description']
el.description
+62 -27
View File
@@ -1,36 +1,36 @@
"""
Renaming tests. This means search for usages.
Renaming tests. This means search for references.
I always leave a little bit of space to add room for additions, because the
results always contain position informations.
"""
#< 4 (0,4), (3,0), (5,0), (17,0), (12,4), (14,5), (15,0)
def abc(): pass
#< 4 (0,4), (3,0), (5,0), (12,4), (14,5), (15,0), (17,0), (19,0)
def abcd(): pass
#< 0 (-3,4), (0,0), (2,0), (14,0), (9,4), (11,5), (12,0)
abc.d.a.bsaasd.abc.d
#< 0 (-3,4), (0,0), (2,0), (9,4), (11,5), (12,0), (14,0), (16,0)
abcd.d.a.bsaasd.abcd.d
abc
abcd
# unicode chars shouldn't be a problem.
x['smörbröd'].abc
x['smörbröd'].abcd
# With the new parser these statements are not recognized as stateents, because
# they are not valid Python.
if 1:
abc =
abcd =
else:
(abc) =
abc =
#< (-17,4), (-14,0), (-12,0), (0,0), (-2,0), (-3,5), (-5,4)
abc
(abcd) =
abcd =
#< (-17,4), (-14,0), (-12,0), (0,0), (2,0), (-2,0), (-3,5), (-5,4)
abcd
abc = 5
abcd = 5
Abc = 3
#< 6 (0,6), (2,4), (5,8), (17,0)
#< 6 (-3,0), (0,6), (2,4), (5,8), (17,0)
class Abc():
#< (-2,6), (0,4), (3,8), (15,0)
#< (-5,0), (-2,6), (0,4), (2,8), (3,8), (15,0)
Abc
def Abc(self):
@@ -63,13 +63,20 @@ def a(): pass
set_object_var = object()
set_object_var.var = 1
def func(a, b):
a = 12
#< 4 (0,4), (3,8)
c = a
if True:
#< 8 (-3,4), (0,8)
c = b
response = 5
#< 0 (0,0), (1,0), (2,0), (4,0)
#< 0 (-2,0), (0,0), (1,0), (2,0), (4,0)
response = HttpResponse(mimetype='application/pdf')
response['Content-Disposition'] = 'attachment; filename=%s.pdf' % id
response.write(pdf)
#< (-4,0), (-3,0), (-2,0), (0,0)
#< (-6,0), (-4,0), (-3,0), (-2,0), (0,0)
response
@@ -215,18 +222,18 @@ class TestProperty:
self.prop
@property
#< 13 (0,8), (4,5)
#< 13 (0,8), (4,5), (6,8), (11,13)
def rw_prop(self):
return self._rw_prop
#< 8 (-4,8), (0,5)
#< 8 (-4,8), (0,5), (2,8), (7,13)
@rw_prop.setter
#< 8 (0,8), (5,13)
#< 8 (-6,8), (-2,5), (0,8), (5,13)
def rw_prop(self, value):
self._rw_prop = value
def b(self):
#< 13 (-5,8), (0,13)
#< 13 (-11,8), (-7,5), (-5,8), (0,13)
self.rw_prop
# -----------------
@@ -287,9 +294,9 @@ x = 32
[x for x in x]
#< 0 (0,0), (2,1), (2,12)
x = 32
y = 32
#< 12 (-2,0), (0,1), (0,12)
[x for b in x]
[y for b in y]
#< 1 (0,1), (0,7)
@@ -297,13 +304,13 @@ x = 32
#< 7 (0,1), (0,7)
[x for x in something]
x = 3
z = 3
#< 1 (0,1), (0,10)
{x:1 for x in something}
{z:1 for z in something}
#< 10 (0,1), (0,10)
{x:1 for x in something}
{z:1 for z in something}
def x():
def whatever_func():
zzz = 3
if UNDEFINED:
zzz = 5
@@ -314,3 +321,31 @@ def x():
#< (0, 8), (1, 4), (-3, 12), (-6, 8), (-8, 4)
zzz
zzz
# -----------------
# global
# -----------------
def global_usage1():
#< (0, 4), (4, 11), (6, 4), (9, 8), (12, 4)
my_global
def global_definition():
#< (-4, 4), (0, 11), (2, 4), (5, 8), (8, 4)
global my_global
#< 4 (-6, 4), (-2, 11), (0, 4), (3, 8), (6, 4)
my_global = 3
if WHATEVER:
#< 8 (-9, 4), (-5, 11), (-3, 4), (0, 8), (3, 4)
my_global = 4
def global_usage2()
my_global
def not_global(my_global):
my_global
class DefinitelyNotGlobal:
def my_global(self):
def my_global(self):
pass
+16 -41
View File
@@ -10,7 +10,7 @@ from . import refactor
import jedi
from jedi.api.environment import InterpreterEnvironment
from jedi.inference.analysis import Warning
from jedi.inference.compiled.value import create_from_access_path
def pytest_addoption(parser):
@@ -85,46 +85,7 @@ def collect_static_analysis_tests(base_dir, test_files):
files_to_execute = [a for a in test_files.items() if a[0] in f_name]
if f_name.endswith(".py") and (not test_files or files_to_execute):
path = os.path.join(base_dir, f_name)
yield StaticAnalysisCase(path)
class StaticAnalysisCase(object):
"""
Static Analysis cases lie in the static_analysis folder.
The tests also start with `#!`, like the goto_definition tests.
"""
def __init__(self, path):
self._path = path
self.name = os.path.basename(path)
with open(path) as f:
self._source = f.read()
self.skip = False
for line in self._source.splitlines():
self.skip = self.skip or run.skip_python_version(line)
def collect_comparison(self):
cases = []
for line_nr, line in enumerate(self._source.splitlines(), 1):
match = re.match(r'(\s*)#! (\d+ )?(.*)$', line)
if match is not None:
column = int(match.group(2) or 0) + len(match.group(1))
cases.append((line_nr + 1, column, match.group(3)))
return cases
def run(self, compare_cb, environment):
analysis = jedi.Script(
self._source,
path=self._path,
environment=environment,
)._analysis()
typ_str = lambda inst: 'warning ' if isinstance(inst, Warning) else ''
analysis = [(r.line, r.column, typ_str(r) + r.name)
for r in analysis]
compare_cb(self, analysis, self.collect_comparison())
def __repr__(self):
return "<%s: %s>" % (self.__class__.__name__, os.path.basename(self._path))
yield run.StaticAnalysisCase(path)
@pytest.fixture(scope='session')
@@ -169,3 +130,17 @@ def inference_state(Script):
@pytest.fixture
def same_process_inference_state(Script):
return Script('', environment=InterpreterEnvironment())._inference_state
@pytest.fixture
def disable_typeshed(monkeypatch):
from jedi.inference.gradual import typeshed
monkeypatch.setattr(typeshed, '_load_from_typeshed', lambda *args, **kwargs: None)
@pytest.fixture
def create_compiled_object(inference_state):
return lambda obj: create_from_access_path(
inference_state,
inference_state.compiled_subprocess.create_simple_object(obj)
)
@@ -0,0 +1,6 @@
from .module import Bar
class Foo(Bar):
def foo(self):
pass
+4
View File
@@ -0,0 +1,4 @@
class Bar:
def bar(self):
pass
+2
View File
@@ -0,0 +1,2 @@
def with_overload(x, y: int) -> list:
pass
+8
View File
@@ -0,0 +1,8 @@
from typing import overload
@overload
def with_overload(x: int, y: int) -> float: ...
@overload
def with_overload(x: str, y: list) -> float: ...
+1 -1
View File
@@ -1,6 +1,6 @@
"""
Test coverage for renaming is mostly being done by testing
`Script.usages`.
`Script.find_references`.
"""
# --- simple
+98 -46
View File
@@ -10,9 +10,9 @@ tests.
There are different kind of tests:
- completions / goto_definitions ``#?``
- goto_assignments: ``#!``
- usages: ``#<``
- completions / inference ``#?``
- goto: ``#!``
- references: ``#<``
How to run tests?
+++++++++++++++++
@@ -26,7 +26,7 @@ multiple Python versions.
Integration test cases are located in ``test/completion`` directory
and each test case is indicated by either the comment ``#?`` (completions /
definitions), ``#!`` (assignments), or ``#<`` (usages).
inference), ``#!`` (goto), or ``#<`` (references).
There is also support for third party libraries. In a normal test run they are
not being executed, you have to provide a ``--thirdparty`` option.
@@ -76,17 +76,17 @@ For example::
Because it follows ``a.rea`` and a is an ``int``, which has a ``real``
property.
Goto Definitions
++++++++++++++++
Inference
+++++++++
Definition tests use the same symbols like completion tests. This is
Inference tests use the same symbols like completion tests. This is
possible because the completion tests are defined with a list::
#? int()
ab = 3; ab
Goto Assignments
++++++++++++++++
Goto
++++
Tests look like this::
@@ -100,8 +100,8 @@ describes the position of the test (otherwise it's just the end of line)::
#! 2 ['abc=1']
abc
Usages
++++++
References
++++++++++
Tests look like this::
@@ -118,6 +118,8 @@ from io import StringIO
from functools import reduce
import parso
from _pytest.outcomes import Skipped
import pytest
import jedi
from jedi import debug
@@ -127,27 +129,20 @@ from jedi.api.completion import get_user_context
from jedi import parser_utils
from jedi.api.environment import get_default_environment, get_system_environment
from jedi.inference.gradual.conversion import convert_values
from jedi.inference.analysis import Warning
TEST_COMPLETIONS = 0
TEST_DEFINITIONS = 1
TEST_ASSIGNMENTS = 2
TEST_USAGES = 3
TEST_INFERENCE = 1
TEST_GOTO = 2
TEST_REFERENCES = 3
grammar36 = parso.load_grammar(version='3.6')
class IntegrationTestCase(object):
def __init__(self, test_type, correct, line_nr, column, start, line,
path=None, skip_version_info=None):
self.test_type = test_type
self.correct = correct
self.line_nr = line_nr
self.column = column
self.start = start
self.line = line
self.path = path
class BaseTestCase(object):
def __init__(self, skip_version_info=None):
self._skip_version_info = skip_version_info
self._skip = None
@@ -175,6 +170,19 @@ class IntegrationTestCase(object):
operator_, min_version[0], min_version[1]
)
class IntegrationTestCase(BaseTestCase):
def __init__(self, test_type, correct, line_nr, column, start, line,
path=None, skip_version_info=None):
super(IntegrationTestCase, self).__init__(skip_version_info)
self.test_type = test_type
self.correct = correct
self.line_nr = line_nr
self.column = column
self.start = start
self.line = line
self.path = path
@property
def module_name(self):
return os.path.splitext(os.path.basename(self.path))[0]
@@ -189,28 +197,30 @@ class IntegrationTestCase(object):
self.line_nr_test, self.line.rstrip())
def script(self, environment):
return jedi.Script(
self.source, self.line_nr, self.column, self.path,
environment=environment
)
return jedi.Script(self.source, path=self.path, environment=environment)
def run(self, compare_cb, environment=None):
testers = {
TEST_COMPLETIONS: self.run_completion,
TEST_DEFINITIONS: self.run_goto_definitions,
TEST_ASSIGNMENTS: self.run_goto_assignments,
TEST_USAGES: self.run_usages,
TEST_INFERENCE: self.run_inference,
TEST_GOTO: self.run_goto,
TEST_REFERENCES: self.run_find_references,
}
if self.path.endswith('pytest.py') and environment.executable != sys.executable:
# It's not guarantueed that pytest is installed in test
# environments, if we're not running in the same environment that
# we're already in, so just skip that case.
pytest.skip()
return testers[self.test_type](compare_cb, environment)
def run_completion(self, compare_cb, environment):
completions = self.script(environment).completions()
#import cProfile; cProfile.run('script.completions()')
completions = self.script(environment).complete(self.line_nr, self.column)
# import cProfile; cProfile.run('...')
comp_str = {c.name for c in completions}
return compare_cb(self, comp_str, set(literal_eval(self.correct)))
def run_goto_definitions(self, compare_cb, environment):
def run_inference(self, compare_cb, environment):
script = self.script(environment)
inference_state = script._inference_state
@@ -227,9 +237,6 @@ class IntegrationTestCase(object):
node = parser.get_root_node()
module_context = script._get_module_context()
user_context = get_user_context(module_context, (self.line_nr, 0))
# TODO needed?
#if user_context._value.api_type == 'function':
# user_context = user_context.get_function_execution()
node.parent = user_context.tree_node
results = convert_values(user_context.infer_node(node))
if not results:
@@ -244,17 +251,17 @@ class IntegrationTestCase(object):
return should
should = definition(self.correct, self.start, script.path)
result = script.goto_definitions()
result = script.infer(self.line_nr, self.column)
is_str = set(comparison(r) for r in result)
return compare_cb(self, is_str, should)
def run_goto_assignments(self, compare_cb, environment):
result = self.script(environment).goto_assignments()
def run_goto(self, compare_cb, environment):
result = self.script(environment).goto(self.line_nr, self.column)
comp_str = str(sorted(str(r.description) for r in result))
return compare_cb(self, comp_str, self.correct)
def run_usages(self, compare_cb, environment):
result = self.script(environment).usages()
def run_find_references(self, compare_cb, environment):
result = self.script(environment).find_references(self.line_nr, self.column)
self.correct = self.correct.strip()
compare = sorted(
(re.sub(r'^test\.completion\.', '', r.module_name), r.line, r.column)
@@ -278,6 +285,49 @@ class IntegrationTestCase(object):
return compare_cb(self, compare, sorted(wanted))
class StaticAnalysisCase(BaseTestCase):
"""
Static Analysis cases lie in the static_analysis folder.
The tests also start with `#!`, like the inference tests.
"""
def __init__(self, path):
self._path = path
self.name = os.path.basename(path)
with open(path) as f:
self._source = f.read()
skip_version_info = None
for line in self._source.splitlines():
skip_version_info = skip_python_version(line) or skip_version_info
super(StaticAnalysisCase, self).__init__(skip_version_info)
def collect_comparison(self):
cases = []
for line_nr, line in enumerate(self._source.splitlines(), 1):
match = re.match(r'(\s*)#! (\d+ )?(.*)$', line)
if match is not None:
column = int(match.group(2) or 0) + len(match.group(1))
cases.append((line_nr + 1, column, match.group(3)))
return cases
def run(self, compare_cb, environment):
def typ_str(inst):
return 'warning ' if isinstance(inst, Warning) else ''
analysis = jedi.Script(
self._source,
path=self._path,
environment=environment,
)._analysis()
analysis = [(r.line, r.column, typ_str(r) + r.name)
for r in analysis]
compare_cb(self, analysis, self.collect_comparison())
def __repr__(self):
return "<%s: %s>" % (self.__class__.__name__, os.path.basename(self._path))
def skip_python_version(line):
# check for python minimal version number
match = re.match(r" *# *python *([<>]=?|==) *(\d+(?:\.\d+)?)$", line)
@@ -307,19 +357,19 @@ def collect_file_tests(path, lines, lines_to_execute):
else:
column = len(line) - 1 # -1 for the \n
if test_type == '!':
yield makecase(TEST_ASSIGNMENTS)
yield makecase(TEST_GOTO)
elif test_type == '<':
yield makecase(TEST_USAGES)
yield makecase(TEST_REFERENCES)
elif correct.startswith('['):
yield makecase(TEST_COMPLETIONS)
else:
yield makecase(TEST_DEFINITIONS)
yield makecase(TEST_INFERENCE)
correct = None
else:
skip_version_info = skip_python_version(line) or skip_version_info
try:
r = re.search(r'(?:^|(?<=\s))#([?!<])\s*([^\n]*)', line)
# test_type is ? for completion and ! for goto_assignments
# test_type is ? for completion and ! for goto
test_type = r.group(1)
correct = r.group(2)
# Quick hack to make everything work (not quite a bloody unicorn hack though).
@@ -470,6 +520,8 @@ if __name__ == '__main__':
if arguments['--pdb']:
import pdb
pdb.post_mortem()
except Skipped:
pass
count += 1
+2
View File
@@ -0,0 +1,2 @@
with open() as fin:
fin.read()
@@ -1,4 +1,4 @@
"""
An import tree, for testing usages.
An import tree, for testing references.
"""
+106 -44
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
@@ -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']
+89 -49
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
+119 -54
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)
+44 -22
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() == []
+115
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
+3 -3
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]
+77
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
+4 -4
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'
+10 -9
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']
+100 -30
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'
+10 -10
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'
+1 -1
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
+2 -2
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 == '('
+6 -6
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])'
+12 -12
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'
+5 -4
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
+3 -3
View File
@@ -3,12 +3,12 @@ Test all things related to the ``jedi.cache`` module.
"""
def test_cache_call_signatures(Script):
def test_cache_find_signatures(Script):
"""
See github issue #390.
"""
def check(column, call_name, path=None):
assert Script(s, 1, column, path).call_signatures()[0].name == call_name
assert Script(s, path=path).find_signatures(1, column)[0].name == call_name
s = 'str(int())'
@@ -26,4 +26,4 @@ def test_cache_call_signatures(Script):
def test_cache_line_split_issues(Script):
"""Should still work even if there's a newline."""
assert Script('int(\n').call_signatures()[0].name == 'int'
assert Script('int(\n').find_signatures()[0].name == 'int'
+27
View File
@@ -0,0 +1,27 @@
def test_goto_definitions(Script):
int_, = Script('x = 1\nx, y\ny', line=2, column=0).goto_definitions()
assert int_.name == 'int'
def test_completions(Script):
c1, c2 = Script('foobar = 1\nfoobaz= 2\nfoobaz, ffff\nfool = 3', line=3, column=3).completions()
assert c1.name == 'foobar'
assert c2.name == 'foobaz'
def test_goto_assignments(Script):
int_, = Script('x = 1\nx, y\ny', line=2, column=0).goto_assignments()
assert int_.get_line_code() == 'x = 1\n'
def test_usages(Script):
d1, d2 = Script('x = 1\nx, y\ny', line=2, column=0).usages()
assert d1.name == 'x'
assert d1.line == 1
assert d2.name == 'x'
assert d2.line == 2
def test_call_signatures(Script):
d1, = Script('abs(float(\nstr(', line=1, column=4).call_signatures()
assert d1.name == 'abs'
+1 -1
View File
@@ -8,4 +8,4 @@ from .. import helpers
@helpers.cwd_at("test/test_inference/absolute_import")
def test_can_complete_when_shadowing(Script):
script = Script(path="unittest.py")
assert script.completions()
assert script.complete()
+5 -5
View File
@@ -18,7 +18,7 @@ def test_simple_annotations(Script, environment):
annot('')""")
assert [d.name for d in Script(source).goto_definitions()] == ['str']
assert [d.name for d in Script(source).infer()] == ['str']
source = dedent("""\
@@ -26,7 +26,7 @@ def test_simple_annotations(Script, environment):
return a
annot_ret('')""")
assert [d.name for d in Script(source).goto_definitions()] == ['str']
assert [d.name for d in Script(source).infer()] == ['str']
source = dedent("""\
def annot(a:int):
@@ -34,7 +34,7 @@ def test_simple_annotations(Script, environment):
annot('')""")
assert [d.name for d in Script(source).goto_definitions()] == ['int']
assert [d.name for d in Script(source).infer()] == ['int']
@pytest.mark.parametrize('reference', [
@@ -50,7 +50,7 @@ def test_illegal_forward_references(Script, environment, reference):
source = 'def foo(bar: "%s"): bar' % reference
assert not Script(source).goto_definitions()
assert not Script(source).infer()
def test_lambda_forward_references(Script, environment):
@@ -61,4 +61,4 @@ def test_lambda_forward_references(Script, environment):
# For now just receiving the 3 is ok. I'm doubting that this is what we
# want. We also execute functions. Should we only execute classes?
assert Script(source).goto_definitions()
assert Script(source).infer()
+17 -5
View File
@@ -9,6 +9,7 @@ import pytest
from jedi.inference import compiled
from jedi.inference.compiled.access import DirectObjectAccess
from jedi.inference.gradual.conversion import _stub_to_python_value_set
from jedi.inference.syntax_tree import _infer_comparison_part
def test_simple(inference_state, environment):
@@ -60,7 +61,7 @@ def test_doc(inference_state):
def test_string_literals(Script, environment):
def typ(string):
d = Script("a = %s; a" % string).goto_definitions()[0]
d = Script("a = %s; a" % string).infer()[0]
return d.name
assert typ('""') == 'str'
@@ -82,12 +83,12 @@ def test_method_completion(Script, environment):
foo = Foo()
foo.bar.__func__''')
assert [c.name for c in Script(code).completions()] == ['__func__']
assert [c.name for c in Script(code).complete()] == ['__func__']
def test_time_docstring(Script):
import time
comp, = Script('import time\ntime.sleep').completions()
comp, = Script('import time\ntime.sleep').complete()
assert comp.docstring(raw=True) == time.sleep.__doc__
expected = 'sleep(secs: float) -> None\n\n' + time.sleep.__doc__
assert comp.docstring() == expected
@@ -97,12 +98,12 @@ def test_dict_values(Script, environment):
if environment.version_info.major == 2:
# It looks like typeshed for Python 2 returns Any.
pytest.skip()
assert Script('import sys\nsys.modules["alshdb;lasdhf"]').goto_definitions()
assert Script('import sys\nsys.modules["alshdb;lasdhf"]').infer()
def test_getitem_on_none(Script):
script = Script('None[1j]')
assert not script.goto_definitions()
assert not script.infer()
issue, = script._inference_state.analysis
assert issue.name == 'type-error-not-subscriptable'
@@ -169,3 +170,14 @@ def test_qualified_names(same_process_inference_state, obj, expected_names):
DirectObjectAccess(same_process_inference_state, obj)
)
assert o.get_qualified_names() == tuple(expected_names)
def test_operation(Script, inference_state, create_compiled_object):
b = create_compiled_object(bool)
true, = _infer_comparison_part(
inference_state, b.parent_context,
left=list(b.execute_with_values())[0],
operator=u'is not',
right=b,
)
assert true.py__name__() == 'bool'
+4 -4
View File
@@ -2,7 +2,7 @@ from jedi._compatibility import force_unicode
def test_module_attributes(Script):
def_, = Script('__name__').completions()
def_, = Script('__name__').complete()
assert def_.name == '__name__'
assert def_.line is None
assert def_.column is None
@@ -11,11 +11,11 @@ def test_module_attributes(Script):
def test_module__file__(Script, environment):
assert not Script('__file__').goto_definitions()
def_, = Script('__file__', path='example.py').goto_definitions()
assert not Script('__file__').infer()
def_, = Script('__file__', path='example.py').infer()
value = force_unicode(def_._name._value.get_safe_value())
assert value.endswith('example.py')
def_, = Script('import antigravity; antigravity.__file__').goto_definitions()
def_, = Script('import antigravity; antigravity.__file__').infer()
value = force_unicode(def_._name._value.get_safe_value())
assert value.endswith('.py')
+36 -26
View File
@@ -32,7 +32,7 @@ def test_function_doc(Script):
defs = Script("""
def func():
'''Docstring of `func`.'''
func""").goto_definitions()
func""").infer()
assert defs[0].docstring() == 'func()\n\nDocstring of `func`.'
@@ -40,7 +40,7 @@ def test_class_doc(Script):
defs = Script("""
class TestClass():
'''Docstring of `TestClass`.'''
TestClass""").goto_definitions()
TestClass""").infer()
expected = 'Docstring of `TestClass`.'
assert defs[0].docstring(raw=True) == expected
@@ -52,7 +52,7 @@ def test_class_doc_with_init(Script):
class TestClass():
'''Docstring'''
def __init__(self, foo, bar=3): pass
TestClass""").goto_definitions()
TestClass""").infer()
assert d.docstring() == 'TestClass(foo, bar=3)\n\nDocstring'
@@ -62,7 +62,7 @@ def test_instance_doc(Script):
class TestClass():
'''Docstring of `TestClass`.'''
tc = TestClass()
tc""").goto_definitions()
tc""").infer()
assert defs[0].docstring() == 'Docstring of `TestClass`.'
@@ -71,7 +71,7 @@ def test_attribute_docstring(Script):
defs = Script("""
x = None
'''Docstring of `x`.'''
x""").goto_definitions()
x""").infer()
assert defs[0].docstring() == 'Docstring of `x`.'
@@ -82,7 +82,7 @@ def test_multiple_docstrings(Script):
'''Original docstring.'''
x = func
'''Docstring of `x`.'''
x""").goto_definitions()
x""").infer()
docs = [d.docstring() for d in defs]
assert docs == ['Original docstring.', 'Docstring of `x`.']
@@ -91,7 +91,7 @@ def test_completion(Script):
assert Script('''
class DocstringCompletion():
#? []
""" asdfas """''').completions()
""" asdfas """''').complete()
def test_docstrings_type_dotted_import(Script):
@@ -101,7 +101,7 @@ def test_docstrings_type_dotted_import(Script):
:type arg: random.Random
'''
arg."""
names = [c.name for c in Script(s).completions()]
names = [c.name for c in Script(s).complete()]
assert 'seed' in names
@@ -112,7 +112,7 @@ def test_docstrings_param_type(Script):
:param str arg: some description
'''
arg."""
names = [c.name for c in Script(s).completions()]
names = [c.name for c in Script(s).complete()]
assert 'join' in names
@@ -124,7 +124,7 @@ def test_docstrings_type_str(Script):
'''
arg."""
names = [c.name for c in Script(s).completions()]
names = [c.name for c in Script(s).complete()]
assert 'join' in names
@@ -150,14 +150,14 @@ def test_docstring_instance(Script):
c.""")
names = [c.name for c in Script(s).completions()]
names = [c.name for c in Script(s).complete()]
assert 'a' in names
assert '__init__' in names
assert 'mro' not in names # Exists only for types.
def test_docstring_keyword(Script):
completions = Script('assert').completions()
completions = Script('assert').complete()
assert 'assert' in completions[0].docstring()
@@ -167,7 +167,7 @@ def test_docstring_params_formatting(Script):
param2,
param3):
pass
func""").goto_definitions()
func""").infer()
assert defs[0].docstring() == 'func(param1, param2, param3)'
@@ -185,7 +185,7 @@ def test_numpydoc_parameters():
y : str
"""
y.''')
names = [c.name for c in jedi.Script(s).completions()]
names = [c.name for c in jedi.Script(s).complete()]
assert 'isupper' in names
assert 'capitalize' in names
@@ -201,7 +201,7 @@ def test_numpydoc_parameters_set_of_values():
x : {'foo', 'bar', 100500}, optional
"""
x.''')
names = [c.name for c in jedi.Script(s).completions()]
names = [c.name for c in jedi.Script(s).complete()]
assert 'isupper' in names
assert 'capitalize' in names
assert 'numerator' in names
@@ -218,7 +218,7 @@ def test_numpydoc_parameters_alternative_types():
x : int or str or list
"""
x.''')
names = [c.name for c in jedi.Script(s).completions()]
names = [c.name for c in jedi.Script(s).complete()]
assert 'isupper' in names
assert 'capitalize' in names
assert 'numerator' in names
@@ -237,7 +237,7 @@ def test_numpydoc_invalid():
"""
x.''')
assert not jedi.Script(s).completions()
assert not jedi.Script(s).complete()
@pytest.mark.skipif(numpydoc_unavailable,
@@ -256,7 +256,7 @@ def test_numpydoc_returns():
def bazbiz():
z = foobar()
z.''')
names = [c.name for c in jedi.Script(s).completions()]
names = [c.name for c in jedi.Script(s).complete()]
assert 'isupper' in names
assert 'capitalize' in names
assert 'numerator' in names
@@ -277,7 +277,7 @@ def test_numpydoc_returns_set_of_values():
def bazbiz():
z = foobar()
z.''')
names = [c.name for c in jedi.Script(s).completions()]
names = [c.name for c in jedi.Script(s).complete()]
assert 'isupper' in names
assert 'capitalize' in names
assert 'numerator' in names
@@ -298,7 +298,7 @@ def test_numpydoc_returns_alternative_types():
def bazbiz():
z = foobar()
z.''')
names = [c.name for c in jedi.Script(s).completions()]
names = [c.name for c in jedi.Script(s).complete()]
assert 'isupper' not in names
assert 'capitalize' not in names
assert 'numerator' in names
@@ -320,7 +320,7 @@ def test_numpydoc_returns_list_of():
def bazbiz():
z = foobar()
z.''')
names = [c.name for c in jedi.Script(s).completions()]
names = [c.name for c in jedi.Script(s).complete()]
assert 'append' in names
assert 'isupper' not in names
assert 'capitalize' not in names
@@ -342,7 +342,7 @@ def test_numpydoc_returns_obj():
z = foobar(x, y)
z.''')
script = jedi.Script(s)
names = [c.name for c in script.completions()]
names = [c.name for c in script.complete()]
assert 'numerator' in names
assert 'seed' in names
@@ -363,7 +363,7 @@ def test_numpydoc_yields():
def bazbiz():
z = foobar():
z.''')
names = [c.name for c in jedi.Script(s).completions()]
names = [c.name for c in jedi.Script(s).complete()]
assert 'isupper' in names
assert 'capitalize' in names
assert 'numerator' in names
@@ -377,7 +377,7 @@ def test_numpy_returns():
x = numpy.asarray([])
x.d'''
)
names = [c.name for c in jedi.Script(s).completions()]
names = [c.name for c in jedi.Script(s).complete()]
assert 'diagonal' in names
@@ -389,7 +389,7 @@ def test_numpy_comp_returns():
x = numpy.array([])
x.d'''
)
names = [c.name for c in jedi.Script(s).completions()]
names = [c.name for c in jedi.Script(s).complete()]
assert 'diagonal' in names
@@ -412,5 +412,15 @@ def test_decorator(Script):
check_user''')
d, = Script(code).goto_definitions()
d, = Script(code).infer()
assert d.docstring(raw=True) == 'Nice docstring'
def test_basic_str_init_signature(Script, disable_typeshed):
# See GH #1414 and GH #1426
code = dedent('''
class Foo(str):
pass
Foo(''')
c, = Script(code).find_signatures()
assert c.name == 'Foo'
+7 -7
View File
@@ -10,10 +10,10 @@ import pytest
def test_completions(Script):
s = Script('import _ctypes; _ctypes.')
assert len(s.completions()) >= 15
assert len(s.complete()) >= 15
def test_call_signatures_extension(Script):
def test_find_signatures_extension(Script):
if os.name == 'nt':
func = 'LoadLibrary'
params = 1
@@ -21,14 +21,14 @@ def test_call_signatures_extension(Script):
func = 'dlopen'
params = 2
s = Script('import _ctypes; _ctypes.%s(' % (func,))
sigs = s.call_signatures()
sigs = s.find_signatures()
assert len(sigs) == 1
assert len(sigs[0].params) == params
def test_call_signatures_stdlib(Script):
def test_find_signatures_stdlib(Script):
s = Script('import math; math.cos(')
sigs = s.call_signatures()
sigs = s.find_signatures()
assert len(sigs) == 1
assert len(sigs[0].params) == 1
@@ -51,7 +51,7 @@ def test_init_extension_module(Script):
This is also why this test only runs on certain systems (and Python 3.4).
"""
s = jedi.Script('import init_extension_module as i\ni.', path='not_existing.py')
assert 'foo' in [c.name for c in s.completions()]
assert 'foo' in [c.name for c in s.complete()]
s = jedi.Script('from init_extension_module import foo\nfoo', path='not_existing.py')
assert ['foo'] == [c.name for c in s.completions()]
assert ['foo'] == [c.name for c in s.complete()]
+2 -3
View File
@@ -13,7 +13,6 @@ def test_fstring_multiline(Script):
'' f'''s{
str.uppe
'''
"""
)
c, = Script(code, line=2, column=9).completions()
""")
c, = Script(code).complete(line=2, column=9)
assert c.name == 'upper'
@@ -0,0 +1,56 @@
import os
from test.helpers import root_dir
from jedi.api.project import Project
from jedi.inference.gradual.conversion import convert_names
def test_sqlite3_conversion(Script):
script1 = Script('import sqlite3; sqlite3.Connection')
d, = script1.infer()
assert not d.module_path
assert d.full_name == 'sqlite3.Connection'
assert convert_names([d._name], only_stubs=True)
d, = script1.infer(only_stubs=True)
assert d.is_stub()
assert d.full_name == 'sqlite3.dbapi2.Connection'
script2 = Script(path=d.module_path)
d, = script2.infer(line=d.line, column=d.column)
assert not d.is_stub()
assert d.full_name == 'sqlite3.Connection'
v, = d._name.infer()
assert v.is_compiled()
def test_conversion_of_stub_only(Script):
project = Project(os.path.join(root_dir, 'test', 'completion', 'stub_folder'))
code = 'import stub_only; stub_only.in_stub_only'
d1, = Script(code, _project=project).goto()
assert d1.is_stub()
script = Script(path=d1.module_path, _project=project)
d2, = script.goto(line=d1.line, column=d1.column)
assert d2.is_stub()
assert d2.module_path == d1.module_path
assert d2.line == d1.line
assert d2.column == d1.column
assert d2.name == 'in_stub_only'
def test_goto_on_file(Script):
project = Project(os.path.join(root_dir, 'test', 'completion', 'stub_folder'))
script = Script('import stub_only; stub_only.Foo', _project=project)
d1, = script.goto()
v, = d1._name.infer()
foo, bar, obj = v.py__mro__()
assert foo.py__name__() == 'Foo'
assert bar.py__name__() == 'Bar'
assert obj.py__name__() == 'object'
# Make sure we go to Bar, because Foo is a bit before: `class Foo(Bar):`
script = Script(path=d1.module_path, _project=project)
d2, = script.goto(line=d1.line, column=d1.column + 4)
assert d2.name == 'Bar'
@@ -23,5 +23,5 @@ def ScriptInStubFolder(Script):
]
)
def test_find_stubs_infer(ScriptInStubFolder, code, expected):
defs = ScriptInStubFolder(code).goto_definitions()
defs = ScriptInStubFolder(code).infer()
assert [d.name for d in defs] == expected
+13 -12
View File
@@ -16,7 +16,7 @@ from test.helpers import root_dir
]
)
@pytest.mark.parametrize(
('code', 'full_name', 'has_stub', 'has_python', 'goto_changes'), [
('code', 'full_name', 'has_stub', 'has_python', 'options'), [
['import os; os.walk', 'os.walk', True, True, {}],
['from collections import Counter', 'collections.Counter', True, True, {}],
['from collections', 'collections', True, True, {}],
@@ -24,15 +24,16 @@ from test.helpers import root_dir
['from collections import Counter; Counter()', 'collections.Counter', True, True, {}],
['from collections import Counter; Counter.most_common',
'collections.Counter.most_common', True, True, {}],
['from collections import deque', 'collections.deque', True, False, {'has_python': True}],
['from collections import deque', 'collections.deque', True, False,
{'goto_has_python': True}],
['from keyword import kwlist; kwlist', 'typing.Sequence', True, True,
{'full_name': 'keyword.kwlist'}],
{'goto_full_name': 'keyword.kwlist'}],
['from keyword import kwlist', 'typing.Sequence', True, True,
{'full_name': 'keyword.kwlist'}],
{'goto_full_name': 'keyword.kwlist'}],
['from socket import AF_INET', 'socket.AddressFamily', True, False,
{'full_name': 'socket.AF_INET'}],
{'goto_full_name': 'socket.AF_INET'}],
['from socket import socket', 'socket.socket', True, True, {}],
['import with_stub', 'with_stub', True, True, {}],
@@ -41,7 +42,7 @@ from test.helpers import root_dir
['import stub_only', 'stub_only', True, False, {}],
])
def test_infer_and_goto(Script, code, full_name, has_stub, has_python, way,
kwargs, type_, goto_changes, environment):
kwargs, type_, options, environment):
if environment.version_info < (3, 5):
# We just don't care about much of the detailed Python 2 failures
# anymore, because its end-of-life soon. (same for 3.4)
@@ -58,22 +59,22 @@ def test_infer_and_goto(Script, code, full_name, has_stub, has_python, way,
only_stubs = kwargs['only_stubs']
if type_ == 'goto':
full_name = goto_changes.get('full_name', full_name)
has_python = goto_changes.get('has_python', has_python)
full_name = options.get('goto_full_name', full_name)
has_python = options.get('goto_has_python', has_python)
if way == 'direct':
if type_ == 'goto':
defs = s.goto_assignments(follow_imports=True, **kwargs)
defs = s.goto(follow_imports=True, **kwargs)
else:
defs = s.goto_definitions(**kwargs)
defs = s.infer(**kwargs)
else:
goto_defs = s.goto_assignments(
goto_defs = s.goto(
# Prefering stubs when we want to go to python and vice versa
prefer_stubs=not (prefer_stubs or only_stubs),
follow_imports=True,
)
if type_ == 'goto':
defs = [d for goto_def in goto_defs for d in goto_def.goto_assignments(**kwargs)]
defs = [d for goto_def in goto_defs for d in goto_def.goto(**kwargs)]
else:
defs = [d for goto_def in goto_defs for d in goto_def.infer(**kwargs)]
@@ -3,9 +3,10 @@ import os
import pytest
from parso.utils import PythonVersionInfo
from jedi.inference.gradual import typeshed, stub_value
from jedi.inference.gradual import typeshed
from jedi.inference.value import TreeInstance, BoundMethod, FunctionValue, \
MethodValue, ClassValue
from jedi.inference.names import StubName
TYPESHED_PYTHON3 = os.path.join(typeshed.TYPESHED_PATH, 'stdlib', '3')
@@ -27,13 +28,13 @@ def test_get_typeshed_directories():
assert dirs == transform({'stdlib/2and3', 'stdlib/3', 'third_party/2and3', 'third_party/3'})
dirs = get_dirs(PythonVersionInfo(3, 5))
assert dirs == transform({'stdlib/2and3', 'stdlib/3', 'stdlib/3.5',
'third_party/2and3', 'third_party/3', 'third_party/3.5'})
assert dirs == transform({'stdlib/2and3', 'stdlib/3',
'third_party/2and3', 'third_party/3'})
dirs = get_dirs(PythonVersionInfo(3, 6))
assert dirs == transform({'stdlib/2and3', 'stdlib/3', 'stdlib/3.5',
assert dirs == transform({'stdlib/2and3', 'stdlib/3',
'stdlib/3.6', 'third_party/2and3',
'third_party/3', 'third_party/3.5', 'third_party/3.6'})
'third_party/3', 'third_party/3.6'})
def test_get_stub_files():
@@ -46,53 +47,53 @@ def test_get_stub_files():
def test_function(Script, environment):
code = 'import threading; threading.current_thread'
def_, = Script(code).goto_definitions()
def_, = Script(code).infer()
value = def_._name._value
assert isinstance(value, FunctionValue), value
def_, = Script(code + '()').goto_definitions()
def_, = Script(code + '()').infer()
value = def_._name._value
assert isinstance(value, TreeInstance)
def_, = Script('import threading; threading.Thread').goto_definitions()
def_, = Script('import threading; threading.Thread').infer()
assert isinstance(def_._name._value, ClassValue), def_
def test_keywords_variable(Script):
code = 'import keyword; keyword.kwlist'
for seq in Script(code).goto_definitions():
for seq in Script(code).infer():
assert seq.name == 'Sequence'
# This points towards the typeshed implementation
stub_seq, = seq.goto_assignments(only_stubs=True)
stub_seq, = seq.goto(only_stubs=True)
assert typeshed.TYPESHED_PATH in stub_seq.module_path
def test_class(Script):
def_, = Script('import threading; threading.Thread').goto_definitions()
def_, = Script('import threading; threading.Thread').infer()
value = def_._name._value
assert isinstance(value, ClassValue), value
def test_instance(Script):
def_, = Script('import threading; threading.Thread()').goto_definitions()
def_, = Script('import threading; threading.Thread()').infer()
value = def_._name._value
assert isinstance(value, TreeInstance)
def test_class_function(Script):
def_, = Script('import threading; threading.Thread.getName').goto_definitions()
def_, = Script('import threading; threading.Thread.getName').infer()
value = def_._name._value
assert isinstance(value, MethodValue), value
def test_method(Script):
code = 'import threading; threading.Thread().getName'
def_, = Script(code).goto_definitions()
def_, = Script(code).infer()
value = def_._name._value
assert isinstance(value, BoundMethod), value
assert isinstance(value._wrapped_value, MethodValue), value
def_, = Script(code + '()').goto_definitions()
def_, = Script(code + '()').infer()
value = def_._name._value
assert isinstance(value, TreeInstance)
assert value.class_value.py__name__() == 'str'
@@ -100,13 +101,13 @@ def test_method(Script):
def test_sys_exc_info(Script):
code = 'import sys; sys.exc_info()'
none, def_ = Script(code + '[1]').goto_definitions()
none, def_ = Script(code + '[1]').infer()
# It's an optional.
assert def_.name == 'BaseException'
assert def_.type == 'instance'
assert none.name == 'NoneType'
none, def_ = Script(code + '[0]').goto_definitions()
none, def_ = Script(code + '[0]').infer()
assert def_.name == 'BaseException'
assert def_.type == 'class'
@@ -114,7 +115,7 @@ def test_sys_exc_info(Script):
def test_sys_getwindowsversion(Script, environment):
# This should only exist on Windows, but type inference should happen
# everywhere.
definitions = Script('import sys; sys.getwindowsversion().major').goto_definitions()
definitions = Script('import sys; sys.getwindowsversion().major').infer()
if environment.version_info.major == 2:
assert not definitions
else:
@@ -124,22 +125,22 @@ def test_sys_getwindowsversion(Script, environment):
def test_sys_hexversion(Script):
script = Script('import sys; sys.hexversion')
def_, = script.completions()
assert isinstance(def_._name, stub_value._StubName), def_._name
def_, = script.complete()
assert isinstance(def_._name, StubName), def_._name
assert typeshed.TYPESHED_PATH in def_.module_path
def_, = script.goto_definitions()
def_, = script.infer()
assert def_.name == 'int'
def test_math(Script):
def_, = Script('import math; math.acos()').goto_definitions()
def_, = Script('import math; math.acos()').infer()
assert def_.name == 'float'
value = def_._name._value
assert value
def test_type_var(Script):
def_, = Script('import typing; T = typing.TypeVar("T1")').goto_definitions()
def_, = Script('import typing; T = typing.TypeVar("T1")').infer()
assert def_.name == 'TypeVar'
assert def_.description == 'TypeVar = object()'
@@ -152,29 +153,29 @@ def test_type_var(Script):
)
def test_math_is_stub(Script, code, full_name):
s = Script(code)
cos, = s.goto_definitions()
cos, = s.infer()
wanted = os.path.join('typeshed', 'stdlib', '2and3', 'math.pyi')
assert cos.module_path.endswith(wanted)
assert cos.is_stub() is True
assert cos.goto_assignments(only_stubs=True) == [cos]
assert cos.goto(only_stubs=True) == [cos]
assert cos.full_name == full_name
cos, = s.goto_assignments()
cos, = s.goto()
assert cos.module_path.endswith(wanted)
assert cos.goto_assignments(only_stubs=True) == [cos]
assert cos.goto(only_stubs=True) == [cos]
assert cos.is_stub() is True
assert cos.full_name == full_name
def test_goto_stubs(Script):
s = Script('import os; os')
os_module, = s.goto_definitions()
os_module, = s.infer()
assert os_module.full_name == 'os'
assert os_module.is_stub() is False
stub, = os_module.goto_assignments(only_stubs=True)
stub, = os_module.goto(only_stubs=True)
assert stub.is_stub() is True
os_module, = s.goto_assignments()
os_module, = s.goto()
def _assert_is_same(d1, d2):
@@ -199,21 +200,17 @@ def test_goto_stubs_on_itself(Script, code, type_):
"""
s = Script(code)
if type_ == 'infer':
def_, = s.goto_definitions()
def_, = s.infer()
else:
def_, = s.goto_assignments(follow_imports=True)
stub, = def_.goto_assignments(only_stubs=True)
def_, = s.goto(follow_imports=True)
stub, = def_.goto(only_stubs=True)
script_on_source = Script(
path=def_.module_path,
line=def_.line,
column=def_.column
)
script_on_source = Script(path=def_.module_path)
if type_ == 'infer':
definition, = script_on_source.goto_definitions()
definition, = script_on_source.infer(def_.line, def_.column)
else:
definition, = script_on_source.goto_assignments()
same_stub, = definition.goto_assignments(only_stubs=True)
definition, = script_on_source.goto(def_.line, def_.column)
same_stub, = definition.goto(only_stubs=True)
_assert_is_same(same_stub, stub)
_assert_is_same(definition, def_)
assert same_stub.module_path != def_.module_path
@@ -221,16 +218,14 @@ def test_goto_stubs_on_itself(Script, code, type_):
# And the reverse.
script_on_stub = Script(
path=same_stub.module_path,
line=same_stub.line,
column=same_stub.column
)
if type_ == 'infer':
same_definition, = script_on_stub.goto_definitions()
same_definition, = script_on_stub.infer(same_stub.line, same_stub.column)
same_definition2, = same_stub.infer()
else:
same_definition, = script_on_stub.goto_assignments()
same_definition2, = same_stub.goto_assignments()
same_definition, = script_on_stub.goto(same_stub.line, same_stub.column)
same_definition2, = same_stub.goto()
_assert_is_same(same_definition, definition)
_assert_is_same(same_definition, same_definition2)
+2 -3
View File
@@ -1,15 +1,14 @@
from textwrap import dedent
from jedi import names
from jedi.inference import helpers
def test_call_of_leaf_in_brackets(environment):
def test_call_of_leaf_in_brackets(Script):
s = dedent("""
x = 1
type(x)
""")
last_x = names(s, references=True, definitions=False, environment=environment)[-1]
last_x = Script(s).names(references=True, definitions=False)[-1]
name = last_x._name.tree_name
call = helpers.call_of_leaf(name)
@@ -17,9 +17,9 @@ def test_implicit_namespace_package(Script):
return Script(sys_path=sys_path, *args, **kwargs)
# goto definition
assert script_with_path('from pkg import ns1_file').goto_definitions()
assert script_with_path('from pkg import ns2_file').goto_definitions()
assert not script_with_path('from pkg import ns3_file').goto_definitions()
assert script_with_path('from pkg import ns1_file').infer()
assert script_with_path('from pkg import ns2_file').infer()
assert not script_with_path('from pkg import ns3_file').infer()
# goto assignment
tests = {
@@ -27,12 +27,12 @@ def test_implicit_namespace_package(Script):
'from pkg.ns1_file import foo': 'ns1_file!',
}
for source, solution in tests.items():
ass = script_with_path(source).goto_assignments()
ass = script_with_path(source).goto()
assert len(ass) == 1
assert ass[0].description == "foo = '%s'" % solution
# completion
completions = script_with_path('from pkg import ').completions()
completions = script_with_path('from pkg import ').complete()
names = [c.name for c in completions]
compare = ['ns1_file', 'ns2_file']
# must at least contain these items, other items are not important
@@ -43,7 +43,7 @@ def test_implicit_namespace_package(Script):
'from pkg import ns1_file as x': 'ns1_file!'
}
for source, solution in tests.items():
for c in script_with_path(source + '; x.').completions():
for c in script_with_path(source + '; x.').complete():
if c.name == 'foo':
completion = c
solution = "foo = '%s'" % solution
@@ -57,11 +57,11 @@ def test_implicit_nested_namespace_package(Script):
script = Script(sys_path=sys_path, source=code, line=1, column=61)
result = script.goto_definitions()
result = script.infer()
assert len(result) == 1
implicit_pkg, = Script(code, column=10, sys_path=sys_path).goto_definitions()
implicit_pkg, = Script(code, sys_path=sys_path).infer(column=10)
assert implicit_pkg.type == 'module'
assert implicit_pkg.module_path is None
@@ -72,7 +72,7 @@ def test_implicit_namespace_package_import_autocomplete(Script):
sys_path = [dirname(__file__)]
script = Script(sys_path=sys_path, source=CODE)
compl = script.completions()
compl = script.complete()
assert [c.name for c in compl] == ['implicit_namespace_package']
@@ -82,7 +82,7 @@ def test_namespace_package_in_multiple_directories_autocompletion(Script):
for d in ['implicit_namespace_package/ns1', 'implicit_namespace_package/ns2']]
script = Script(sys_path=sys_path, source=CODE)
compl = script.completions()
compl = script.complete()
assert set(c.name for c in compl) == set(['ns1_file', 'ns2_file'])
@@ -91,7 +91,7 @@ def test_namespace_package_in_multiple_directories_goto_definition(Script):
sys_path = [join(dirname(__file__), d)
for d in ['implicit_namespace_package/ns1', 'implicit_namespace_package/ns2']]
script = Script(sys_path=sys_path, source=CODE)
result = script.goto_definitions()
result = script.infer()
assert len(result) == 1
@@ -101,5 +101,5 @@ def test_namespace_name_autocompletion_full_name(Script):
for d in ['implicit_namespace_package/ns1', 'implicit_namespace_package/ns2']]
script = Script(sys_path=sys_path, source=CODE)
compl = script.completions()
compl = script.complete()
assert set(c.full_name for c in compl) == set(['pkg'])
+58 -54
View File
@@ -46,7 +46,7 @@ pkg_zip_path = os.path.join(os.path.dirname(__file__),
def test_find_module_package_zipped(Script, inference_state, environment):
sys_path = environment.get_sys_path() + [pkg_zip_path]
script = Script('import pkg; pkg.mod', sys_path=sys_path)
assert len(script.completions()) == 1
assert len(script.complete()) == 1
file_io, is_package = inference_state.compiled_subprocess.get_module_info(
sys_path=sys_path,
@@ -87,11 +87,11 @@ def test_find_module_package_zipped(Script, inference_state, environment):
def test_correct_zip_package_behavior(Script, inference_state, environment, code,
file, package, path, skip_python2):
sys_path = environment.get_sys_path() + [pkg_zip_path]
pkg, = Script(code, sys_path=sys_path).goto_definitions()
pkg, = Script(code, sys_path=sys_path).infer()
value, = pkg._name.infer()
assert value.py__file__() == os.path.join(pkg_zip_path, 'pkg', file)
assert '.'.join(value.py__package__()) == package
assert value.is_package is (path is not None)
assert value.is_package() is (path is not None)
if path is not None:
assert value.py__path__() == [os.path.join(pkg_zip_path, path)]
@@ -100,7 +100,7 @@ def test_find_module_not_package_zipped(Script, inference_state, environment):
path = os.path.join(os.path.dirname(__file__), 'zipped_imports/not_pkg.zip')
sys_path = environment.get_sys_path() + [path]
script = Script('import not_pkg; not_pkg.val', sys_path=sys_path)
assert len(script.completions()) == 1
assert len(script.complete()) == 1
file_io, is_package = inference_state.compiled_subprocess.get_module_info(
sys_path=sys_path,
@@ -115,13 +115,15 @@ def test_find_module_not_package_zipped(Script, inference_state, environment):
def test_import_not_in_sys_path(Script):
"""
non-direct imports (not in sys.path)
This is in the end just a fallback.
"""
a = Script(path='module.py', line=5).goto_definitions()
a = Script(path='module.py').infer(line=5)
assert a[0].name == 'int'
a = Script(path='module.py', line=6).goto_definitions()
a = Script(path='module.py').infer(line=6)
assert a[0].name == 'str'
a = Script(path='module.py', line=7).goto_definitions()
a = Script(path='module.py').infer(line=7)
assert a[0].name == 'str'
@@ -143,19 +145,19 @@ def test_flask_ext(Script, code, name):
"""flask.ext.foo is really imported from flaskext.foo or flask_foo.
"""
path = os.path.join(os.path.dirname(__file__), 'flask-site-packages')
completions = Script(code, sys_path=[path]).completions()
completions = Script(code, sys_path=[path]).complete()
assert name in [c.name for c in completions]
@cwd_at('test/test_inference/')
def test_not_importable_file(Script):
src = 'import not_importable_file as x; x.'
assert not Script(src, path='example.py').completions()
assert not Script(src, path='example.py').complete()
def test_import_unique(Script):
src = "import os; os.path"
defs = Script(src, path='example.py').goto_definitions()
defs = Script(src, path='example.py').infer()
parent_contexts = [d._name._value for d in defs]
assert len(parent_contexts) == len(set(parent_contexts))
@@ -166,9 +168,9 @@ def test_cache_works_with_sys_path_param(Script, tmpdir):
foo_path.join('module.py').write('foo = 123', ensure=True)
bar_path.join('module.py').write('bar = 123', ensure=True)
foo_completions = Script('import module; module.',
sys_path=[foo_path.strpath]).completions()
sys_path=[foo_path.strpath]).complete()
bar_completions = Script('import module; module.',
sys_path=[bar_path.strpath]).completions()
sys_path=[bar_path.strpath]).complete()
assert 'foo' in [c.name for c in foo_completions]
assert 'bar' not in [c.name for c in foo_completions]
@@ -179,7 +181,7 @@ def test_cache_works_with_sys_path_param(Script, tmpdir):
def test_import_completion_docstring(Script):
import abc
s = Script('"""test"""\nimport ab')
abc_completions = [c for c in s.completions() if c.name == 'abc']
abc_completions = [c for c in s.complete() if c.name == 'abc']
assert len(abc_completions) == 1
assert abc_completions[0].docstring(fast=False) == abc.__doc__
@@ -189,72 +191,72 @@ def test_import_completion_docstring(Script):
def test_goto_definition_on_import(Script):
assert Script("import sys_blabla", 1, 8).goto_definitions() == []
assert len(Script("import sys", 1, 8).goto_definitions()) == 1
assert Script("import sys_blabla").infer(1, 8) == []
assert len(Script("import sys").infer(1, 8)) == 1
@cwd_at('jedi')
def test_complete_on_empty_import(Script):
assert Script("from datetime import").completions()[0].name == 'import'
assert Script("from datetime import").complete()[0].name == 'import'
# should just list the files in the directory
assert 10 < len(Script("from .", path='whatever.py').completions()) < 30
assert 10 < len(Script("from .", path='whatever.py').complete()) < 30
# Global import
assert len(Script("from . import", 1, 5, 'whatever.py').completions()) > 30
assert len(Script("from . import", 'whatever.py').complete(1, 5)) > 30
# relative import
assert 10 < len(Script("from . import", 1, 6, 'whatever.py').completions()) < 30
assert 10 < len(Script("from . import", 'whatever.py').complete(1, 6)) < 30
# Global import
assert len(Script("from . import classes", 1, 5, 'whatever.py').completions()) > 30
assert len(Script("from . import classes", 'whatever.py').complete(1, 5)) > 30
# relative import
assert 10 < len(Script("from . import classes", 1, 6, 'whatever.py').completions()) < 30
assert 10 < len(Script("from . import classes", 'whatever.py').complete(1, 6)) < 30
wanted = {'ImportError', 'import', 'ImportWarning'}
assert {c.name for c in Script("import").completions()} == wanted
assert len(Script("import import", path='').completions()) > 0
assert {c.name for c in Script("import").complete()} == wanted
assert len(Script("import import", path='').complete()) > 0
# 111
assert Script("from datetime import").completions()[0].name == 'import'
assert Script("from datetime import ").completions()
assert Script("from datetime import").complete()[0].name == 'import'
assert Script("from datetime import ").complete()
def test_imports_on_global_namespace_without_path(Script):
"""If the path is None, there shouldn't be any import problem"""
completions = Script("import operator").completions()
completions = Script("import operator").complete()
assert [c.name for c in completions] == ['operator']
completions = Script("import operator", path='example.py').completions()
completions = Script("import operator", path='example.py').complete()
assert [c.name for c in completions] == ['operator']
# the first one has a path the second doesn't
completions = Script("import keyword", path='example.py').completions()
completions = Script("import keyword", path='example.py').complete()
assert [c.name for c in completions] == ['keyword']
completions = Script("import keyword").completions()
completions = Script("import keyword").complete()
assert [c.name for c in completions] == ['keyword']
def test_named_import(Script):
"""named import - jedi-vim issue #8"""
s = "import time as dt"
assert len(Script(s, 1, 15, '/').goto_definitions()) == 1
assert len(Script(s, 1, 10, '/').goto_definitions()) == 1
assert len(Script(s, path='/').infer(1, 15)) == 1
assert len(Script(s, path='/').infer(1, 10)) == 1
@pytest.mark.skipif('True', reason='The nested import stuff is still very messy.')
def test_goto_following_on_imports(Script):
s = "import multiprocessing.dummy; multiprocessing.dummy"
g = Script(s).goto_assignments()
g = Script(s).goto()
assert len(g) == 1
assert (g[0].line, g[0].column) != (0, 0)
def test_goto_assignments(Script):
sys, = Script("import sys", 1, 10).goto_assignments(follow_imports=True)
def test_goto(Script):
sys, = Script("import sys", 1, 10).goto(follow_imports=True)
assert sys.type == 'module'
def test_os_after_from(Script):
def check(source, result, column=None):
completions = Script(source, column=column).completions()
completions = Script(source).complete(column=column)
assert [c.name for c in completions] == result
check('\nfrom os. ', ['path'])
@@ -268,7 +270,7 @@ def test_os_after_from(Script):
def test_os_issues(Script):
def import_names(*args, **kwargs):
return [d.name for d in Script(*args, **kwargs).completions()]
return [d.name for d in Script(*args).complete(**kwargs)]
# Github issue #759
s = 'import os, s'
@@ -289,7 +291,7 @@ def test_path_issues(Script):
See pull request #684 for details.
"""
source = '''from datetime import '''
assert Script(source).completions()
assert Script(source).complete()
def test_compiled_import_none(monkeypatch, Script):
@@ -298,7 +300,7 @@ def test_compiled_import_none(monkeypatch, Script):
"""
script = Script('import sys')
monkeypatch.setattr(compiled, 'load_module', lambda *args, **kwargs: None)
def_, = script.goto_definitions()
def_, = script.infer()
assert def_.type == 'module'
value, = def_._name.infer()
assert not _stub_to_python_value_set(value)
@@ -340,8 +342,8 @@ def test_get_modules_containing_name(inference_state, path, goal, is_package):
)
def test_load_module_from_path(inference_state, path, base_names, is_package, names):
file_io = KnownContentFileIO(path, '')
m = imports._load_module_from_path(inference_state, file_io, base_names)
assert m.is_package == is_package
m = imports.load_module_from_path(inference_state, file_io, base_names)
assert m.is_package() == is_package
assert m.string_names == names
@@ -359,7 +361,7 @@ def test_relative_imports_with_multiple_similar_directories(Script, path, empty_
path=os.path.join(dir, path),
_project=project,
)
name, import_ = script.completions()
name, import_ = script.complete()
assert import_.name == 'import'
assert name.name == 'api_test1'
@@ -372,37 +374,39 @@ def test_relative_imports_with_outside_paths(Script):
path=os.path.join(dir, 'api/whatever/test_this.py'),
_project=project,
)
assert [c.name for c in script.completions()] == ['api', 'import', 'whatever']
assert [c.name for c in script.complete()] == ['api', 'whatever']
script = Script(
"from " + '.' * 100,
path=os.path.join(dir, 'api/whatever/test_this.py'),
_project=project,
)
assert [c.name for c in script.completions()] == ['import']
assert not script.complete()
@cwd_at('test/examples/issue1209/api/whatever/')
def test_relative_imports_without_path(Script):
project = Project('.', sys_path=[], smart_sys_path=False)
script = Script("from . ", _project=project)
assert [c.name for c in script.completions()] == ['api_test1', 'import']
assert [c.name for c in script.complete()] == ['api_test1', 'import']
script = Script("from .. ", _project=project)
assert [c.name for c in script.completions()] == ['import', 'whatever']
assert [c.name for c in script.complete()] == ['import', 'whatever']
script = Script("from ... ", _project=project)
assert [c.name for c in script.completions()] == ['api', 'import', 'whatever']
assert [c.name for c in script.complete()] == ['api', 'import', 'whatever']
def test_relative_import_out_of_file_system(Script):
script = Script("from " + '.' * 100)
import_, = script.completions()
code = "from " + '.' * 100
assert not Script(code).complete()
script = Script(code + ' ')
import_, = script.complete()
assert import_.name == 'import'
script = Script("from " + '.' * 100 + 'abc import ABCMeta')
assert not script.goto_definitions()
assert not script.completions()
assert not script.infer()
assert not script.complete()
@pytest.mark.parametrize(
@@ -454,13 +458,13 @@ def test_import_needed_modules_by_jedi(Script, environment, tmpdir, name):
path=tmpdir.join('something.py').strpath,
sys_path=[tmpdir.strpath] + environment.get_sys_path(),
)
module, = script.goto_definitions()
module, = script.infer()
assert module._inference_state.builtins_module.py__file__() != module_path
assert module._inference_state.typing_module.py__file__() != module_path
def test_import_with_semicolon(Script):
names = [c.name for c in Script('xzy; from abc import ').completions()]
names = [c.name for c in Script('xzy; from abc import ').complete()]
assert 'ABCMeta' in names
assert 'abc' not in names
@@ -473,6 +477,6 @@ def test_relative_import_star(Script):
from . import *
furl.c
"""
script = jedi.Script(source, 3, len("furl.c"), 'export.py')
script = jedi.Script(source, 'export.py')
assert script.completions()
assert script.complete(3, len("furl.c"))
+4 -8
View File
@@ -3,7 +3,7 @@ from jedi.inference.value import TreeInstance
def _infer_literal(Script, code, is_fstring=False):
def_, = Script(code).goto_definitions()
def_, = Script(code).infer()
if is_fstring:
assert def_.name == 'str'
assert isinstance(def_._name._value, TreeInstance)
@@ -26,13 +26,9 @@ def test_f_strings(Script, environment):
assert _infer_literal(Script, 'rF"{asdf} "', is_fstring=True) == ''
def test_rb_strings(Script, environment):
assert _infer_literal(Script, 'br"asdf"') == b'asdf'
obj = _infer_literal(Script, 'rb"asdf"')
# rb is not valid in Python 2. Due to error recovery we just get a
# string.
assert obj == b'asdf'
def test_rb_strings(Script, environment, skip_python2):
assert _infer_literal(Script, 'x = br"asdf"; x') == b'asdf'
assert _infer_literal(Script, 'x = rb"asdf"; x') == b'asdf'
def test_thousand_separators(Script, environment):
+37 -2
View File
@@ -1,7 +1,42 @@
import sys
if sys.version_info > (3, 5):
from typing import Generic, TypeVar, List
import pytest
import jedi
def interpreter(code, namespace, *args, **kwargs):
return jedi.Interpreter(code, [namespace], *args, **kwargs)
def test_on_code():
from functools import wraps
i = jedi.Interpreter("wraps.__code__", [{'wraps':wraps}])
assert i.goto_definitions()
i = interpreter("wraps.__code__", {'wraps': wraps})
assert i.infer()
@pytest.mark.skipif('sys.version_info < (3,5)')
def test_generics():
# Used to raise a recursion error
T = TypeVar('T')
class Stack(Generic[T]):
def __init__(self):
self.items = [] # type: List[T]
def push(self, item):
self.items.append(item)
def pop(self):
# type: () -> T
return self.items.pop()
class StackWrapper():
def __init__(self):
self.stack = Stack()
self.stack.push(1)
s = StackWrapper()
print(interpreter('s.stack.pop().', locals()).complete())
+11 -11
View File
@@ -15,9 +15,9 @@ def script_with_path(Script, *args, **kwargs):
def test_goto_definition(Script):
assert script_with_path(Script, 'from pkg import ns1_file').goto_definitions()
assert script_with_path(Script, 'from pkg import ns2_file').goto_definitions()
assert not script_with_path(Script, 'from pkg import ns3_file').goto_definitions()
assert script_with_path(Script, 'from pkg import ns1_file').infer()
assert script_with_path(Script, 'from pkg import ns2_file').infer()
assert not script_with_path(Script, 'from pkg import ns3_file').infer()
@pytest.mark.parametrize(
@@ -31,14 +31,14 @@ def test_goto_definition(Script):
]
)
def test_goto_assignment(Script, source, solution):
ass = script_with_path(Script, source).goto_assignments()
ass = script_with_path(Script, source).goto()
assert len(ass) == 1
assert ass[0].description == "foo = '%s'" % solution
def test_simple_completions(Script):
# completion
completions = script_with_path(Script, 'from pkg import ').completions()
completions = script_with_path(Script, 'from pkg import ').complete()
names = [str(c.name) for c in completions] # str because of unicode
compare = ['foo', 'ns1_file', 'ns1_folder', 'ns2_folder', 'ns2_file',
'pkg_resources', 'pkgutil', '__name__', '__path__',
@@ -58,7 +58,7 @@ def test_simple_completions(Script):
]
)
def test_completions(Script, source, solution):
for c in script_with_path(Script, source + '; x.').completions():
for c in script_with_path(Script, source + '; x.').complete():
if c.name == 'foo':
completion = c
solution = "foo = '%s'" % solution
@@ -70,9 +70,9 @@ def test_nested_namespace_package(Script):
sys_path = [dirname(__file__)]
script = Script(sys_path=sys_path, source=code, line=1, column=45)
script = Script(sys_path=sys_path, source=code)
result = script.goto_definitions()
result = script.infer(line=1, column=45)
assert len(result) == 1
@@ -88,9 +88,9 @@ def test_relative_import(Script, environment, tmpdir):
# Need to copy the content in a directory where there's no __init__.py.
py.path.local(directory).copy(tmpdir)
file_path = join(tmpdir.strpath, "rel1.py")
script = Script(path=file_path, line=1)
d, = script.goto_definitions()
script = Script(path=file_path)
d, = script.infer(line=1)
assert d.name == 'int'
d, = script.goto_assignments()
d, = script.goto(line=1)
assert d.name == 'name'
assert d.module_name == 'rel2'
+1 -1
View File
@@ -70,4 +70,4 @@ def test_pyc(pyc_project_path, environment):
"from dummy_package import dummy; dummy.",
path=path,
environment=environment)
assert len(s.completions()) >= 2
assert len(s.complete()) >= 2
+1 -1
View File
@@ -2,7 +2,7 @@ from textwrap import dedent
def get_definition_and_inference_state(Script, source):
first, = Script(dedent(source)).goto_definitions()
first, = Script(dedent(source)).infer()
return first._name._value, first._inference_state
+23 -12
View File
@@ -1,10 +1,12 @@
from textwrap import dedent
from operator import ge, lt
import re
import os
import pytest
from jedi.inference.gradual.conversion import _stub_to_python_value_set
from ..helpers import get_example_dir
@pytest.mark.parametrize(
@@ -16,9 +18,10 @@ from jedi.inference.gradual.conversion import _stub_to_python_value_set
('str', "str(object='', /) -> str", ['object'], ge, (2, 7)),
('pow', 'pow(x, y, z=None, /) -> number', ['x', 'y', 'z'], lt, (3, 5)),
('pow', 'pow(x, y, z=None, /)', ['x', 'y', 'z'], ge, (3, 5)),
('pow', 'pow(base, exp, mod=None)', ['base', 'exp', 'mod'], ge, (3, 8)),
('bytes.partition', 'partition(self, sep, /) -> (head, sep, tail)', ['self', 'sep'], lt, (3, 5)),
('bytes.partition', 'partition(self, sep, /) -> (head, sep, tail)',
['self', 'sep'], lt, (3, 5)),
('bytes.partition', 'partition(self, sep, /)', ['self', 'sep'], ge, (3, 5)),
('bytes().partition', 'partition(sep, /) -> (head, sep, tail)', ['sep'], lt, (3, 5)),
@@ -29,7 +32,7 @@ def test_compiled_signature(Script, environment, code, sig, names, op, version):
if not op(environment.version_info, version):
return # The test right next to it should take over.
d, = Script(code).goto_definitions()
d, = Script(code).infer()
value, = d._name.infer()
compiled, = _stub_to_python_value_set(value)
signature, = compiled.get_signatures()
@@ -70,8 +73,8 @@ d = functools.partial()
('def f(x,/,y,* ,z): pass\n f(', 'f(x, /, y, *, z)'),
('def f(a, /, *, x=3, **kwargs): pass\n f(', 'f(a, /, *, x=3, **kwargs)'),
(classmethod_code + 'X.x(', 'x(cls, a, b)'),
(classmethod_code + 'X().x(', 'x(cls, a, b)'),
(classmethod_code + 'X.x(', 'x(a, b)'),
(classmethod_code + 'X().x(', 'x(a, b)'),
(classmethod_code + 'X.static(', 'static(a, b)'),
(classmethod_code + 'X().static(', 'static(a, b)'),
@@ -87,9 +90,9 @@ def test_tree_signature(Script, environment, code, expected):
pytest.skip()
if expected is None:
assert not Script(code).call_signatures()
assert not Script(code).find_signatures()
else:
sig, = Script(code).call_signatures()
sig, = Script(code).find_signatures()
assert expected == sig.to_string()
@@ -179,7 +182,7 @@ def test_nested_signatures(Script, environment, combination, expected, skip_pre_
super().foo(**kwargs)
''')
code += 'z = ' + combination + '\nz('
sig, = Script(code).call_signatures()
sig, = Script(code).find_signatures()
computed = sig.to_string()
if not re.match(r'\w+\(', expected):
expected = '<lambda>(' + expected + ')'
@@ -188,7 +191,7 @@ def test_nested_signatures(Script, environment, combination, expected, skip_pre_
def test_pow_signature(Script):
# See github #1357
sigs = Script('pow(').call_signatures()
sigs = Script('pow(').find_signatures()
strings = {sig.to_string() for sig in sigs}
assert strings == {'pow(x: float, y: float, z: float, /) -> float',
'pow(x: float, y: float, /) -> float',
@@ -227,7 +230,7 @@ def test_pow_signature(Script):
]
)
def test_wraps_signature(Script, code, signature, skip_pre_python35):
sigs = Script(code).call_signatures()
sigs = Script(code).find_signatures()
assert {sig.to_string() for sig in sigs} == {signature}
@@ -260,7 +263,7 @@ def test_dataclass_signature(Script, skip_pre_python37, start, start_params):
code = 'from dataclasses import dataclass\n' + start + code
sig, = Script(code).call_signatures()
sig, = Script(code).find_signatures()
assert [p.name for p in sig.params] == start_params + ['name', 'price', 'quantity']
quantity, = sig.params[-1].infer()
assert quantity.name == 'int'
@@ -286,5 +289,13 @@ def test_param_resolving_to_static(Script, stmt, expected, skip_pre_python35):
def simple(a, b, *, c): ...
full_redirect(simple)('''.format(stmt=stmt))
sig, = Script(code).call_signatures()
sig, = Script(code).find_signatures()
assert sig.to_string() == expected
def test_overload(Script):
dir_ = get_example_dir('typing_overload')
code = 'from file import with_overload; with_overload('
x1, x2 = Script(code, path=os.path.join(dir_, 'foo.py')).find_signatures()
assert x1.to_string() == 'with_overload(x: int, y: int) -> float'
assert x2.to_string() == 'with_overload(x: str, y: list) -> float'
+8 -9
View File
@@ -17,7 +17,7 @@ def test_namedtuple_str(letter, expected, Script):
Person = collections.namedtuple('Person', 'name smart')
dave = Person('Dave', False)
dave.%s""") % letter
result = Script(source).completions()
result = Script(source).complete()
completions = set(r.name for r in result)
assert completions == set(expected)
@@ -28,7 +28,7 @@ def test_namedtuple_list(Script):
Cat = collections.namedtuple('Person', ['legs', u'length', 'large'])
garfield = Cat(4, '85cm', True)
garfield.l""")
result = Script(source).completions()
result = Script(source).complete()
completions = set(r.name for r in result)
assert completions == {'legs', 'length', 'large'}
@@ -42,7 +42,7 @@ def test_namedtuple_content(Script):
""")
def d(source):
x, = Script(source).goto_definitions()
x, = Script(source).infer()
return x.name
assert d(source + 'unnamed.bar') == 'int'
@@ -60,12 +60,11 @@ def test_nested_namedtuples(Script):
Dataset = collections.namedtuple('Dataset', ['data'])
Datasets = collections.namedtuple('Datasets', ['train'])
train_x = Datasets(train=Dataset('data_value'))
train_x.train.'''
))
assert 'data' in [c.name for c in s.completions()]
train_x.train.'''))
assert 'data' in [c.name for c in s.complete()]
def test_namedtuple_goto_definitions(Script):
def test_namedtuple_infer(Script):
source = dedent("""
from collections import namedtuple
@@ -74,7 +73,7 @@ def test_namedtuple_goto_definitions(Script):
from jedi.api import Script
d1, = Script(source).goto_definitions()
d1, = Script(source).infer()
assert d1.get_line_code() == "class Foo(tuple):\n"
assert d1.module_path is None
@@ -86,7 +85,7 @@ def test_re_sub(Script, environment):
version differences.
"""
def run(code):
defs = Script(code).goto_definitions()
defs = Script(code).infer()
return {d.name for d in defs}
names = run("import re; re.sub('a', 'a', 'f')")
+3 -2
View File
@@ -45,8 +45,9 @@ def test_completion(case, monkeypatch, environment, has_typing):
def test_static_analysis(static_analysis_case, environment):
if static_analysis_case.skip is not None:
pytest.skip(static_analysis_case.skip)
skip_reason = static_analysis_case.get_skip_reason(environment)
if skip_reason is not None:
pytest.skip(skip_reason)
else:
static_analysis_case.run(assert_static_analysis, environment)
+7 -7
View File
@@ -6,7 +6,7 @@ from parso import parse
def test_form_feed_characters(Script):
s = "\f\nclass Test(object):\n pass"
Script(s, line=2, column=18).call_signatures()
Script(s).find_signatures(line=2, column=18)
def check_p(src):
@@ -29,7 +29,7 @@ def test_if(Script):
# Two parsers needed, one for pass and one for the function.
check_p(src)
assert [d.name for d in Script(src, 8, 6).goto_definitions()] == ['int']
assert [d.name for d in Script(src).infer(8, 6)] == ['int']
def test_class_and_if(Script):
@@ -47,7 +47,7 @@ def test_class_and_if(Script):
# COMMENT
a_func()""")
check_p(src)
assert [d.name for d in Script(src).goto_definitions()] == ['int']
assert [d.name for d in Script(src).infer()] == ['int']
def test_add_to_end(Script):
@@ -70,8 +70,8 @@ def test_add_to_end(Script):
" self."
def complete(code, line=None, column=None):
script = Script(code, line, column, 'example.py')
assert script.completions()
script = Script(code, 'example.py')
assert script.complete(line, column)
complete(a, 7, 12)
complete(a + b)
@@ -82,7 +82,7 @@ def test_add_to_end(Script):
def test_tokenizer_with_string_literal_backslash(Script):
c = Script("statement = u'foo\\\n'; statement").goto_definitions()
c = Script("statement = u'foo\\\n'; statement").infer()
assert c[0]._name._value.get_safe_value() == 'foo'
@@ -90,6 +90,6 @@ def test_ellipsis_without_getitem(Script, environment):
if environment.version_info.major == 2:
pytest.skip('In 2.7 Ellipsis can only be used like x[...]')
def_, = Script('x=...;x').goto_definitions()
def_, = Script('x=...;x').infer()
assert def_.name == 'ellipsis'
@@ -6,7 +6,7 @@ def test_error_correction_with(Script):
with open() as f:
try:
f."""
comps = Script(source).completions()
comps = Script(source).complete()
assert len(comps) > 30
# `open` completions have a closed attribute.
assert [1 for c in comps if c.name == 'closed']
@@ -23,14 +23,14 @@ def test_string_literals(Script):
script = Script(dedent(source))
assert script._get_module_context().tree_node.end_pos == (6, 0)
assert script.completions()
assert script.complete()
def test_incomplete_function(Script):
source = '''return ImportErr'''
script = Script(dedent(source), 1, 3)
assert script.completions()
script = Script(dedent(source))
assert script.complete(1, 3)
def test_decorator_string_issue(Script):
@@ -46,5 +46,5 @@ def test_decorator_string_issue(Script):
bla.''')
s = Script(source)
assert s.completions()
assert s.complete()
assert s._get_module_context().tree_node.get_code() == source
@@ -62,13 +62,13 @@ def test_hex_values_in_docstring():
@pytest.mark.parametrize(
'code,call_signature', [
'code,signature', [
('def my_function(x, typed: Type, z):\n return', 'my_function(x, typed: Type, z)'),
('def my_function(x, y, z) -> str:\n return', 'my_function(x, y, z) -> str'),
('lambda x, y, z: x + y * z\n', '<lambda>(x, y, z)')
])
def test_get_call_signature(code, call_signature):
def test_get_signature(code, signature):
node = parse(code, version='3.5').children[0]
if node.type == 'simple_stmt':
node = node.children[0]
assert parser_utils.get_call_signature(node) == call_signature
assert parser_utils.get_signature(node) == signature
+20 -3
View File
@@ -12,14 +12,14 @@ def auto_import_json(monkeypatch):
def test_base_auto_import_modules(auto_import_json, Script):
loads, = Script('import json; json.loads').goto_definitions()
loads, = Script('import json; json.loads').infer()
assert isinstance(loads._name, ValueName)
value, = loads._name.infer()
assert isinstance(value.parent_context._value, StubModuleValue)
def test_auto_import_modules_imports(auto_import_json, Script):
main, = Script('from json import tool; tool.main').goto_definitions()
main, = Script('from json import tool; tool.main').infer()
assert isinstance(main._name, CompiledValueName)
@@ -31,4 +31,21 @@ def test_additional_dynamic_modules(monkeypatch, Script):
'additional_dynamic_modules',
['/foo/bar/jedi_not_existing_file.py']
)
assert not Script('def some_func(f):\n f.').completions()
assert not Script('def some_func(f):\n f.').complete()
def test_cropped_file_size(monkeypatch, names, Script):
code = 'class Foo(): pass\n'
monkeypatch.setattr(
settings,
'_cropped_file_size',
len(code)
)
foo, = names(code + code)
assert foo.line == 1
# It should just not crash if we are outside of the cropped range.
script = Script(code + code + 'Foo')
assert not script.infer()
assert 'Foo' in [c.name for c in script.complete()]
+5 -5
View File
@@ -33,14 +33,14 @@ def _check_speed(time_per_run, number=4, run_warm=True):
@_check_speed(0.5)
def test_os_path_join(Script):
s = "from posixpath import join; join('', '')."
assert len(Script(s).completions()) > 10 # is a str completion
assert len(Script(s).complete()) > 10 # is a str completion
@_check_speed(0.15)
def test_scipy_speed(Script):
s = 'import scipy.weave; scipy.weave.inline('
script = Script(s, 1, len(s), '')
script.call_signatures()
script = Script(s, path='')
script.find_signatures(1, len(s))
@_check_speed(0.8)
@@ -52,7 +52,7 @@ def test_precedence_slowdown(Script):
"""
with open('speed/precedence.py') as f:
line = len(f.read().splitlines())
assert Script(line=line, path='speed/precedence.py').goto_definitions()
assert Script(path='speed/precedence.py').infer(line=line)
@_check_speed(0.1)
@@ -70,4 +70,4 @@ def test_no_repr_computation(Script):
def __repr__(self):
time.sleep(0.2)
test = SlowRepr()
jedi.Interpreter('test.som', [locals()]).completions()
jedi.Interpreter('test.som', [locals()]).complete()
+26 -22
View File
@@ -19,7 +19,7 @@ class TestSetupReadline(unittest.TestCase):
self.namespace = self.NameSpace()
utils.setup_readline(self.namespace)
def completions(self, text):
def complete(self, text):
completer = readline.get_completer()
i = 0
completions = []
@@ -32,18 +32,18 @@ class TestSetupReadline(unittest.TestCase):
return completions
def test_simple(self):
assert self.completions('list') == ['list']
assert self.completions('importerror') == ['ImportError']
assert self.complete('list') == ['list']
assert self.complete('importerror') == ['ImportError']
s = "print(BaseE"
assert self.completions(s) == [s + 'xception']
assert self.complete(s) == [s + 'xception']
def test_nested(self):
assert self.completions('list.Insert') == ['list.insert']
assert self.completions('list().Insert') == ['list().insert']
assert self.complete('list.Insert') == ['list.insert']
assert self.complete('list().Insert') == ['list().insert']
def test_magic_methods(self):
assert self.completions('list.__getitem__') == ['list.__getitem__']
assert self.completions('list().__getitem__') == ['list().__getitem__']
assert self.complete('list.__getitem__') == ['list.__getitem__']
assert self.complete('list().__getitem__') == ['list().__getitem__']
def test_modules(self):
import sys
@@ -52,44 +52,48 @@ class TestSetupReadline(unittest.TestCase):
self.namespace.os = os
try:
assert self.completions('os.path.join') == ['os.path.join']
assert self.complete('os.path.join') == ['os.path.join']
string = 'os.path.join("a").upper'
assert self.completions(string) == [string]
assert self.complete(string) == [string]
c = {'os.' + d for d in dir(os) if d.startswith('ch')}
assert set(self.completions('os.ch')) == set(c)
assert set(self.complete('os.ch')) == set(c)
finally:
del self.namespace.sys
del self.namespace.os
def test_calls(self):
s = 'str(bytes'
assert self.completions(s) == [s, 'str(BytesWarning']
assert self.complete(s) == [s, 'str(BytesWarning']
def test_import(self):
s = 'from os.path import a'
assert set(self.completions(s)) == {s + 'ltsep', s + 'bspath'}
assert self.completions('import keyword') == ['import keyword']
assert set(self.complete(s)) == {s + 'ltsep', s + 'bspath'}
assert self.complete('import keyword') == ['import keyword']
import os
s = 'from os import '
goal = {s + el for el in dir(os)}
# There are minor differences, e.g. the dir doesn't include deleted
# items as well as items that are not only available on linux.
difference = set(self.completions(s)).symmetric_difference(goal)
difference = {x for x in difference if not x.startswith('from os import _')}
difference = set(self.complete(s)).symmetric_difference(goal)
difference = {
x for x in difference
if all(not x.startswith('from os import ' + s)
for s in ['_', 'O_', 'EX_', 'MFD_', 'SF_', 'ST_'])
}
# There are quite a few differences, because both Windows and Linux
# (posix and nt) libraries are included.
assert len(difference) < 38
# (posix and nt) librariesare included.
assert len(difference) < 20
@cwd_at('test')
def test_local_import(self):
s = 'import test_utils'
assert self.completions(s) == [s]
assert self.complete(s) == [s]
def test_preexisting_values(self):
self.namespace.a = range(10)
assert set(self.completions('a.')) == {'a.' + n for n in dir(range(1))}
assert set(self.complete('a.')) == {'a.' + n for n in dir(range(1))}
del self.namespace.a
def test_colorama(self):
@@ -106,8 +110,8 @@ class TestSetupReadline(unittest.TestCase):
pass
else:
self.namespace.colorama = colorama
assert self.completions('colorama')
assert self.completions('colorama.Fore.BLACK') == ['colorama.Fore.BLACK']
assert self.complete('colorama')
assert self.complete('colorama.Fore.BLACK') == ['colorama.Fore.BLACK']
del self.namespace.colorama