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