Adding new stuff

This commit is contained in:
ViktorBarzin 2017-07-09 00:23:01 +03:00
parent 9ef8a96f9a
commit 0b3d063cb3
1580 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,30 @@
# todo probably remove test_integration_keyword
def test_keyword_doc():
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():
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(self):
r = list(Script("a == b", 1, 3).goto_definitions())
assert len(r) == 1
assert len(r[0].doc) > 100
def test_lambda():
defs = Script('lambda x: x', column=0).goto_definitions()
assert [d.type for d in defs] == ['keyword']

View file

@ -0,0 +1,3 @@
""" needed for some modules to test against packages. """
some_variable = 1

View file

@ -0,0 +1,430 @@
# -----------------
# basic array lookups
# -----------------
#? int()
[1,""][0]
#? str()
[1,""][1]
#? int() str()
[1,""][2]
#? int() str()
[1,""][20]
#? int() str()
[1,""][str(hello)]
a = list()
#? list()
[a][0]
#? list()
[[a,a,a]][2][100]
c = [[a,""]]
#? str()
c[0][1]
b = [6,7]
#? int()
b[8-7]
# -----------------
# Slices
# -----------------
#? list()
b[8:]
#? list()
b[int():]
#? list()
b[:]
class _StrangeSlice():
def __getitem__(self, sliced):
return sliced
# Should not result in an error, just because the slice itself is returned.
#? slice()
_StrangeSlice()[1:2]
# -----------------
# iterable multiplication
# -----------------
a = ['']*2
#? list()
a
# -----------------
# tuple assignments
# -----------------
a1, b1 = (1, "")
#? int()
a1
#? str()
b1
(a2, b2) = (1, "")
#? int()
a2
#? str()
b2
# list assignment
[list1, list2] = (1, "")
#? int()
list1
#? str()
list2
[list3, list4] = [1, ""]
#? int()
list3
#? str()
list4
# -----------------
# subtuple assignment
# -----------------
(a3, (b3, c3)) = (1, ("", list))
#? list
c3
a4, (b4, c4) = (1, ("", list))
#? list
c4
#? int()
a4
#? str()
b4
# -----------------
# multiple assignments
# -----------------
a = b = 1
#? int()
a
#? int()
b
(a, b) = (c, (e, f)) = ('2', (3, 4))
#? str()
a
#? tuple()
b
#? str()
c
#? int()
e
#? int()
f
# -----------------
# unnessecary braces
# -----------------
a = (1)
#? int()
a
#? int()
(1)
#? int()
((1))
#? int()
((1)+1)
u, v = 1, ""
#? int()
u
((u1, v1)) = 1, ""
#? int()
u1
#? int()
(u1)
(a), b = 1, ''
#? int()
a
def a(): return ''
#? str()
(a)()
#? str()
(a)().replace()
#? int()
(tuple).index()
#? int()
(tuple)().index()
class C():
def __init__(self):
self.a = (str()).upper()
#? str()
C().a
# -----------------
# imbalanced sides
# -----------------
(f, g) = (1,)
#? int()
f
#? []
g.
(f, g, h) = (1,'')
#? int()
f
#? str()
g
#? []
h.
(f1, g1) = 1
#? []
f1.
#? []
g1.
(f, g) = (1,'',1.0)
#? int()
f
#? str()
g
# -----------------
# dicts
# -----------------
dic2 = {'asdf': 3, 'b': 'str'}
#? int()
dic2['asdf']
# string literal
#? int()
dic2[r'asdf']
#? int()
dic2[r'asdf']
#? int()
dic2[r'as' 'd' u'f']
#? int() str()
dic2['just_something']
# unpacking
a, b = dic2
#? str()
a
a, b = {1: 'x', 2.0: 1j}
#? int() float()
a
#? int() float()
b
def f():
""" github #83 """
r = {}
r['status'] = (200, 'ok')
return r
#? dict()
f()
# completion within dicts
#? 9 ['str']
{str: str}
# iteration problem (detected with sith)
d = dict({'a':''})
def y(a):
return a
#?
y(**d)
# problem with more complicated casts
dic = {str(key): ''}
#? str()
dic['']
for x in {1: 3.0, '': 1j}:
#? int() str()
x
# -----------------
# with variable as index
# -----------------
a = (1, "")
index = 1
#? str()
a[index]
# these should just ouput the whole array
index = int
#? int() str()
a[index]
index = int()
#? int() str()
a[index]
# dicts
index = 'asdf'
dic2 = {'asdf': 3, 'b': 'str'}
#? int()
dic2[index]
# -----------------
# __getitem__
# -----------------
class GetItem():
def __getitem__(self, index):
return 1.0
#? float()
GetItem()[0]
class GetItem():
def __init__(self, el):
self.el = el
def __getitem__(self, index):
return self.el
#? str()
GetItem("")[1]
class GetItemWithList():
def __getitem__(self, index):
return [1, 1.0, 's'][index]
#? float()
GetItemWithList()[1]
for i in 0, 2:
#? int() str()
GetItemWithList()[i]
# With super
class SuperYeah(list):
def __getitem__(self, index):
return super()[index]
#?
SuperYeah([1])[0]
#?
SuperYeah()[0]
# -----------------
# conversions
# -----------------
a = [1, ""]
#? int() str()
list(a)[1]
#? int() str()
list(a)[0]
#?
set(a)[0]
#? int() str()
list(set(a))[1]
#? int() str()
list(list(set(a)))[1]
# does not yet work, because the recursion catching is not good enough (catches # to much)
#? int() str()
list(set(list(set(a))))[1]
#? int() str()
list(set(set(a)))[1]
# frozenset
#? int() str()
list(frozenset(a))[1]
#? int() str()
list(set(frozenset(a)))[1]
# iter
#? int() str()
list(iter(a))[1]
#? int() str()
list(iter(list(set(a))))[1]
# tuple
#? int() str()
tuple(a)[1]
#? int() str()
tuple(list(set(a)))[1]
#? int()
tuple({1})[0]
#? int()
tuple((1,))[0]
# implementation detail for lists, should not be visible
#? []
list().__iterable
# With a list comprehension.
for i in set(a for a in [1]):
#? int()
i
# -----------------
# Merged Arrays
# -----------------
for x in [1] + ['']:
#? int() str()
x
# -----------------
# For loops with attribute assignment.
# -----------------
def test_func():
x = 'asdf'
for x.something in [6,7,8]:
pass
#? str()
x
for x.something, b in [[6, 6.0]]:
pass
#? str()
x
# -----------------
# PEP 3132 Extended Iterable Unpacking (star unpacking)
# -----------------
a, *b, c = [1, 'b', list, dict]
#? int()
a
#? str()
b
#? list
c
# Not valid syntax
a, *b, *c = [1, 'd', list]
#? int()
a
#? str()
b
#? list
c
lc = [x for a, *x in [(1, '', 1.0)]]
#?
lc[0][0]

View file

@ -0,0 +1,293 @@
# -----------------
# cursor position
# -----------------
#? 0 int
int()
#? 3 int
int()
#? 4 str
int(str)
# -----------------
# should not complete
# -----------------
#? []
.
#? []
str..
#? []
a(0):.
# -----------------
# if/else/elif
# -----------------
if (random.choice([0, 1])):
1
elif(random.choice([0, 1])):
a = 3
else:
a = ''
#? int() str()
a
def func():
if random.choice([0, 1]):
1
elif(random.choice([0, 1])):
a = 3
else:
a = ''
#? int() str()
return a
#? int() str()
func()
# -----------------
# keywords
# -----------------
#? list()
assert []
def focus_return():
#? list()
return []
# -----------------
# for loops
# -----------------
for a in [1,2]:
#? int()
a
for a1 in 1,"":
#? int() str()
a1
for a3, b3 in (1,""), (1,""), (1,""):
#? int()
a3
#? str()
b3
for a4, (b4, c4) in (1,("", list)), (1,("", list)):
#? int()
a4
#? str()
b4
#? list
c4
a = []
for i in [1,'']:
#? int() str()
i
a += [i]
#? int() str()
a[0]
for i in list([1,'']):
#? int() str()
i
#? int() str()
for x in [1,'']: x
a = []
b = [1.0,'']
for i in b:
a += [i]
#? float() str()
a[0]
for i in [1,2,3]:
#? int()
i
else:
i
# -----------------
# range()
# -----------------
for i in range(10):
#? int()
i
# -----------------
# ternary operator
# -----------------
a = 3
b = '' if a else set()
#? str() set()
b
def ret(a):
return ['' if a else set()]
#? str() set()
ret(1)[0]
#? str() set()
ret()[0]
# -----------------
# with statements
# -----------------
with open('') as f:
#? ['closed']
f.closed
for line in f:
#? str()
line
with open('') as f1, open('') as f2:
#? ['closed']
f1.closed
#? ['closed']
f2.closed
# -----------------
# global vars
# -----------------
def global_define():
global global_var_in_func
global_var_in_func = 3
#? int()
global_var_in_func
def funct1():
# From issue #610
global global_dict_var
global_dict_var = dict()
def funct2():
global global_dict_var
#? dict()
global_dict_var
# -----------------
# within docstrs
# -----------------
def a():
"""
#? ['global_define']
global_define
"""
pass
#?
# str literals in comment """ upper
def completion_in_comment():
#? ['Exception']
# might fail because the comment is not a leaf: Exception
pass
some_word
#? ['Exception']
# Very simple comment completion: Exception
# Commment after it
# -----------------
# magic methods
# -----------------
class A(object): pass
class B(): pass
#? ['__init__']
A.__init__
#? ['__init__']
B.__init__
#? ['__init__']
int().__init__
# -----------------
# comments
# -----------------
class A():
def __init__(self):
self.hello = {} # comment shouldn't be a string
#? dict()
A().hello
# -----------------
# unicode
# -----------------
a = 'smörbröd'
#? str()
a
xyz = 'smörbröd.py'
if 1:
#? str()
xyz
#?
¹.
# -----------------
# exceptions
# -----------------
try:
import math
except ImportError as i_a:
#? ['i_a']
i_a
#? ImportError()
i_a
try:
import math
except ImportError, i_b:
# TODO check this only in Python2
##? ['i_b']
i_b
##? ImportError()
i_b
class MyException(Exception):
def __init__(self, my_attr):
self.my_attr = my_attr
try:
raise MyException(1)
except MyException as e:
#? ['my_attr']
e.my_attr
#? 22 ['my_attr']
for x in e.my_attr:
pass
# -----------------
# continuations
# -----------------
foo = \
1
#? int()
foo
# -----------------
# module attributes
# -----------------
# Don't move this to imports.py, because there's a star import.
#? str()
__file__
#? ['__file__']
__file__

View file

@ -0,0 +1,470 @@
def find_class():
""" This scope is special, because its in front of TestClass """
#? ['ret']
TestClass.ret
if 1:
#? ['ret']
TestClass.ret
class FindClass():
#? []
TestClass.ret
if a:
#? []
TestClass.ret
def find_class(self):
#? ['ret']
TestClass.ret
if 1:
#? ['ret']
TestClass.ret
#? []
FindClass().find_class.self
#? []
FindClass().find_class.self.find_class
# set variables, which should not be included, because they don't belong to the
# class
second = 1
second = ""
class TestClass(object):
var_class = TestClass(1)
def __init__(self2, first_param, second_param, third=1.0):
self2.var_inst = first_param
self2.second = second_param
self2.first = first_param
a = 3
def var_func(self):
return 1
def get_first(self):
# traversal
self.second_new = self.second
return self.var_inst
def values(self):
self.var_local = 3
#? ['var_class', 'var_func', 'var_inst', 'var_local']
self.var_
def ret(self, a1):
# should not know any class functions!
#? []
values
#? ['return']
ret
return a1
# should not work
#? []
var_local
#? []
var_inst
#? []
var_func
# instance
inst = TestClass(1)
#? ['var_class', 'var_func', 'var_inst', 'var_local']
inst.var
#? ['var_class', 'var_func']
TestClass.var
#? int()
inst.var_local
#? []
TestClass.var_local.
#? int()
TestClass().ret(1)
# Should not return int(), because we want the type before `.ret(1)`.
#? 11 TestClass()
TestClass().ret(1)
#? int()
inst.ret(1)
myclass = TestClass(1, '', 3.0)
#? int()
myclass.get_first()
#? []
myclass.get_first.real
# too many params
#? int()
TestClass(1,1,1).var_inst
# too few params
#? int()
TestClass(1).first
#? []
TestClass(1).second.
# complicated variable settings in class
#? str()
myclass.second
#? str()
myclass.second_new
# multiple classes / ordering
ints = TestClass(1, 1.0)
strs = TestClass("", '')
#? float()
ints.second
#? str()
strs.second
#? ['var_class']
TestClass.var_class.var_class.var_class.var_class
# operations (+, *, etc) shouldn't be InstanceElements - #246
class A():
def __init__(self):
self.addition = 1 + 2
#? int()
A().addition
# should also work before `=`
#? 8 int()
A().addition = None
#? 8 int()
A(1).addition = None
#? 1 A
A(1).addition = None
a = A()
#? 8 int()
a.addition = None
# -----------------
# inheritance
# -----------------
class Base(object):
def method_base(self):
return 1
class SuperClass(Base):
class_super = 3
def __init__(self):
self.var_super = ''
def method_super(self):
self.var2_super = list
class Mixin(SuperClass):
def method_mixin(self):
return int
#? 20 SuperClass
class SubClass(SuperClass):
class_sub = 3
def __init__(self):
self.var_sub = ''
def method_sub(self):
self.var_sub = list
return tuple
instance = SubClass()
#? ['method_base', 'method_sub', 'method_super']
instance.method_
#? ['var2_super', 'var_sub', 'var_super']
instance.var
#? ['class_sub', 'class_super']
instance.class_
#? ['method_base', 'method_sub', 'method_super']
SubClass.method_
#? []
SubClass.var
#? ['class_sub', 'class_super']
SubClass.class_
# -----------------
# inheritance of builtins
# -----------------
class Base(str):
pass
#? ['upper']
Base.upper
#? ['upper']
Base().upper
# -----------------
# dynamic inheritance
# -----------------
class Angry(object):
def shout(self):
return 'THIS IS MALARKEY!'
def classgetter():
return Angry
class Dude(classgetter()):
def react(self):
#? ['shout']
self.s
# -----------------
# __call__
# -----------------
class CallClass():
def __call__(self):
return 1
#? int()
CallClass()()
# -----------------
# variable assignments
# -----------------
class V:
def __init__(self, a):
self.a = a
def ret(self):
return self.a
d = b
b = ret
if 1:
c = b
#? int()
V(1).b()
#? int()
V(1).c()
#?
V(1).d()
# Only keywords should be possible to complete.
#? ['is', 'in', 'not', 'and', 'or', 'if']
V(1).d()
# -----------------
# ordering
# -----------------
class A():
def b(self):
#? int()
a_func()
#? str()
self.a_func()
return a_func()
def a_func(self):
return ""
def a_func():
return 1
#? int()
A().b()
#? str()
A().a_func()
# -----------------
# nested classes
# -----------------
class A():
class B():
pass
def b(self):
return 1.0
#? float()
A().b()
class A():
def b(self):
class B():
def b(self):
return []
return B().b()
#? list()
A().b()
# -----------------
# ducktyping
# -----------------
def meth(self):
return self.a, self.b
class WithoutMethod():
a = 1
def __init__(self):
self.b = 1.0
def blub(self):
return self.b
m = meth
class B():
b = ''
a = WithoutMethod().m()
#? int()
a[0]
#? float()
a[1]
#? float()
WithoutMethod.blub(WithoutMethod())
#? str()
WithoutMethod.blub(B())
# -----------------
# __getattr__ / getattr() / __getattribute__
# -----------------
#? str().upper
getattr(str(), 'upper')
#? str.upper
getattr(str, 'upper')
# some strange getattr calls
#?
getattr(str, 1)
#?
getattr()
#?
getattr(str)
#?
getattr(getattr, 1)
#?
getattr(str, [])
class Base():
def ret(self, b):
return b
class Wrapper():
def __init__(self, obj):
self.obj = obj
def __getattr__(self, name):
return getattr(self.obj, name)
class Wrapper2():
def __getattribute__(self, name):
return getattr(Base(), name)
#? int()
Wrapper(Base()).ret(3)
#? int()
Wrapper2(Base()).ret(3)
class GetattrArray():
def __getattr__(self, name):
return [1]
#? int()
GetattrArray().something[0]
# -----------------
# private vars
# -----------------
class PrivateVar():
def __init__(self):
self.__var = 1
#? int()
self.__var
#? ['__var']
self.__var
#? []
PrivateVar().__var
#?
PrivateVar().__var
# -----------------
# super
# -----------------
class Super(object):
a = 3
def return_sup(self):
return 1
class TestSuper(Super):
#?
super()
def test(self):
#? Super()
super()
#? ['a']
super().a
if 1:
#? Super()
super()
def a():
#?
super()
def return_sup(self):
#? int()
return super().return_sup()
#? int()
TestSuper().return_sup()
# -----------------
# if flow at class level
# -----------------
class TestX(object):
def normal_method(self):
return 1
if True:
def conditional_method(self):
var = self.normal_method()
#? int()
var
return 2
def other_method(self):
var = self.conditional_method()
#? int()
var
# -----------------
# mro method
# -----------------
class A(object):
a = 3
#? ['mro']
A.mro
#? []
A().mro
# -----------------
# mro resolution
# -----------------
class B(A()):
b = 3
#?
B.a
#?
B().a
#? int()
B.b
#? int()
B().b

View file

@ -0,0 +1,26 @@
"""
Special cases of completions (typically special positions that caused issues
with context parsing.
"""
def pass_decorator(func):
return func
def x():
return (
1,
#? ["tuple"]
tuple
)
# Comment just somewhere
class MyClass:
@pass_decorator
def x(foo,
#? 5 ["tuple"]
tuple,
):
return 1

View file

@ -0,0 +1,14 @@
""" Mostly for stupid error reports of @dbrgn. :-) """
import time
class Foo(object):
global time
asdf = time
def asdfy():
return Foo
xorz = getattr(asdfy()(), 'asdf')
#? time
xorz

View file

@ -0,0 +1,200 @@
# -----------------
# list comprehensions
# -----------------
# basics:
a = ['' for a in [1]]
#? str()
a[0]
#? ['insert']
a.insert
a = [a for a in [1]]
#? int()
a[0]
y = 1.0
# Should not leak.
[y for y in [3]]
#? float()
y
a = [a for a in (1, 2)]
#? int()
a[0]
a = [a for a,b in [(1,'')]]
#? int()
a[0]
arr = [1,'']
a = [a for a in arr]
#? int()
a[0]
#? str()
a[1]
#? int() str()
a[2]
a = [a if 1.0 else '' for a in [1] if [1.0]]
#? int() str()
a[0]
# name resolve should be correct
left, right = 'a', 'b'
left, right = [x for x in (left, right)]
#? str()
left
# with a dict literal
#? int()
[a for a in {1:'x'}][0]
# list comprehensions should also work in combination with functions
def listen(arg):
for x in arg:
#? str()
x
listen(['' for x in [1]])
#?
([str for x in []])[0]
# with a set literal
#? int()
[a for a in {1, 2, 3}][0]
# -----------------
# nested list comprehensions
# -----------------
b = [a for arr in [[1]] for a in arr]
#? int()
b[0]
b = [a for arr in [[1]] if '' for a in arr if '']
#? int()
b[0]
b = [b for arr in [[[1.0]]] for a in arr for b in a]
#? float()
b[0]
# jedi issue #26
#? list()
a = [[int(v) for v in line.strip().split() if v] for line in ["123", "123", "123"] if line]
#? list()
a[0]
#? int()
a[0][0]
# -----------------
# generator comprehensions
# -----------------
left, right = (i for i in (1, ''))
#? int()
left
#? str()
right
gen = (i for i in (1,))
#? int()
next(gen)
#?
gen[0]
gen = (a for arr in [[1.0]] for a in arr)
#? float()
next(gen)
#? int()
(i for i in (1,)).send()
# issues with different formats
left, right = (i for i in
('1', 2))
#? str()
left
#? int()
right
# -----------------
# dict comprehensions
# -----------------
#? int()
list({a - 1: 3 for a in [1]})[0]
d = {a - 1: b for a, b in {1: 'a', 3: 1.0}.items()}
#? int()
list(d)[0]
#? str() float()
d.values()[0]
#? str()
d[0]
#? float() str()
d[1]
#? float()
d[2]
# -----------------
# set comprehensions
# -----------------
#? set()
{a - 1 for a in [1]}
#? set()
{a for a in range(10)}
#? int()
[x for x in {a for a in range(10)}][0]
#? int()
{a for a in range(10)}.pop()
#? float() str()
{b for a in [[3.0], ['']] for b in a}.pop()
#? int()
next(iter({a for a in range(10)}))
# -----------------
# name resolution in comprehensions.
# -----------------
def x():
"""Should not try to resolve to the if hio, which was a bug."""
#? 22
[a for a in h if hio]
if hio: pass
# -----------------
# slices
# -----------------
#? list()
foo = [x for x in [1, '']][:1]
#? int()
foo[0]
# -----------------
# In class
# -----------------
class X():
def __init__(self, bar):
self.bar = bar
def foo(self):
x = [a for a in self.bar][0]
#? int()
x
return x
#? int()
X([1]).foo()

View file

@ -0,0 +1,32 @@
class Base():
myfoobar = 3
class X(Base):
def func(self, foo):
pass
class Y(X):
def actual_function(self):
pass
#? []
def actual_function
#? ['func']
def f
#? []
def __class__
#? ['__repr__']
def __repr__
#? []
def mro
#? ['myfoobar']
myfoobar
#? []
myfoobar

View file

@ -0,0 +1,306 @@
# -----------------
# normal decorators
# -----------------
def decorator(func):
def wrapper(*args):
return func(1, *args)
return wrapper
@decorator
def decorated(a,b):
return a,b
exe = decorated(set, '')
#? set
exe[1]
#? int()
exe[0]
# more complicated with args/kwargs
def dec(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@dec
def fu(a, b, c, *args, **kwargs):
return a, b, c, args, kwargs
exe = fu(list, c=set, b=3, d='')
#? list
exe[0]
#? int()
exe[1]
#? set
exe[2]
#? []
exe[3][0].
#? str()
exe[4]['d']
exe = fu(list, set, 3, '', d='')
#? str()
exe[3][0]
# -----------------
# multiple decorators
# -----------------
def dec2(func2):
def wrapper2(first_arg, *args2, **kwargs2):
return func2(first_arg, *args2, **kwargs2)
return wrapper2
@dec2
@dec
def fu2(a, b, c, *args, **kwargs):
return a, b, c, args, kwargs
exe = fu2(list, c=set, b=3, d='str')
#? list
exe[0]
#? int()
exe[1]
#? set
exe[2]
#? []
exe[3][0].
#? str()
exe[4]['d']
# -----------------
# Decorator is a class
# -----------------
def same_func(func):
return func
class Decorator(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
return self.func(1, *args, **kwargs)
@Decorator
def nothing(a,b,c):
return a,b,c
#? int()
nothing("")[0]
#? str()
nothing("")[1]
@same_func
@Decorator
def nothing(a,b,c):
return a,b,c
#? int()
nothing("")[0]
class MethodDecoratorAsClass():
class_var = 3
@Decorator
def func_without_self(arg, arg2):
return arg, arg2
@Decorator
def func_with_self(self, arg):
return self.class_var
#? int()
MethodDecoratorAsClass().func_without_self('')[0]
#? str()
MethodDecoratorAsClass().func_without_self('')[1]
#?
MethodDecoratorAsClass().func_with_self(1)
class SelfVars():
"""Init decorator problem as an instance, #247"""
@Decorator
def __init__(self):
"""
__init__ decorators should be ignored when looking up variables in the
class.
"""
self.c = list
@Decorator
def shouldnt_expose_var(not_self):
"""
Even though in real Python this shouldn't expose the variable, in this
case Jedi exposes the variable, because these kind of decorators are
normally descriptors, which SHOULD be exposed (at least 90%).
"""
not_self.b = 1.0
def other_method(self):
#? float()
self.b
#? list
self.c
# -----------------
# not found decorators (are just ignored)
# -----------------
@not_found_decorator
def just_a_func():
return 1
#? int()
just_a_func()
#? ['__closure__']
just_a_func.__closure__
class JustAClass:
@not_found_decorator2
def a(self):
return 1
#? ['__call__']
JustAClass().a.__call__
#? int()
JustAClass().a()
#? ['__call__']
JustAClass.a.__call__
#? int()
JustAClass.a()
# -----------------
# illegal decorators
# -----------------
class DecoratorWithoutCall():
def __init__(self, func):
self.func = func
@DecoratorWithoutCall
def f():
return 1
# cannot be resolved - should be ignored
@DecoratorWithoutCall(None)
def g():
return 1
#?
f()
#? int()
g()
class X():
@str
def x(self):
pass
def y(self):
#? str()
self.x
#?
self.x()
# -----------------
# method decorators
# -----------------
def dec(f):
def wrapper(s):
return f(s)
return wrapper
class MethodDecorators():
_class_var = 1
def __init__(self):
self._method_var = ''
@dec
def constant(self):
return 1.0
@dec
def class_var(self):
return self._class_var
@dec
def method_var(self):
return self._method_var
#? float()
MethodDecorators().constant()
#? int()
MethodDecorators().class_var()
#? str()
MethodDecorators().method_var()
class Base():
@not_existing
def __init__(self):
pass
@not_existing
def b(self):
return ''
@dec
def c(self):
return 1
class MethodDecoratorDoesntExist(Base):
"""#272 github: combination of method decorators and super()"""
def a(self):
#?
super().__init__()
#? str()
super().b()
#? int()
super().c()
#? float()
self.d()
@doesnt_exist
def d(self):
return 1.0
# -----------------
# others
# -----------------
def memoize(function):
def wrapper(*args):
if random.choice([0, 1]):
pass
else:
rv = function(*args)
return rv
return wrapper
@memoize
def follow_statement(stmt):
return stmt
# here we had problems with the else clause, because the parent was not right.
#? int()
follow_statement(1)
# -----------------
# class decorators
# -----------------
# class decorators should just be ignored
@should_ignore
class A():
def ret(self):
return 1
#? int()
A().ret()

View file

@ -0,0 +1,68 @@
"""
Fallback to callee definition when definition not found.
- https://github.com/davidhalter/jedi/issues/131
- https://github.com/davidhalter/jedi/pull/149
"""
"""Parenthesis closed at next line."""
# Ignore these definitions for a little while, not sure if we really want them.
# python <= 2.5
#? isinstance
isinstance(
)
#? isinstance
isinstance(
)
#? isinstance
isinstance(None,
)
#? isinstance
isinstance(None,
)
"""Parenthesis closed at same line."""
# Note: len('isinstance(') == 11
#? 11 isinstance
isinstance()
# Note: len('isinstance(None,') == 16
##? 16 isinstance
isinstance(None,)
# Note: len('isinstance(None,') == 16
##? 16 isinstance
isinstance(None, )
# Note: len('isinstance(None, ') == 17
##? 17 isinstance
isinstance(None, )
# Note: len('isinstance( ') == 12
##? 12 isinstance
isinstance( )
"""Unclosed parenthesis."""
#? isinstance
isinstance(
def x(): pass # acts like EOF
##? isinstance
isinstance(
def x(): pass # acts like EOF
#? isinstance
isinstance(None,
def x(): pass # acts like EOF
##? isinstance
isinstance(None,

View file

@ -0,0 +1,219 @@
class RevealAccess(object):
"""
A data descriptor that sets and returns values
normally and prints a message logging their access.
"""
def __init__(self, initval=None, name='var'):
self.val = initval
self.name = name
def __get__(self, obj, objtype):
print('Retrieving', self.name)
return self.val
def __set__(self, obj, val):
print('Updating', self.name)
self.val = val
def just_a_method(self):
pass
class C(object):
x = RevealAccess(10, 'var "x"')
#? RevealAccess()
x
#? ['just_a_method']
x.just_a_method
y = 5.0
def __init__(self):
#? int()
self.x
#? []
self.just_a_method
#? []
C.just_a_method
m = C()
#? int()
m.x
#? float()
m.y
#? int()
C.x
#? []
m.just_a_method
#? []
C.just_a_method
# -----------------
# properties
# -----------------
class B():
@property
def r(self):
return 1
@r.setter
def r(self, value):
return ''
def t(self):
return ''
p = property(t)
#? []
B().r().
#? int()
B().r
#? str()
B().p
#? []
B().p().
class PropClass():
def __init__(self, a):
self.a = a
@property
def ret(self):
return self.a
@ret.setter
def ret(self, value):
return 1.0
def ret2(self):
return self.a
ret2 = property(ret2)
@property
def nested(self):
""" causes recusions in properties, should work """
return self.ret
@property
def nested2(self):
""" causes recusions in properties, should not work """
return self.nested2
@property
def join1(self):
""" mutual recusion """
return self.join2
@property
def join2(self):
""" mutual recusion """
return self.join1
#? str()
PropClass("").ret
#? []
PropClass().ret.
#? str()
PropClass("").ret2
#?
PropClass().ret2
#? int()
PropClass(1).nested
#? []
PropClass().nested.
#?
PropClass(1).nested2
#? []
PropClass().nested2.
#?
PropClass(1).join1
# -----------------
# staticmethod/classmethod
# -----------------
class E(object):
a = ''
def __init__(self, a):
self.a = a
def f(x):
return x
f = staticmethod(f)
@staticmethod
def g(x):
return x
def s(cls, x):
return x
s = classmethod(s)
@classmethod
def t(cls, x):
return x
@classmethod
def u(cls, x):
return cls.a
e = E(1)
#? int()
e.f(1)
#? int()
E.f(1)
#? int()
e.g(1)
#? int()
E.g(1)
#? int()
e.s(1)
#? int()
E.s(1)
#? int()
e.t(1)
#? int()
E.t(1)
#? str()
e.u(1)
#? str()
E.u(1)
# -----------------
# Conditions
# -----------------
from functools import partial
class Memoize():
def __init__(self, func):
self.func = func
def __get__(self, obj, objtype):
if obj is None:
return self.func
return partial(self, obj)
def __call__(self, *args, **kwargs):
# We don't do caching here, but that's what would normally happen.
return self.func(*args, **kwargs)
class MemoizeTest():
def __init__(self, x):
self.x = x
@Memoize
def some_func(self):
return self.x
#? int()
MemoizeTest(10).some_func()
# Now also call the same function over the class (see if clause above).
#? float()
MemoizeTest.some_func(MemoizeTest(10.0))

View file

@ -0,0 +1,235 @@
""" Test docstrings in functions and classes, which are used to infer types """
# -----------------
# sphinx style
# -----------------
def sphinxy(a, b, c, d, x):
""" asdfasdf
:param a: blablabla
:type a: str
:type b: (str, int)
:type c: random.Random
:type d: :class:`random.Random`
:param str x: blablabla
:rtype: dict
"""
#? str()
a
#? str()
b[0]
#? int()
b[1]
#? ['seed']
c.seed
#? ['seed']
d.seed
#? ['lower']
x.lower
#? dict()
sphinxy()
# wrong declarations
def sphinxy2(a, b, x):
"""
:param a: Forgot type declaration
:type a:
:param b: Just something
:type b: ``
:param x: Just something without type
:rtype:
"""
#?
a
#?
b
#?
x
#?
sphinxy2()
# local classes -> github #370
class ProgramNode():
pass
def local_classes(node, node2):
"""
:type node: ProgramNode
... and the class definition after this func definition:
:type node2: ProgramNode2
"""
#? ProgramNode()
node
#? ProgramNode2()
node2
class ProgramNode2():
pass
def list_with_non_imports(lst):
"""
Should be able to work with tuples and lists and still import stuff.
:type lst: (random.Random, [collections.defaultdict, ...])
"""
#? ['seed']
lst[0].seed
import collections as col
# use some weird index
#? col.defaultdict()
lst[1][10]
def two_dots(a):
"""
:type a: json.decoder.JSONDecoder
"""
#? ['raw_decode']
a.raw_decode
# sphinx returns
def return_module_object():
"""
:rtype: :class:`random.Random`
"""
#? ['seed']
return_module_object().seed
# -----------------
# epydoc style
# -----------------
def epydoc(a, b):
""" asdfasdf
@type a: str
@param a: blablabla
@type b: (str, int)
@param b: blablah
@rtype: list
"""
#? str()
a
#? str()
b[0]
#? int()
b[1]
#? list()
epydoc()
# Returns with param type only
def rparam(a,b):
"""
@type a: str
"""
return a
#? str()
rparam()
# Composite types
def composite():
"""
@rtype: (str, int, dict)
"""
x, y, z = composite()
#? str()
x
#? int()
y
#? dict()
z
# Both docstring and calculated return type
def both():
"""
@rtype: str
"""
return 23
#? str() int()
both()
class Test(object):
def __init__(self):
self.teststr = ""
"""
# jedi issue #210
"""
def test(self):
#? ['teststr']
self.teststr
# -----------------
# statement docstrings
# -----------------
d = ''
""" bsdf """
#? str()
d.upper()
# -----------------
# class docstrings
# -----------------
class InInit():
def __init__(self, foo):
"""
:type foo: str
"""
#? str()
foo
class InClass():
"""
:type foo: str
"""
def __init__(self, foo):
#? str()
foo
class InBoth():
"""
:type foo: str
"""
def __init__(self, foo):
"""
:type foo: int
"""
#? str() int()
foo
def __init__(foo):
"""
:type foo: str
"""
#? str()
foo
# -----------------
# Renamed imports (#507)
# -----------------
import datetime
from datetime import datetime as datetime_imported
def import_issues(foo):
"""
@type foo: datetime_imported
"""
#? datetime.datetime()
foo

View file

@ -0,0 +1,306 @@
"""
Checking for ``list.append`` and all the other possible array modifications.
"""
# -----------------
# list.append
# -----------------
arr = []
for a in [1,2]:
arr.append(a);
arr.append # should not cause an exception
arr.append() # should not cause an exception
#? int()
arr[10]
arr = [tuple()]
for a in [1,2]:
arr.append(a);
#? int() tuple()
arr[10]
#? int()
arr[10].index()
arr = list([])
arr.append(1)
#? int()
arr[0]
# -----------------
# list.insert
# -----------------
arr = [""]
arr.insert(0, 1.0)
# on exception due to this, please!
arr.insert(0)
arr.insert()
#? float() str()
arr[10]
for a in arr:
#? float() str()
a
#? float() str()
list(arr)[10]
# -----------------
# set.add
# -----------------
st = {1.0}
for a in [1,2]:
st.add(a)
st.append('') # lists should not have an influence
st.add # should not cause an exception
st.add()
# -----------------
# list.extend / set.update
# -----------------
arr = [1.0]
arr.extend([1,2,3])
arr.extend([])
arr.extend("") # should ignore
#? float() int()
arr[100]
a = set(arr)
a.update(list(["", 1]))
#? float() int() str()
list(a)[0]
# -----------------
# set/list initialized as functions
# -----------------
st = set()
st.add(1)
#? int()
for s in st: s
lst = list()
lst.append(1)
#? int()
for i in lst: i
# -----------------
# renames / type changes
# -----------------
arr = []
arr2 = arr
arr2.append('')
#? str()
arr2[0]
st = {1.0}
st.add(1)
lst = list(st)
lst.append('')
#? float() int() str()
lst[0]
lst = [1]
lst.append(1.0)
s = set(lst)
s.add("")
lst = list(s)
lst.append({})
#? dict() int() float() str()
lst[0]
# should work with tuple conversion, too.
#? dict() int() float() str()
tuple(lst)[0]
# but not with an iterator
#?
iter(lst)[0]
# -----------------
# complex including +=
# -----------------
class C(): pass
class D(): pass
class E(): pass
lst = [1]
lst.append(1.0)
lst += [C]
s = set(lst)
s.add("")
s += [D]
lst = list(s)
lst.append({})
lst += [E]
##? dict() int() float() str() C D E
lst[0]
# -----------------
# functions
# -----------------
def arr_append(arr4, a):
arr4.append(a)
def add_to_arr(arr2, a):
arr2.append(a)
return arr2
def app(a):
arr3.append(a)
arr3 = [1.0]
res = add_to_arr(arr3, 1)
arr_append(arr3, 'str')
app(set())
#? float() str() int() set()
arr3[10]
#? float() str() int() set()
res[10]
# -----------------
# returns, special because the module dicts are not correct here.
# -----------------
def blub():
a = []
a.append(1.0)
#? float()
a[0]
return a
#? float()
blub()[0]
# list with default
def blub():
a = list([1])
a.append(1.0)
return a
#? int() float()
blub()[0]
# empty list
def blub():
a = list()
a.append(1.0)
return a
#? float()
blub()[0]
# with if
def blub():
if 1:
a = []
a.append(1.0)
return a
#? float()
blub()[0]
# with else clause
def blub():
if random.choice([0, 1]):
1
else:
a = []
a.append(1)
return a
#? int()
blub()[0]
# -----------------
# returns, the same for classes
# -----------------
class C():
def blub(self, b):
if 1:
a = []
a.append(b)
return a
def blub2(self):
""" mapper function """
a = self.blub(1.0)
#? float()
a[0]
return a
def literal_arr(self, el):
self.a = []
self.a.append(el)
#? int()
self.a[0]
return self.a
def list_arr(self, el):
self.b = list([])
self.b.append(el)
#? float()
self.b[0]
return self.b
#? int()
C().blub(1)[0]
#? float()
C().blub2(1)[0]
#? int()
C().a[0]
#? int()
C().literal_arr(1)[0]
#? float()
C().b[0]
#? float()
C().list_arr(1.0)[0]
# -----------------
# array recursions
# -----------------
a = set([1.0])
a.update(a)
a.update([1])
#? float() int()
list(a)[0]
def first(a):
b = []
b.append(a)
b.extend(second(a))
return list(b)
def second(a):
b = []
b.extend(first(a))
return list(b)
#? float()
first(1.0)[0]
def third():
b = []
b.extend
extend()
b.extend(first())
return list(b)
#?
third()[0]

View file

@ -0,0 +1,134 @@
"""
This is used for dynamic object completion.
Jedi tries to guess param types with a backtracking approach.
"""
def func(a, default_arg=2):
#? int()
default_arg
#? int() str()
return a
#? int()
func(1)
func
int(1) + (int(2))+ func('')
# Again the same function, but with another call.
def func(a):
#? float()
return a
func(1.0)
# Again the same function, but with no call.
def func(a):
#?
return a
def func(a):
#? float()
return a
str(func(1.0))
# -----------------
# *args, **args
# -----------------
def arg(*args):
#? tuple()
args
#? int()
args[0]
arg(1,"")
# -----------------
# decorators
# -----------------
def def_func(f):
def wrapper(*args, **kwargs):
return f(*args, **kwargs)
return wrapper
@def_func
def func(c):
#? str()
return c
#? str()
func("str")
@def_func
def func(c=1):
#? int() float()
return c
func(1.0)
def tricky_decorator(func):
def wrapper(*args):
return func(1, *args)
return wrapper
@tricky_decorator
def func(a, b):
#? int()
a
#? float()
b
func(1.0)
# Needs to be here, because in this case func is an import -> shouldn't lead to
# exceptions.
import sys as func
func.sys
# -----------------
# classes
# -----------------
class A():
def __init__(self, a):
#? str()
a
A("s")
class A():
def __init__(self, a):
#? int()
a
self.a = a
def test(self, a):
#? float()
a
self.c = self.test2()
def test2(self):
#? int()
return self.a
def test3(self):
#? int()
self.test2()
#? int()
self.c
A(3).test(2.0)
A(3).test2()
# -----------------
# list comprehensions
# -----------------
def from_comprehension(foo):
#? int() float()
return foo
[from_comprehension(1.0) for n in (1,)]
[from_comprehension(n) for n in (1,)]

View file

@ -0,0 +1,257 @@
def foo(x):
if 1.0:
return 1
else:
return ''
#? int()
foo(1)
# Exceptions are not analyzed. So check both if branches
def try_except(x):
try:
if 0:
return 1
else:
return ''
except AttributeError:
return 1.0
#? float() str()
try_except(1)
# Exceptions are not analyzed. So check both if branches
def try_except(x):
try:
if 0:
return 1
else:
return ''
except AttributeError:
return 1.0
#? float() str()
try_except(1)
# -----------------
# elif
# -----------------
def elif_flows1(x):
if False:
return 1
elif True:
return 1.0
else:
return ''
#? float()
elif_flows1(1)
def elif_flows2(x):
try:
if False:
return 1
elif 0:
return 1.0
else:
return ''
except ValueError:
return set
#? str() set
elif_flows2(1)
def elif_flows3(x):
try:
if True:
return 1
elif 0:
return 1.0
else:
return ''
except ValueError:
return set
#? int() set
elif_flows3(1)
# -----------------
# mid-difficulty if statements
# -----------------
def check(a):
if a is None:
return 1
return ''
return set
#? int()
check(None)
#? str()
check('asb')
a = list
if 2 == True:
a = set
elif 1 == True:
a = 0
#? int()
a
if check != 1:
a = ''
#? str()
a
if check == check:
a = list
#? list
a
if check != check:
a = set
else:
a = dict
#? dict
a
if not (check is not check):
a = 1
#? int()
a
# -----------------
# name resolution
# -----------------
a = list
def elif_name(x):
try:
if True:
a = 1
elif 0:
a = 1.0
else:
return ''
except ValueError:
a = x
return a
#? int() set
elif_name(set)
if 0:
a = ''
else:
a = int
#? int
a
# -----------------
# isinstance
# -----------------
class A(): pass
def isinst(x):
if isinstance(x, A):
return dict
elif isinstance(x, int) and x == 1 or x is True:
return set
elif isinstance(x, (float, reversed)):
return list
elif not isinstance(x, str):
return tuple
return 1
#? dict
isinst(A())
#? set
isinst(True)
#? set
isinst(1)
#? tuple
isinst(2)
#? list
isinst(1.0)
#? tuple
isinst(False)
#? int()
isinst('')
# -----------------
# flows that are not reachable should be able to access parent scopes.
# -----------------
foobar = ''
if 0:
within_flow = 1.0
#? float()
within_flow
#? str()
foobar
if 0:
nested = 1
#? int()
nested
#? float()
within_flow
#? str()
foobar
#?
nested
# -----------------
# True objects like modules
# -----------------
class X():
pass
if X:
a = 1
else:
a = ''
#? int()
a
# -----------------
# Recursion issues
# -----------------
def possible_recursion_error(filename):
if filename == 'a':
return filename
# It seems like without the brackets there wouldn't be a RecursionError.
elif type(filename) == str:
return filename
if NOT_DEFINED:
s = str()
else:
s = str()
#? str()
possible_recursion_error(s)
# -----------------
# In combination with imports
# -----------------
from import_tree import flow_import
if 1 == flow_import.env:
a = 1
elif 2 == flow_import.env:
a = ''
elif 3 == flow_import.env:
a = 1.0
#? int() str()
a

View file

@ -0,0 +1,475 @@
def array(first_param):
#? ['first_param']
first_param
return list()
#? []
array.first_param
#? []
array.first_param.
func = array
#? []
func.first_param
#? list()
array()
#? ['array']
arr
def inputs(param):
return param
#? list
inputs(list)
def variable_middle():
var = 3
return var
#? int()
variable_middle()
def variable_rename(param):
var = param
return var
#? int()
variable_rename(1)
def multi_line_func(a, # comment blabla
b):
return b
#? str()
multi_line_func(1,'')
def multi_line_call(b):
return b
multi_line_call(
#? int()
b=1)
# nothing after comma
def asdf(a):
return a
x = asdf(a=1,
)
#? int()
x
# -----------------
# double execution
# -----------------
def double_exe(param):
return param
#? str()
variable_rename(double_exe)("")
# -> shouldn't work (and throw no error)
#? []
variable_rename(list())().
#? []
variable_rename(1)().
# -----------------
# recursions (should ignore)
# -----------------
def recursion(a, b):
if a:
return b
else:
return recursion(a+".", b+1)
# Does not also return int anymore, because we now support operators in simple cases.
#? float()
recursion("a", 1.0)
def other(a):
return recursion2(a)
def recursion2(a):
if random.choice([0, 1]):
return other(a)
else:
if random.choice([0, 1]):
return recursion2("")
else:
return a
#? int() str()
recursion2(1)
# -----------------
# ordering
# -----------------
def a():
#? int()
b()
return b()
def b():
return 1
#? int()
a()
# -----------------
# keyword arguments
# -----------------
def func(a=1, b=''):
return a, b
exe = func(b=list, a=tuple)
#? tuple
exe[0]
#? list
exe[1]
# -----------------
# default arguments
# -----------------
#? int()
func()[0]
#? str()
func()[1]
#? float()
func(1.0)[0]
#? str()
func(1.0)[1]
#? float()
func(a=1.0)[0]
#? str()
func(a=1.0)[1]
#? int()
func(b=1.0)[0]
#? float()
func(b=1.0)[1]
#? list
func(a=list, b=set)[0]
#? set
func(a=list, b=set)[1]
def func_default(a, b=1):
return a, b
def nested_default(**kwargs):
return func_default(**kwargs)
#? float()
nested_default(a=1.0)[0]
#? int()
nested_default(a=1.0)[1]
#? str()
nested_default(a=1.0, b='')[1]
# Defaults should only work if they are defined before - not after.
def default_function(a=default):
#?
return a
#?
default_function()
default = int()
def default_function(a=default):
#? int()
return a
#? int()
default_function()
# -----------------
# closures
# -----------------
def a():
l = 3
def func_b():
l = ''
#? str()
l
#? ['func_b']
func_b
#? int()
l
# -----------------
# *args
# -----------------
def args_func(*args):
#? tuple()
return args
exe = args_func(1, "")
#? int()
exe[0]
#? str()
exe[1]
# illegal args (TypeError)
#?
args_func(*1)[0]
# iterator
#? int()
args_func(*iter([1]))[0]
# different types
e = args_func(*[1+"", {}])
#? int() str()
e[0]
#? dict()
e[1]
_list = [1,""]
exe2 = args_func(_list)[0]
#? str()
exe2[1]
exe3 = args_func([1,""])[0]
#? str()
exe3[1]
def args_func(arg1, *args):
return arg1, args
exe = args_func(1, "", list)
#? int()
exe[0]
#? tuple()
exe[1]
#? list
exe[1][1]
# In a dynamic search, both inputs should be given.
def simple(a):
#? int() str()
return a
def xargs(*args):
return simple(*args)
xargs(1)
xargs('')
# *args without a self symbol
def memoize(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
class Something():
@memoize
def x(self, a, b=1):
return a
#? int()
Something().x(1)
# -----------------
# ** kwargs
# -----------------
def kwargs_func(**kwargs):
#? ['keys']
kwargs.keys
#? dict()
return kwargs
exe = kwargs_func(a=3,b=4.0)
#? dict()
exe
#? int()
exe['a']
#? float()
exe['b']
#? int() float()
exe['c']
a = 'a'
exe2 = kwargs_func(**{a:3,
'b':4.0})
#? int()
exe2['a']
#? float()
exe2['b']
#? int() float()
exe2['c']
# -----------------
# *args / ** kwargs
# -----------------
def func_without_call(*args, **kwargs):
#? tuple()
args
#? dict()
kwargs
def fu(a=1, b="", *args, **kwargs):
return a, b, args, kwargs
exe = fu(list, 1, "", c=set, d="")
#? list
exe[0]
#? int()
exe[1]
#? tuple()
exe[2]
#? str()
exe[2][0]
#? dict()
exe[3]
#? set
exe[3]['c']
def kwargs_iteration(**kwargs):
return kwargs
for x in kwargs_iteration(d=3):
#? float()
{'d': 1.0, 'c': '1'}[x]
# -----------------
# nested *args
# -----------------
def function_args(a, b, c):
return b
def nested_args(*args):
return function_args(*args)
def nested_args2(*args, **kwargs):
return nested_args(*args)
#? int()
nested_args('', 1, 1.0, list)
#? []
nested_args('').
#? int()
nested_args2('', 1, 1.0)
#? []
nested_args2('').
# -----------------
# nested **kwargs
# -----------------
def nested_kw(**kwargs1):
return function_args(**kwargs1)
def nested_kw2(**kwargs2):
return nested_kw(**kwargs2)
# invalid command, doesn't need to return anything
#?
nested_kw(b=1, c=1.0, list)
#? int()
nested_kw(b=1)
# invalid command, doesn't need to return anything
#?
nested_kw(d=1.0, b=1, list)
#? int()
nested_kw(a=3.0, b=1)
#? int()
nested_kw(b=1, a=r"")
#? []
nested_kw(1, '').
#? []
nested_kw(a='').
#? int()
nested_kw2(b=1)
#? int()
nested_kw2(b=1, c=1.0)
#? int()
nested_kw2(c=1.0, b=1)
#? []
nested_kw2('').
#? []
nested_kw2(a='').
#? []
nested_kw2('', b=1).
# -----------------
# nested *args/**kwargs
# -----------------
def nested_both(*args, **kwargs):
return function_args(*args, **kwargs)
def nested_both2(*args, **kwargs):
return nested_both(*args, **kwargs)
# invalid commands, may return whatever.
#? list
nested_both('', b=1, c=1.0, list)
#? list
nested_both('', c=1.0, b=1, list)
#? []
nested_both('').
#? int()
nested_both2('', b=1, c=1.0)
#? int()
nested_both2('', c=1.0, b=1)
#? []
nested_both2('').
# -----------------
# nested *args/**kwargs with a default arg
# -----------------
def function_def(a, b, c):
return a, b
def nested_def(a, *args, **kwargs):
return function_def(a, *args, **kwargs)
def nested_def2(*args, **kwargs):
return nested_def(*args, **kwargs)
#? str()
nested_def2('', 1, 1.0)[0]
#? str()
nested_def2('', b=1, c=1.0)[0]
#? str()
nested_def2('', c=1.0, b=1)[0]
#? int()
nested_def2('', 1, 1.0)[1]
#? int()
nested_def2('', b=1, c=1.0)[1]
#? int()
nested_def2('', c=1.0, b=1)[1]
#? []
nested_def2('')[1].
# -----------------
# magic methods
# -----------------
def a(): pass
#? ['__closure__']
a.__closure__

View file

@ -0,0 +1,199 @@
# -----------------
# yield statement
# -----------------
def gen():
if random.choice([0, 1]):
yield 1
else:
yield ""
gen_exe = gen()
#? int() str()
next(gen_exe)
#? int() str() list
next(gen_exe, list)
def gen_ret(value):
yield value
#? int()
next(gen_ret(1))
#? []
next(gen_ret()).
# generators evaluate to true if cast by bool.
a = ''
if gen_ret():
a = 3
#? int()
a
# -----------------
# generators should not be indexable
# -----------------
def get(param):
if random.choice([0, 1]):
yield 1
else:
yield ""
#? []
get()[0].
# -----------------
# __iter__
# -----------------
for a in get():
#? int() str()
a
class Get():
def __iter__(self):
if random.choice([0, 1]):
yield 1
else:
yield ""
b = []
for a in Get():
#? int() str()
a
b += [a]
#? list()
b
#? int() str()
b[0]
g = iter(Get())
#? int() str()
next(g)
g = iter([1.0])
#? float()
next(g)
# -----------------
# __next__
# -----------------
class Counter:
def __init__(self, low, high):
self.current = low
self.high = high
def __iter__(self):
return self
def next(self):
""" need to have both __next__ and next, because of py2/3 testing """
return self.__next__()
def __next__(self):
if self.current > self.high:
raise StopIteration
else:
self.current += 1
return self.current - 1
for c in Counter(3, 8):
#? int()
print c
# -----------------
# tuples
# -----------------
def gen():
if random.choice([0,1]):
yield 1, ""
else:
yield 2, 1.0
a, b = next(gen())
#? int()
a
#? str() float()
b
def simple():
if random.choice([0, 1]):
yield 1
else:
yield ""
a, b = simple()
#? int() str()
a
# For now this is ok.
#?
b
def simple2():
yield 1
yield ""
a, b = simple2()
#? int()
a
#? str()
b
# -----------------
# More complicated access
# -----------------
# `close` is a method wrapper.
#? ['__call__']
gen().close.__call__
#?
gen().throw()
#? ['co_consts']
gen().gi_code.co_consts
#? []
gen.gi_code.co_consts
# `send` is also a method wrapper.
#? ['__call__']
gen().send.__call__
#? tuple()
gen().send()
#?
gen()()
# -----------------
# yield from
# -----------------
# python >= 3.3
def yield_from():
yield from iter([1])
#? int()
next(yield_from())
def yield_from_multiple():
yield from iter([1])
yield str()
x, y = yield_from_multiple()
#? int()
x
#? str()
y

View file

@ -0,0 +1,231 @@
# goto_assignments command tests are different in syntax
definition = 3
#! 0 ['a = definition']
a = definition
#! []
b
#! ['a = definition']
a
b = a
c = b
#! ['c = b']
c
cd = 1
#! 1 ['cd = c']
cd = c
#! 0 ['cd = e']
cd = e
#! ['module math']
import math
#! ['import math']
math
#! ['import math']
b = math
#! ['b = math']
b
#! 18 ['foo = 10']
foo = 10;print(foo)
# -----------------
# classes
# -----------------
class C(object):
def b(self):
#! ['b = math']
b
#! ['def b']
self.b
#! 14 ['def b']
self.b()
#! 11 ['self']
self.b
return 1
#! ['def b']
b
#! ['b = math']
b
#! ['def b']
C.b
#! ['def b']
C().b
#! 0 ['class C']
C().b
#! 0 ['class C']
C().b
D = C
#! ['def b']
D.b
#! ['def b']
D().b
#! 0 ['D = C']
D().b
#! 0 ['D = C']
D().b
def c():
return ''
#! ['def c']
c
#! 0 ['def c']
c()
class ClassVar():
x = 3
#! ['x = 3']
ClassVar.x
#! ['x = 3']
ClassVar().x
# before assignments
#! 10 ['x = 3']
ClassVar.x = ''
#! 12 ['x = 3']
ClassVar().x = ''
# Recurring use of the same var name, github #315
def f(t=None):
#! 9 ['t=None']
t = t or 1
class X():
pass
#! 3 []
X(foo=x)
# -----------------
# imports
# -----------------
#! ['module import_tree']
import import_tree
#! ["a = ''"]
import_tree.a
#! ['module mod1']
import import_tree.mod1
#! ['a = 1']
import_tree.mod1.a
#! ['module pkg']
import import_tree.pkg
#! ['a = list']
import_tree.pkg.a
#! ['module mod1']
import import_tree.pkg.mod1
#! ['a = 1.0']
import_tree.pkg.mod1.a
#! ["a = ''"]
import_tree.a
#! ['module mod1']
from import_tree.pkg import mod1
#! ['a = 1.0']
mod1.a
#! ['module mod1']
from import_tree import mod1
#! ['a = 1']
mod1.a
#! ['a = 1.0']
from import_tree.pkg.mod1 import a
#! ['import os']
from .imports import os
#! ['some_variable = 1']
from . import some_variable
# -----------------
# anonymous classes
# -----------------
def func():
class A():
def b(self):
return 1
return A()
#! 8 ['def b']
func().b()
# -----------------
# on itself
# -----------------
#! 7 ['class ClassDef']
class ClassDef():
""" abc """
pass
# -----------------
# params
# -----------------
param = ClassDef
#! 8 ['param']
def ab1(param): pass
#! 9 ['param']
def ab2(param): pass
#! 11 ['param = ClassDef']
def ab3(a=param): pass
ab1(ClassDef);ab2(ClassDef);ab3(ClassDef)
# -----------------
# for loops
# -----------------
for i in range(1):
#! ['for i in range(1): i']
i
for key, value in [(1,2)]:
#! ['for key, value in [(1,2)]: key']
key
for i in []:
#! ['for i in []: i']
i
# -----------------
# decorator
# -----------------
def dec(dec_param=3):
pass
#! 8 ['dec_param=3']
@dec(dec_param=5)
def y():
pass
class ClassDec():
def class_func(func):
return func
#! 14 ['def class_func']
@ClassDec.class_func
def x():
pass
#! 2 ['class ClassDec']
@ClassDec.class_func
def z():
pass

View file

@ -0,0 +1,7 @@
a = ''
from . import invisible_pkg
the_pkg = invisible_pkg
invisible_pkg = 1

View file

@ -0,0 +1,4 @@
if name:
env = 1
else:
env = 2

View file

@ -0,0 +1,7 @@
"""
It should not be possible to import this pkg except for the import_tree itself,
because it is overwritten there. (It would be possible with a sys.path
modification, though).
"""
foo = 1.0

View file

@ -0,0 +1,4 @@
a = 1
from import_tree.random import a as c
foobarbaz = 3.0

View file

@ -0,0 +1 @@
from . import mod1 as fake

View file

@ -0,0 +1,3 @@
a = list
from math import *

View file

@ -0,0 +1 @@
a = 1.0

View file

@ -0,0 +1,4 @@
"""
Here because random is also a builtin module.
"""
a = set

View file

@ -0,0 +1,5 @@
import recurse_class2
class C(recurse_class2.C):
def a(self):
pass

View file

@ -0,0 +1,4 @@
import recurse_class1
class C(recurse_class1.C):
pass

View file

@ -0,0 +1,3 @@
""" used for renaming tests """
abc = 3

View file

@ -0,0 +1,6 @@
""" used for renaming tests """
from rename1 import abc
abc

View file

@ -0,0 +1,285 @@
# -----------------
# own structure
# -----------------
# do separate scopes
def scope_basic():
from import_tree import mod1
#? int()
mod1.a
#? []
import_tree.a
#? []
import_tree.mod1
import import_tree
#? str()
import_tree.a
def scope_pkg():
import import_tree.mod1
#? str()
import_tree.a
#? ['mod1']
import_tree.mod1
#? int()
import_tree.mod1.a
def scope_nested():
import import_tree.pkg.mod1
#? str()
import_tree.a
#? list
import_tree.pkg.a
#? ['sqrt']
import_tree.pkg.sqrt
#? ['pkg']
import_tree.p
#? float()
import_tree.pkg.mod1.a
#? ['a', '__name__', '__package__', '__file__', '__doc__']
a = import_tree.pkg.mod1.
import import_tree.random
#? set
import_tree.random.a
def scope_nested2():
"""Multiple modules should be indexable, if imported"""
import import_tree.mod1
import import_tree.pkg
#? ['mod1']
import_tree.mod1
#? ['pkg']
import_tree.pkg
# With the latest changes this completion also works, because submodules
# are always included (some nested import structures lead to this,
# typically).
#? ['rename1']
import_tree.rename1
def scope_from_import_variable():
"""
All of them shouldn't work, because "fake" imports don't work in python
without the use of ``sys.modules`` modifications (e.g. ``os.path`` see also
github issue #213 for clarification.
"""
a = 3
#?
from import_tree.mod2.fake import a
#?
from import_tree.mod2.fake import c
#?
a
#?
c
def scope_from_import_variable_with_parenthesis():
from import_tree.mod2.fake import (
a, foobarbaz
)
#?
a
#?
foobarbaz
# shouldn't complete, should still list the name though.
#? ['foobarbaz']
foobarbaz
def as_imports():
from import_tree.mod1 import a as xyz
#? int()
xyz
import not_existant, import_tree.mod1 as foo
#? int()
foo.a
import import_tree.mod1 as bar
#? int()
bar.a
def test_import_priorities():
"""
It's possible to overwrite import paths in an ``__init__.py`` file, by
just assigining something there.
See also #536.
"""
from import_tree import the_pkg, invisible_pkg
#? int()
invisible_pkg
# In real Python, this would be the module, but it's not, because Jedi
# doesn't care about most stateful issues such as __dict__, which it would
# need to, to do this in a correct way.
#? int()
the_pkg
# Importing foo is still possible, even though inivisible_pkg got changed.
#? float()
from import_tree.invisible_pkg import foo
# -----------------
# std lib modules
# -----------------
import tokenize
#? ['tok_name']
tokenize.tok_name
from pyclbr import *
#? ['readmodule_ex']
readmodule_ex
import os
#? ['dirname']
os.path.dirname
from os.path import (
expanduser
)
#? os.path.expanduser
expanduser
from itertools import (tee,
islice)
#? ['islice']
islice
from functools import (partial, wraps)
#? ['wraps']
wraps
from keyword import kwlist, \
iskeyword
#? ['kwlist']
kwlist
#? []
from keyword import not_existing1, not_existing2
from tokenize import io
tokenize.generate_tokens
# -----------------
# builtins
# -----------------
import sys
#? ['prefix']
sys.prefix
#? ['append']
sys.path.append
from math import *
#? ['cos', 'cosh']
cos
def func_with_import():
import time
return time
#? ['sleep']
func_with_import().sleep
# -----------------
# relative imports
# -----------------
from .import_tree import mod1
#? int()
mod1.a
from ..import_tree import mod1
#?
mod1.a
from .......import_tree import mod1
#?
mod1.a
from .. import helpers
#? int()
helpers.sample_int
from ..helpers import sample_int as f
#? int()
f
from . import run
#? []
run.
from . import import_tree as imp_tree
#? str()
imp_tree.a
from . import datetime as mod1
#? []
mod1.
# self import
# this can cause recursions
from imports import *
# -----------------
# packages
# -----------------
from import_tree.mod1 import c
#? set
c
from import_tree import recurse_class1
#? ['a']
recurse_class1.C.a
# github #239 RecursionError
#? ['a']
recurse_class1.C().a
# -----------------
# Jedi debugging
# -----------------
# memoizing issues (check git history for the fix)
import not_existing_import
if not_existing_import:
a = not_existing_import
else:
a = not_existing_import
#?
a
# -----------------
# module underscore descriptors
# -----------------
def underscore():
import keyword
#? ['__file__']
keyword.__file__
#? str()
keyword.__file__
# Does that also work for the our own module?
#? ['__file__']
__file__

View file

@ -0,0 +1,214 @@
"""
This file is less about the results and much more about the fact, that no
exception should be thrown.
Basically this file could change depending on the current implementation. But
there should never be any errors.
"""
# wait until keywords are out of definitions (pydoc function).
##? 5
's'()
#? []
str()).upper
# -----------------
# funcs
# -----------------
def asdf(a or b): # multiple param names
return a
#?
asdf(2)
asdf = ''
from a import (b
def blub():
return 0
def wrong_indents():
asdf = 3
asdf
asdf(
# TODO this seems to be wrong now?
##? int()
asdf
def openbrace():
asdf = 3
asdf(
#? int()
asdf
return 1
#? int()
openbrace()
blub([
#? int()
openbrace()
def indentfault():
asd(
indentback
#? []
indentfault().
def openbrace2():
asd(
def normalfunc():
return 1
#? int()
normalfunc()
# dots in param
def f(seq1...=None):
return seq1
#?
f(1)
@
def test_empty_decorator():
return 1
#? int()
test_empty_decorator()
def invalid_param(param=):
#?
param
# -----------------
# flows
# -----------------
# first part not complete (raised errors)
if a
a
else:
#? ['AttributeError']
AttributeError
try
#? ['AttributeError']
except AttributeError
pass
finally:
pass
#? ['isinstance']
if isi
try:
except TypeError:
#? str()
str()
def break(): pass
# wrong ternary expression
a = ''
a = 1 if
#? str()
a
# No completions for for loops without the right syntax
for for_local in :
for_local
#? []
for_local
#?
for_local
# -----------------
# list comprehensions
# -----------------
a2 = [for a2 in [0]]
#?
a2[0]
a3 = [for xyz in]
#?
a3[0]
a3 = [a4 for in 'b']
#?
a3[0]
a3 = [a4 for a in for x in y]
#?
a3[0]
a = [for a in
def break(): pass
#?
a[0]
a = [a for a in [1,2]
def break(): pass
#?
a[0]
#? []
int()).real
# -----------------
# keywords
# -----------------
#! []
as
def empty_assert():
x = 3
assert
#? int()
x
import datetime as
# -----------------
# statements
# -----------------
call = ''
invalid = .call
#?
invalid
invalid = call?.call
#? str()
invalid
# comma
invalid = ,call
#? str()
invalid
# -----------------
# classes
# -----------------
class BrokenPartsOfClass():
def foo(self):
# This construct contains two places where Jedi with Python 3 can fail.
# It should just ignore those constructs and still execute `bar`.
pass
if 2:
try:
pass
except ValueError, e:
raise TypeError, e
else:
pass
def bar(self):
self.x = 3
return ''
#? str()
BrokenPartsOfClass().bar()

View file

@ -0,0 +1,100 @@
if isinstance(i, str):
#? str()
i
if isinstance(j, (str, int)):
#? str() int()
j
while isinstance(k, (str, int)):
#? str() int()
k
if not isinstance(k, (str, int)):
#?
k
while not isinstance(k, (str, int)):
#?
k
assert isinstance(ass, int)
#? int()
ass
assert isinstance(ass, str)
assert not isinstance(ass, int)
if 2:
#? str()
ass
# -----------------
# invalid arguments
# -----------------
if isinstance(wrong, str()):
#?
wrong
# -----------------
# in functions
# -----------------
import datetime
def fooooo(obj):
if isinstance(obj, datetime.datetime):
#? datetime.datetime()
obj
def fooooo2(obj):
if isinstance(obj, datetime.date):
return obj
else:
return 1
a
# In earlier versions of Jedi, this returned both datetime and int, but now
# Jedi does flow checks and realizes that the top return isn't executed.
#? int()
fooooo2('')
def isinstance_func(arr):
for value in arr:
if isinstance(value, dict):
# Shouldn't fail, even with the dot.
#? 17 dict()
value.
elif isinstance(value, int):
x = value
#? int()
x
# -----------------
# Names with multiple indices.
# -----------------
class Test():
def __init__(self, testing):
if isinstance(testing, str):
self.testing = testing
else:
self.testing = 10
def boo(self):
if isinstance(self.testing, str):
#? str()
self.testing
#? Test()
self
# -----------------
# Syntax
# -----------------
#?
isinstance(1, int())

View file

@ -0,0 +1,59 @@
#? ['raise']
raise
#? ['Exception']
except
#? []
b + continu
#? []
b + continue
#? ['continue']
b; continue
#? ['continue']
b; continu
#? []
c + brea
#? []
a + break
#? ['break']
b; break
# -----------------
# Keywords should not appear everywhere.
# -----------------
#? []
with open() as f
#? []
def i
#? []
class i
#? []
continue i
# More syntax details, e.g. while only after newline, but not after semicolon,
# continue also after semicolon
#? ['while']
while
#? []
x while
#? []
x; while
#? ['continue']
x; continue
#? []
and
#? ['and']
x and
#? []
x * and

View file

@ -0,0 +1,106 @@
# -----------------
# lambdas
# -----------------
a = lambda: 3
#? int()
a()
x = []
a = lambda x: x
#? int()
a(0)
#? float()
(lambda x: x)(3.0)
arg_l = lambda x, y: y, x
#? float()
arg_l[0]('', 1.0)
#? list()
arg_l[1]
arg_l = lambda x, y: (y, x)
args = 1,""
result = arg_l(*args)
#? tuple()
result
#? str()
result[0]
#? int()
result[1]
def with_lambda(callable_lambda, *args, **kwargs):
return callable_lambda(1, *args, **kwargs)
#? int()
with_lambda(arg_l, 1.0)[1]
#? float()
with_lambda(arg_l, 1.0)[0]
#? float()
with_lambda(arg_l, y=1.0)[0]
#? int()
with_lambda(lambda x: x)
#? float()
with_lambda(lambda x, y: y, y=1.0)
arg_func = lambda *args, **kwargs: (args[0], kwargs['a'])
#? int()
arg_func(1, 2, a='', b=10)[0]
#? list()
arg_func(1, 2, a=[], b=10)[1]
# magic method
a = lambda: 3
#? ['__closure__']
a.__closure__
class C():
def __init__(self, foo=1.0):
self.a = lambda: 1
self.foo = foo
def ret(self):
return lambda: self.foo
def with_param(self):
return lambda x: x + self.a()
#? int()
C().a()
#? str()
C('foo').ret()()
index = C().with_param()(1)
#? float()
['', 1, 1.0][index]
def xy(param):
def ret(a, b):
return a + b
return lambda b: ret(param, b)
#? int()
xy(1)(2)
# -----------------
# lambda param (#379)
# -----------------
class Test(object):
def __init__(self, pred=lambda a, b: a):
self.a = 1
#? int()
self.a
#? float()
pred(1.0, 2)
# -----------------
# test_nocond in grammar (happens in list comprehensions with `if`)
# -----------------
# Doesn't need to do anything yet. It should just not raise an error. These
# nocond lambdas make no sense at all.
#? int()
[a for a in [1,2] if lambda: 3][0]

View file

@ -0,0 +1,48 @@
"""
Named Params:
>>> def a(abc): pass
...
>>> a(abc=3) # <- this stuff (abc)
"""
def a(abc):
pass
#? 5 ['abc']
a(abc)
def a(*some_args, **some_kwargs):
pass
#? 11 []
a(some_args)
#? 13 []
a(some_kwargs)
def multiple(foo, bar):
pass
#? 17 ['bar']
multiple(foo, bar)
#? ['bar']
multiple(foo, bar
my_lambda = lambda lambda_param: lambda_param + 1
#? 22 ['lambda_param']
my_lambda(lambda_param)
# __call__
class Test(object):
def __init__(self, hello_other):
pass
def __call__(self, hello):
pass
#? 12 ['hello']
Test()(hello=)
#? 11 []
Test()(self=)

View file

@ -0,0 +1,108 @@
def from_names():
#? ['mod1']
from import_tree.pkg.
#? ['path']
from os.
def from_names_goto():
from import_tree import pkg
#? pkg
from import_tree.pkg
def builtin_test():
#? ['math']
import math
# -----------------
# completions within imports
# -----------------
#? ['sqlite3']
import sqlite3
#? ['classes']
import classes
#? ['timedelta']
from datetime import timedel
#? 21 []
from datetime.timedel import timedel
# should not be possible, because names can only be looked up 1 level deep.
#? []
from datetime.timedelta import resolution
#? []
from datetime.timedelta import
#? ['Cursor']
from sqlite3 import Cursor
#? ['some_variable']
from . import some_variable
#? ['arrays']
from . import arrays
#? []
from . import import_tree as ren
import os
#? os.path.join
from os.path import join
# -----------------
# special positions -> edge cases
# -----------------
import datetime
#? 6 datetime
from datetime.time import time
#? []
import datetime.
#? []
import datetime.date
#? 21 ['import']
from import_tree.pkg import pkg
#? 49 ['a', '__name__', '__doc__', '__file__', '__package__']
from import_tree.pkg.mod1 import not_existant, # whitespace before
#? ['a', '__name__', '__doc__', '__file__', '__package__']
from import_tree.pkg.mod1 import not_existant,
#? 22 ['mod1']
from import_tree.pkg. import mod1
#? 17 ['mod1', 'mod2', 'random', 'pkg', 'rename1', 'rename2', 'recurse_class1', 'recurse_class2', 'invisible_pkg', 'flow_import']
from import_tree. import pkg
#? 18 ['pkg']
from import_tree.p import pkg
#? 17 ['import_tree']
from .import_tree import
#? 10 ['run']
from ..run import
#? ['run']
from ..run
#? 10 ['run']
from ..run.
#? []
from ..run.
#? ['run']
from .. import run
#? []
from not_a_module import
#137
import json
#? 23 json.dump
from json import load, dump
#? 17 json.load
from json import load, dump
# without the from clause:
import json, datetime
#? 7 json
import json, datetime
#? 13 datetime
import json, datetime

View file

@ -0,0 +1,195 @@
# -----------------
# normal
# -----------------
a = ""
a = 1
#? int()
a
#? []
a.append
a = list
b = 1; b = ""
#? str()
b
# temp should not be accessible before definition
#? []
temp
a = 1
temp = b;
b = a
a = temp
#? int()
b
#? int()
b
#? str()
a
a = tuple
if 1:
a = list
#? ['append']
a.append
#? ['index']
a.index
# -----------------
# tuples exchanges
# -----------------
a, b = 1, ""
#? int()
a
#? str()
b
b, a = a, b
#? int()
b
#? str()
a
b, a = a, b
#? int()
a
#? str()
b
# -----------------
# function
# -----------------
def a(a=3):
#? int()
a
#? []
a.func
return a
#? int()
a(2)
#? []
a(2).func
a_param = 3
def func(a_param):
# should not be int
#? []
a_param.
from os import path
# should not return a function, because `a` is a function above
def f(b, a): return a
#? []
f(b=3).
# -----------------
# closure
# -----------------
def x():
a = 0
def x():
return a
a = 3.0
return x()
#? float()
x()
# -----------------
# class
# -----------------
class A(object):
a = ""
a = 3
#? int()
a
a = list()
def __init__(self):
self.b = ""
def before(self):
self.b = 3
# TODO should this be so? include entries after cursor?
#? int() str() list
self.b
self.b = list
self.a = 1
#? str() int()
self.a
#? ['after']
self.after
self.c = 3
#? int()
self.c
def after(self):
self.a = ''
c = set()
#? list()
A.a
a = A()
#? ['after']
a.after
#? []
a.upper
#? []
a.append
#? []
a.real
#? str() int()
a.a
a = 3
class a():
def __init__(self, a):
self.a = a
#? float()
a(1.0).a
#?
a().a
# -----------------
# imports
# -----------------
math = 3
import math
#? ['cosh']
math.cosh
#? []
math.real
math = 3
#? int()
math
#? []
math.cos
# do the same for star imports
cosh = 3
from math import *
# cosh doesn't work, but that's not a problem, star imports should be at the
# start of EVERY script!
cosh.real
cosh = 3
#? int()
cosh

View file

@ -0,0 +1,43 @@
"""
Issues with the parser and not the type inference should be part of this file.
"""
class IndentIssues():
"""
issue jedi-vim#288
Which is really a fast parser issue. It used to start a new block at the
parentheses, because it had problems with the indentation.
"""
def one_param(
self,
):
return 1
def with_param(
self,
y):
return y
#? int()
IndentIssues().one_param()
#? str()
IndentIssues().with_param('')
"""
Just because there's a def keyword, doesn't mean it should not be able to
complete to definition.
"""
definition = 0
#? ['definition']
str(def
# It might be hard to determine the context
class Foo(object):
@property
#? ['str']
def bar(str

View file

@ -0,0 +1,160 @@
""" Pep-0484 type hinting """
# python >= 3.2
class A():
pass
def function_parameters(a: A, b, c: str, d: int, e: str, f: str, g: int=4):
"""
:param e: if docstring and annotation agree, only one should be returned
:type e: str
:param f: if docstring and annotation disagree, both should be returned
:type f: int
"""
#? A()
a
#?
b
#? str()
c
#? int()
d
#? str()
e
#? int() str()
f
# int()
g
def return_unspecified():
pass
#?
return_unspecified()
def return_none() -> None:
"""
Return type None means the same as no return type as far as jedi
is concerned
"""
pass
#?
return_none()
def return_str() -> str:
pass
#? str()
return_str()
def return_custom_class() -> A:
pass
#? A()
return_custom_class()
def return_annotation_and_docstring() -> str:
"""
:rtype: int
"""
pass
#? str() int()
return_annotation_and_docstring()
def return_annotation_and_docstring_different() -> str:
"""
:rtype: str
"""
pass
#? str()
return_annotation_and_docstring_different()
def annotation_forward_reference(b: "B") -> "B":
#? B()
b
#? ["test_element"]
annotation_forward_reference(1).t
class B:
test_element = 1
pass
#? B()
annotation_forward_reference(1)
class SelfReference:
test_element = 1
def test_method(self, x: "SelfReference") -> "SelfReference":
#? SelfReference()
x
#? ["test_element", "test_method"]
self.t
#? ["test_element", "test_method"]
x.t
#? ["test_element", "test_method"]
self.test_method(1).t
#? SelfReference()
SelfReference().test_method()
def function_with_non_pep_0484_annotation(
x: "I can put anything here",
xx: "",
yy: "\r\n\0;+*&^564835(---^&*34",
y: 3 + 3,
zz: float) -> int("42"):
# infers int from function call
#? int()
x
# infers int from function call
#? int()
xx
# infers int from function call
#? int()
yy
# infers str from function call
#? str()
y
#? float()
zz
#?
function_with_non_pep_0484_annotation(1, 2, 3, "force string")
def function_forward_reference_dynamic(
x: return_str_type(),
y: "return_str_type()") -> None:
#?
x
#? str()
y
def return_str_type():
return str
X = str
def function_with_assined_class_in_reference(x: X, y: "Y"):
#? str()
x
#? int()
y
Y = int
def just_because_we_can(x: "flo" + "at"):
#? float()
x

View file

@ -0,0 +1,109 @@
a = 3 # type: str
#? str()
a
b = 3 # type: str but I write more
#? int()
b
c = 3 # type: str # I comment more
#? str()
c
d = "It should not read comments from the next line"
# type: int
#? str()
d
# type: int
e = "It should not read comments from the previous line"
#? str()
e
class BB: pass
def test(a, b):
a = a # type: BB
c = a # type: str
d = a
# type: str
e = a # type: str # Should ignore long whitespace
#? BB()
a
#? str()
c
#? BB()
d
#? str()
e
a,b = 1, 2 # type: str, float
#? str()
a
#? float()
b
class Employee:
pass
# The typing library is not installable for Python 2.6, therefore ignore the
# following tests.
# python >= 2.7
from typing import List
x = [] # type: List[Employee]
#? Employee()
x[1]
x, y, z = [], [], [] # type: List[int], List[int], List[str]
#? int()
y[2]
x, y, z = [], [], [] # type: (List[float], List[float], List[BB])
for zi in z:
#? BB()
zi
x = [
1,
2,
] # type: List[str]
#? str()
x[1]
for bar in foo(): # type: str
#? str()
bar
for bar, baz in foo(): # type: int, float
#? int()
bar
#? float()
baz
for bar, baz in foo():
# type: str, str
""" type hinting on next line should not work """
#?
bar
#?
baz
with foo(): # type: int
...
with foo() as f: # type: str
#? str()
f
with foo() as f:
# type: str
""" type hinting on next line should not work """
#?
f
aaa = some_extremely_long_function_name_that_doesnt_leave_room_for_hints() \
# type: float # We should be able to put hints on the next line with a \
#? float()
aaa

View file

@ -0,0 +1,263 @@
"""
Test the typing library, with docstrings. This is needed since annotations
are not supported in python 2.7 else then annotating by comment (and this is
still TODO at 2016-01-23)
"""
# There's no Python 2.6 typing module.
# python >= 2.7
import typing
class B:
pass
def we_can_has_sequence(p, q, r, s, t, u):
"""
:type p: typing.Sequence[int]
:type q: typing.Sequence[B]
:type r: typing.Sequence[int]
:type s: typing.Sequence["int"]
:type t: typing.MutableSequence[dict]
:type u: typing.List[float]
"""
#? ["count"]
p.c
#? int()
p[1]
#? ["count"]
q.c
#? B()
q[1]
#? ["count"]
r.c
#? int()
r[1]
#? ["count"]
s.c
#? int()
s[1]
#? []
s.a
#? ["append"]
t.a
#? dict()
t[1]
#? ["append"]
u.a
#? float()
u[1]
def iterators(ps, qs, rs, ts):
"""
:type ps: typing.Iterable[int]
:type qs: typing.Iterator[str]
:type rs: typing.Sequence["ForwardReference"]
:type ts: typing.AbstractSet["float"]
"""
for p in ps:
#? int()
p
#?
next(ps)
a, b = ps
#? int()
a
##? int() --- TODO fix support for tuple assignment
# https://github.com/davidhalter/jedi/pull/663#issuecomment-172317854
# test below is just to make sure that in case it gets fixed by accident
# these tests will be fixed as well the way they should be
#?
b
for q in qs:
#? str()
q
#? str()
next(qs)
for r in rs:
#? ForwardReference()
r
#?
next(rs)
for t in ts:
#? float()
t
def sets(p, q):
"""
:type p: typing.AbstractSet[int]
:type q: typing.MutableSet[float]
"""
#? []
p.a
#? ["add"]
q.a
def tuple(p, q, r):
"""
:type p: typing.Tuple[int]
:type q: typing.Tuple[int, str, float]
:type r: typing.Tuple[B, ...]
"""
#? int()
p[0]
#? int()
q[0]
#? str()
q[1]
#? float()
q[2]
#? B()
r[0]
#? B()
r[1]
#? B()
r[2]
#? B()
r[10000]
i, s, f = q
#? int()
i
##? str() --- TODO fix support for tuple assignment
# https://github.com/davidhalter/jedi/pull/663#issuecomment-172317854
#?
s
##? float() --- TODO fix support for tuple assignment
# https://github.com/davidhalter/jedi/pull/663#issuecomment-172317854
#?
f
class Key:
pass
class Value:
pass
def mapping(p, q, d, r, s, t):
"""
:type p: typing.Mapping[Key, Value]
:type q: typing.MutableMapping[Key, Value]
:type d: typing.Dict[Key, Value]
:type r: typing.KeysView[Key]
:type s: typing.ValuesView[Value]
:type t: typing.ItemsView[Key, Value]
"""
#? []
p.setd
#? ["setdefault"]
q.setd
#? ["setdefault"]
d.setd
#? Value()
p[1]
for key in p:
#? Key()
key
for key in p.keys():
#? Key()
key
for value in p.values():
#? Value()
value
for item in p.items():
#? Key()
item[0]
#? Value()
item[1]
(key, value) = item
#? Key()
key
#? Value()
value
for key, value in p.items():
#? Key()
key
#? Value()
value
for key in r:
#? Key()
key
for value in s:
#? Value()
value
for key, value in t:
#? Key()
key
#? Value()
value
def union(p, q, r, s, t):
"""
:type p: typing.Union[int]
:type q: typing.Union[int, int]
:type r: typing.Union[int, str, "int"]
:type s: typing.Union[int, typing.Union[str, "typing.Union['float', 'dict']"]]
:type t: typing.Union[int, None]
"""
#? int()
p
#? int()
q
#? int() str()
r
#? int() str() float() dict()
s
#? int()
t
def optional(p):
"""
:type p: typing.Optional[int]
Optional does not do anything special. However it should be recognised
as being of that type. Jedi doesn't do anything with the extra into that
it can be None as well
"""
#? int()
p
class ForwardReference:
pass
class TestDict(typing.Dict[str, int]):
def setdud(self):
pass
def testdict(x):
"""
:type x: TestDict
"""
#? ["setdud", "setdefault"]
x.setd
for key in x.keys():
#? str()
key
for value in x.values():
#? int()
value
x = TestDict()
#? ["setdud", "setdefault"]
x.setd
for key in x.keys():
#? str()
key
for value in x.values():
#? int()
value
# python >= 3.2
"""
docstrings have some auto-import, annotations can use all of Python's
import logic
"""
import typing as t
def union2(x: t.Union[int, str]):
#? int() str()
x
from typing import Union
def union3(x: Union[int, str]):
#? int() str()
x
from typing import Union as U
def union4(x: U[int, str]):
#? int() str()
x

View file

@ -0,0 +1,138 @@
"""
Test Jedi's operation understanding. Jedi should understand simple additions,
multiplications, etc.
"""
# -----------------
# numbers
# -----------------
x = [1, 'a', 1.0]
#? int() str() float()
x[12]
#? float()
x[1 + 1]
index = 0 + 1
#? str()
x[index]
#? int()
x[1 + (-1)]
def calculate(number):
return number + constant
constant = 1
#? float()
x[calculate(1)]
def calculate(number):
return number + constant
# -----------------
# strings
# -----------------
x = 'upp' + 'e'
#? str.upper
getattr(str, x + 'r')
a = "a"*3
#? str()
a
a = 3 * "a"
#? str()
a
a = 3 * "a"
#? str()
a
#? int()
(3 ** 3)
#? int() str()
(3 ** 'a')
# -----------------
# assignments
# -----------------
x = [1, 'a', 1.0]
i = 0
i += 1
i += 1
#? float()
x[i]
i = 1
i += 1
i -= 3
i += 1
#? int()
x[i]
# -----------------
# in
# -----------------
if 'X' in 'Y':
a = 3
else:
a = ''
# For now don't really check for truth values. So in should return both
# results.
#? str() int()
a
# -----------------
# for flow assignments
# -----------------
class FooBar(object):
fuu = 0.1
raboof = 'fourtytwo'
# targets should be working
target = ''
for char in ['f', 'u', 'u']:
target += char
#? float()
getattr(FooBar, target)
# github #24
target = u''
for char in reversed(['f', 'o', 'o', 'b', 'a', 'r']):
target += char
#? str()
getattr(FooBar, target)
# -----------------
# repetition problems -> could be very slow and memory expensive - shouldn't
# be.
# -----------------
b = [str(1)]
l = list
for x in [l(0), l(1), l(2), l(3), l(4), l(5), l(6), l(7), l(8), l(9), l(10),
l(11), l(12), l(13), l(14), l(15), l(16), l(17), l(18), l(19), l(20),
l(21), l(22), l(23), l(24), l(25), l(26), l(27), l(28), l(29)]:
b += x
#? str()
b[1]
# -----------------
# undefined names
# -----------------
a = foobarbaz + 'hello'
#? int() float()
{'hello': 1, 'bar': 1.0}[a]

View file

@ -0,0 +1,51 @@
"""
Code that might cause recursion issues (or has caused in the past).
"""
def Recursion():
def recurse(self):
self.a = self.a
self.b = self.b.recurse()
#?
Recursion().a
#?
Recursion().b
class X():
def __init__(self):
self.recursive = [1, 3]
def annoying(self):
self.recursive = [self.recursive[0]]
def recurse(self):
self.recursive = [self.recursive[1]]
#? int()
X().recursive[0]
def to_list(iterable):
return list(set(iterable))
def recursion1(foo):
return to_list(to_list(foo)) + recursion1(foo)
#? int()
recursion1([1,2])[0]
class FooListComp():
def __init__(self):
self.recursive = [1]
def annoying(self):
self.recursive = [x for x in self.recursive]
#? int()
FooListComp().recursive[0]

View file

@ -0,0 +1,224 @@
"""
std library stuff
"""
# -----------------
# builtins
# -----------------
arr = ['']
#? str()
sorted(arr)[0]
#? str()
next(reversed(arr))
next(reversed(arr))
# should not fail if there's no return value.
def yielder():
yield None
#? None
next(reversed(yielder()))
# empty reversed should not raise an error
#?
next(reversed())
#? str()
next(open(''))
#? int()
{'a':2}.setdefault('a', 3)
# Compiled classes should have the meta class attributes.
#? ['__itemsize__']
tuple.__itemsize__
# -----------------
# type() calls with one parameter
# -----------------
#? int
type(1)
#? int
type(int())
#? type
type(int)
#? type
type(type)
#? list
type([])
def x():
yield 1
generator = type(x())
#? generator
type(x for x in [])
#? type(x)
type(lambda: x)
import math
import os
#? type(os)
type(math)
class X(): pass
#? type
type(X)
# -----------------
# enumerate
# -----------------
for i, j in enumerate(["as", "ad"]):
#? int()
i
#? str()
j
# -----------------
# re
# -----------------
import re
c = re.compile(r'a')
# re.compile should not return str -> issue #68
#? []
c.startswith
#? int()
c.match().start()
#? int()
re.match(r'a', 'a').start()
for a in re.finditer('a', 'a'):
#? int()
a.start()
#? str()
re.sub('a', 'a')
# -----------------
# ref
# -----------------
import weakref
#? int()
weakref.proxy(1)
#? weakref.ref()
weakref.ref(1)
#? int()
weakref.ref(1)()
# -----------------
# functools
# -----------------
import functools
basetwo = functools.partial(int, base=2)
#? int()
basetwo()
def function(a, b):
return a, b
a = functools.partial(function, 0)
#? int()
a('')[0]
#? str()
a('')[1]
kw = functools.partial(function, b=1.0)
tup = kw(1)
#? int()
tup[0]
#? float()
tup[1]
def my_decorator(f):
@functools.wraps(f)
def wrapper(*args, **kwds):
return f(*args, **kwds)
return wrapper
@my_decorator
def example(a):
return a
#? str()
example('')
# -----------------
# sqlite3 (#84)
# -----------------
import sqlite3
#? sqlite3.Connection()
con = sqlite3.connect()
#? sqlite3.Cursor()
c = con.cursor()
#? sqlite3.Row()
row = c.fetchall()[0]
#? str()
row.keys()[0]
def huhu(db):
"""
:type db: sqlite3.Connection
:param db: the db connection
"""
#? sqlite3.Connection()
db
# -----------------
# hashlib
# -----------------
import hashlib
#? ['md5']
hashlib.md5
# -----------------
# copy
# -----------------
import copy
#? int()
copy.deepcopy(1)
#?
copy.copy()
# -----------------
# json
# -----------------
# We don't want any results for json, because it depends on IO.
import json
#?
json.load('asdf')
#?
json.loads('[1]')
# -----------------
# random
# -----------------
import random
class A(object):
def say(self): pass
class B(object):
def shout(self): pass
cls = random.choice([A, B])
#? ['say', 'shout']
cls().s
# -----------------
# random
# -----------------
import zipfile
z = zipfile.ZipFile("foo")
# It's too slow. So we don't run it at the moment.
##? ['upper']
z.read('name').upper

View file

@ -0,0 +1,25 @@
import sys
import os
from os import dirname
sys.path.insert(0, '../../jedi')
sys.path.append(dirname(os.path.abspath('thirdparty' + os.path.sep + 'asdf')))
# modifications, that should fail:
# because of sys module
sys.path.append(sys.path[1] + '/thirdparty')
# syntax err
sys.path.append('a' +* '/thirdparty')
#? ['evaluate']
import evaluate
#? ['Evaluator']
evaluate.Evaluator
#? ['jedi_']
import jedi_
#? ['el']
jedi_.el

View file

@ -0,0 +1,19 @@
from PyQt4.QtCore import *
from PyQt4.QtGui import *
#? ['QActionGroup']
QActionGroup
#? ['currentText']
QStyleOptionComboBox().currentText
#? []
QStyleOptionComboBox().currentText.
from PyQt4 import QtGui
#? ['currentText']
QtGui.QStyleOptionComboBox().currentText
#? []
QtGui.QStyleOptionComboBox().currentText.

View file

@ -0,0 +1,11 @@
#! ['class ObjectDoesNotExist']
from django.core.exceptions import ObjectDoesNotExist
import django
#? ['get_version']
django.get_version
from django.conf import settings
#? ['configured']
settings.configured

View file

@ -0,0 +1,52 @@
from jedi import functions, evaluate, parsing
el = functions.completions()[0]
#? ['description']
el.description
#? str()
el.description
scopes, path, dot, like = \
api._prepare_goto(source, row, column, path, True)
# has problems with that (sometimes) very deep nesting.
#? set()
el = scopes
# get_names_for_scope is also recursion stuff
#? tuple()
el = list(evaluate.get_names_for_scope())[0]
#? int() parsing.Module()
el = list(evaluate.get_names_for_scope(1))[0][0]
#? parsing.Module()
el = list(evaluate.get_names_for_scope())[0][0]
#? list()
el = list(evaluate.get_names_for_scope(1))[0][1]
#? list()
el = list(evaluate.get_names_for_scope())[0][1]
#? list()
parsing.Scope((0,0)).get_set_vars()
#? parsing.Import() parsing.Name()
parsing.Scope((0,0)).get_set_vars()[0]
# TODO access parent is not possible, because that is not set in the class
## parsing.Class()
parsing.Scope((0,0)).get_set_vars()[0].parent
#? parsing.Import() parsing.Name()
el = list(evaluate.get_names_for_scope())[0][1][0]
#? evaluate.Array() evaluate.Class() evaluate.Function() evaluate.Instance()
list(evaluate.follow_call())[0]
# With the right recursion settings, this should be possible (and maybe more):
# Array Class Function Generator Instance Module
# However, this was produced with the recursion settings 10/350/10000, and
# lasted 18.5 seconds. So we just have to be content with the results.
#? evaluate.Class() evaluate.Function()
evaluate.get_scopes_for_name()[0]

View file

@ -0,0 +1,11 @@
import psycopg2
conn = psycopg2.connect('dbname=test')
#? ['cursor']
conn.cursor
cur = conn.cursor()
#? ['fetchall']
cur.fetchall

View file

@ -0,0 +1,36 @@
import pylab
# two gotos
#! ['module numpy']
import numpy
#! ['module random']
import numpy.random
#? ['array2string']
numpy.array2string
#? ['shape']
numpy.matrix().shape
#? ['random_integers']
pylab.random_integers
#? []
numpy.random_integers
#? ['random_integers']
numpy.random.random_integers
#? ['sample']
numpy.random.sample
import numpy
na = numpy.array([1,2])
#? ['shape']
na.shape
# shouldn't raise an error #29, jedi-vim
# doesn't return something, because matplotlib uses __import__
fig = pylab.figure()
#?
fig.add_subplot

View file

@ -0,0 +1,127 @@
# -----------------
# non array
# -----------------
#? ['imag']
int.imag
#? []
int.is_integer
#? ['is_integer']
float.is_int
#? ['is_integer']
1.0.is_integer
#? ['upper']
"".upper
#? ['upper']
r"".upper
# strangely this didn't work, because the = is used for assignments
#? ['upper']
"=".upper
a = "="
#? ['upper']
a.upper
# -----------------
# lists
# -----------------
arr = []
#? ['append']
arr.app
#? ['append']
list().app
#? ['append']
[].append
arr2 = [1,2,3]
#? ['append']
arr2.app
#? int()
arr.count(1)
x = []
#?
x.pop()
x = [3]
#? int()
x.pop()
x = []
x.append(1.0)
#? float()
x.pop()
# -----------------
# dicts
# -----------------
dic = {}
#? ['copy', 'clear']
dic.c
dic2 = dict(a=1, b=2)
#? ['pop', 'popitem']
dic2.p
#? ['popitem']
{}.popitem
dic2 = {'asdf': 3}
#? ['popitem']
dic2.popitem
#? int()
dic2['asdf']
d = {'a': 3, 1.0: list}
#? int() list
d.values()[0]
##? int() list
dict(d).values()[0]
#? str()
d.items()[0][0]
#? int()
d.items()[0][1]
# -----------------
# set
# -----------------
set_t = {1,2}
#? ['clear', 'copy']
set_t.c
set_t2 = set()
#? ['clear', 'copy']
set_t2.c
# -----------------
# tuples
# -----------------
tup = ('',2)
#? ['count']
tup.c
tup2 = tuple()
#? ['index']
tup2.i
#? ['index']
().i
tup3 = 1,""
#? ['index']
tup3.index
tup4 = 1,""
#? ['index']
tup4.index

View file

@ -0,0 +1,275 @@
"""
Renaming tests. This means search for usages.
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
#< 0 (-3,4), (0,0), (2,0), (14,0), (9,4), (11,5), (12,0)
abc.d.a.bsaasd.abc.d
abc
# unicode chars shouldn't be a problem.
x['smörbröd'].abc
# With the new parser these statements are not recognized as stateents, because
# they are not valid Python.
if 1:
abc =
else:
(abc) =
abc =
#< (-17,4), (-14,0), (-12,0), (0,0), (-2,0), (-3,5), (-5,4)
abc
abc = 5
Abc = 3
#< 6 (0,6), (2,4), (5,8), (17,0)
class Abc():
#< (-2,6), (0,4), (3,8), (15,0)
Abc
def Abc(self):
Abc; self.c = 3
#< 17 (0,16), (2,8)
def a(self, Abc):
#< 10 (-2,16), (0,8)
Abc
#< 19 (0,18), (2,8)
def self_test(self):
#< 12 (-2,18), (0,8)
self.b
Abc.d.Abc
#< 4 (0,4), (5,1)
def blubi():
pass
#< (-5,4), (0,1)
@blubi
def a(): pass
#< 0 (0,0), (1,0)
set_object_var = object()
set_object_var.var = 1
response = 5
#< 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)
response
# -----------------
# imports
# -----------------
#< (0,7), (3,0)
import module_not_exists
#< (-3,7), (0,0)
module_not_exists
#< ('rename1', 1,0), (0,24), (3,0), (6,17), ('rename2', 4,5), (10,17), (13,17), ('imports', 72, 16)
from import_tree import rename1
#< (0,8), ('rename1',3,0), ('rename2',4,20), ('rename2',6,0), (3,32), (7,32), (4,0)
rename1.abc
#< (-3,8), ('rename1', 3,0), ('rename2', 4,20), ('rename2', 6,0), (0,32), (4,32), (1,0)
from import_tree.rename1 import abc
abc
#< 20 ('rename1', 1,0), ('rename2', 4,5), (-10,24), (-7,0), (-4,17), (0,17), (3,17), ('imports', 72, 16)
from import_tree.rename1 import abc
#< (0, 32),
from import_tree.rename1 import not_existing
# Shouldn't raise an error or do anything weird.
from not_existing import *
# -----------------
# classes
# -----------------
class TestMethods(object):
#< 8 (0,8), (2,13)
def a_method(self):
#< 13 (-2,8), (0,13)
self.a_method()
#< 13 (2,8), (0,13), (3,13)
self.b_method()
def b_method(self):
self.b_method
class TestClassVar(object):
#< 4 (0,4), (5,13), (7,21)
class_v = 1
def a(self):
class_v = 1
#< (-5,4), (0,13), (2,21)
self.class_v
#< (-7,4), (-2,13), (0,21)
TestClassVar.class_v
#< (0,8), (-7, 8)
class_v
class TestInstanceVar():
def a(self):
#< 13 (4,13), (0,13)
self._instance_var = 3
def b(self):
#< (-4,13), (0,13)
self._instance_var
# A call to self used to trigger an error, because it's also a trailer
# with two children.
self()
class NestedClass():
def __getattr__(self, name):
return self
# Shouldn't find a definition, because there's other `instance`.
# TODO reenable that test
##< (0, 14),
NestedClass().instance
# -----------------
# inheritance
# -----------------
class Super(object):
#< 4 (0,4), (23,18), (25,13)
base_class = 1
#< 4 (0,4),
class_var = 1
#< 8 (0,8),
def base_method(self):
#< 13 (0,13), (20,13)
self.base_var = 1
#< 13 (0,13),
self.instance_var = 1
#< 8 (0,8),
def just_a_method(self): pass
#< 20 (0,16), (-18,6)
class TestClass(Super):
#< 4 (0,4),
class_var = 1
def x_method(self):
#< (0,18), (2,13), (-23,4)
TestClass.base_class
#< (-2,18), (0,13), (-25,4)
self.base_class
#< (-20,13), (0,13)
self.base_var
#<
TestClass.base_var
#< 13 (5,13), (0,13)
self.instance_var = 3
#< 9 (0,8),
def just_a_method(self):
#< (-5,13), (0,13)
self.instance_var
# -----------------
# properties
# -----------------
class TestProperty:
@property
#< 10 (0,8), (5,13)
def prop(self):
return 1
def a(self):
#< 13 (-5,8), (0,13)
self.prop
@property
#< 13 (0,8), (4,5)
def rw_prop(self):
return self._rw_prop
#< 8 (-4,8), (0,5)
@rw_prop.setter
#< 8 (0,8), (5,13)
def rw_prop(self, value):
self._rw_prop = value
def b(self):
#< 13 (-5,8), (0,13)
self.rw_prop
# -----------------
# *args, **kwargs
# -----------------
#< 11 (1,11), (0,8)
def f(**kwargs):
return kwargs
# -----------------
# No result
# -----------------
if isinstance(j, int):
#<
j
# -----------------
# Dynamic Param Search
# -----------------
class DynamicParam():
def foo(self):
return
def check(instance):
#< 13 (-5,8), (0,13)
instance.foo()
check(DynamicParam())
# -----------------
# Compiled Objects
# -----------------
import _sre
#< 0 (-3,7), (0,0), ('_sre', None, None)
_sre
# -----------------
# on syntax
# -----------------
#< 0
import undefined

View file

@ -0,0 +1,130 @@
import os
import re
import pytest
from . import helpers
from . import run
from . import refactor
import jedi
from jedi.evaluate.analysis import Warning
from jedi import settings
def pytest_addoption(parser):
parser.addoption(
"--integration-case-dir",
default=os.path.join(helpers.test_dir, 'completion'),
help="Directory in which integration test case files locate.")
parser.addoption(
"--refactor-case-dir",
default=os.path.join(helpers.test_dir, 'refactor'),
help="Directory in which refactoring test case files locate.")
parser.addoption(
"--test-files", "-T", default=[], action='append',
help=(
"Specify test files using FILE_NAME[:LINE[,LINE[,...]]]. "
"For example: -T generators.py:10,13,19. "
"Note that you can use -m to specify the test case by id."))
parser.addoption(
"--thirdparty", action='store_true',
help="Include integration tests that requires third party modules.")
def parse_test_files_option(opt):
"""
Parse option passed to --test-files into a key-value pair.
>>> parse_test_files_option('generators.py:10,13,19')
('generators.py', [10, 13, 19])
"""
opt = str(opt)
if ':' in opt:
(f_name, rest) = opt.split(':', 1)
return (f_name, list(map(int, rest.split(','))))
else:
return (opt, [])
def pytest_generate_tests(metafunc):
"""
:type metafunc: _pytest.python.Metafunc
"""
test_files = dict(map(parse_test_files_option,
metafunc.config.option.test_files))
if 'case' in metafunc.fixturenames:
base_dir = metafunc.config.option.integration_case_dir
thirdparty = metafunc.config.option.thirdparty
cases = list(run.collect_dir_tests(base_dir, test_files))
if thirdparty:
cases.extend(run.collect_dir_tests(
os.path.join(base_dir, 'thirdparty'), test_files, True))
ids = ["%s:%s" % (c.module_name, c.line_nr_test) for c in cases]
metafunc.parametrize('case', cases, ids=ids)
if 'refactor_case' in metafunc.fixturenames:
base_dir = metafunc.config.option.refactor_case_dir
metafunc.parametrize(
'refactor_case',
refactor.collect_dir_tests(base_dir, test_files))
if 'static_analysis_case' in metafunc.fixturenames:
base_dir = os.path.join(os.path.dirname(__file__), 'static_analysis')
metafunc.parametrize(
'static_analysis_case',
collect_static_analysis_tests(base_dir, test_files))
def collect_static_analysis_tests(base_dir, test_files):
for f_name in os.listdir(base_dir):
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
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):
analysis = jedi.Script(self._source, path=self._path)._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))
@pytest.fixture()
def isolated_jedi_cache(monkeypatch, tmpdir):
"""
Set `jedi.settings.cache_directory` to a temporary directory during test.
Same as `clean_jedi_cache`, but create the temporary directory for
each test case (scope='function').
"""
monkeypatch.setattr(settings, 'cache_directory', str(tmpdir))

View file

@ -0,0 +1,40 @@
"""
A helper module for testing, improves compatibility for testing (as
``jedi._compatibility``) as well as introducing helper functions.
"""
import sys
if sys.hexversion < 0x02070000:
import unittest2 as unittest
else:
import unittest
TestCase = unittest.TestCase
import os
from os.path import abspath, dirname
import functools
test_dir = dirname(abspath(__file__))
root_dir = dirname(test_dir)
sample_int = 1 # This is used in completion/imports.py
def cwd_at(path):
"""
Decorator to run function at `path`.
:type path: str
:arg path: relative path from repository root (e.g., ``'jedi'``).
"""
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwds):
try:
oldcwd = os.getcwd()
repo_root = os.path.dirname(test_dir)
os.chdir(os.path.join(repo_root, path))
return func(*args, **kwds)
finally:
os.chdir(oldcwd)
return wrapper
return decorator

View file

@ -0,0 +1,99 @@
#!/usr/bin/env python
"""
Refactoring tests work a little bit similar to Black Box tests. But the idea is
here to compare two versions of code. **Note: Refactoring is currently not in
active development (and was never stable), the tests are therefore not really
valuable - just ignore them.**
"""
from __future__ import with_statement
import os
import re
from functools import reduce
import jedi
from jedi import refactoring
class RefactoringCase(object):
def __init__(self, name, source, line_nr, index, path,
new_name, start_line_test, desired):
self.name = name
self.source = source
self.line_nr = line_nr
self.index = index
self.path = path
self.new_name = new_name
self.start_line_test = start_line_test
self.desired = desired
def refactor(self):
script = jedi.Script(self.source, self.line_nr, self.index, self.path)
f_name = os.path.basename(self.path)
refactor_func = getattr(refactoring, f_name.replace('.py', ''))
args = (self.new_name,) if self.new_name else ()
return refactor_func(script, *args)
def run(self):
refactor_object = self.refactor()
# try to get the right excerpt of the newfile
f = refactor_object.new_files()[self.path]
lines = f.splitlines()[self.start_line_test:]
end = self.start_line_test + len(lines)
pop_start = None
for i, l in enumerate(lines):
if l.startswith('# +++'):
end = i
break
elif '#? ' in l:
pop_start = i
lines.pop(pop_start)
self.result = '\n'.join(lines[:end - 1]).strip()
return self.result
def check(self):
return self.run() == self.desired
def __repr__(self):
return '<%s: %s:%s>' % (self.__class__.__name__,
self.name, self.line_nr - 1)
def collect_file_tests(source, path, lines_to_execute):
r = r'^# --- ?([^\n]*)\n((?:(?!\n# \+\+\+).)*)' \
r'\n# \+\+\+((?:(?!\n# ---).)*)'
for match in re.finditer(r, source, re.DOTALL | re.MULTILINE):
name = match.group(1).strip()
first = match.group(2).strip()
second = match.group(3).strip()
start_line_test = source[:match.start()].count('\n') + 1
# get the line with the position of the operation
p = re.match(r'((?:(?!#\?).)*)#\? (\d*) ?([^\n]*)', first, re.DOTALL)
if p is None:
print("Please add a test start.")
continue
until = p.group(1)
index = int(p.group(2))
new_name = p.group(3)
line_nr = start_line_test + until.count('\n') + 2
if lines_to_execute and line_nr - 1 not in lines_to_execute:
continue
yield RefactoringCase(name, source, line_nr, index, path,
new_name, start_line_test, second)
def collect_dir_tests(base_dir, test_files):
for f_name in os.listdir(base_dir):
files_to_execute = [a for a in test_files.items() if a[0] in f_name]
lines_to_execute = reduce(lambda x, y: x + y[1], files_to_execute, [])
if f_name.endswith(".py") and (not test_files or files_to_execute):
path = os.path.join(base_dir, f_name)
with open(path) as f:
source = f.read()
for case in collect_file_tests(source, path, lines_to_execute):
yield case

View file

@ -0,0 +1,47 @@
# --- simple
def test():
#? 35 a
return test(100, (30 + b, c) + 1)
# +++
def test():
a = (30 + b, c) + 1
return test(100, a)
# --- simple #2
def test():
#? 25 a
return test(100, (30 + b, c) + 1)
# +++
def test():
a = 30 + b
return test(100, (a, c) + 1)
# --- multiline
def test():
#? 30 x
return test(1, (30 + b, c)
+ 1)
# +++
def test():
x = ((30 + b, c)
+ 1)
return test(1, x
)
# --- multiline #2
def test():
#? 25 x
return test(1, (30 + b, c)
+ 1)
# +++
def test():
x = 30 + b
return test(1, (x, c)
+ 1)

View file

@ -0,0 +1,18 @@
# --- simple
def test():
#? 4
a = (30 + b, c) + 1
return test(100, a)
# +++
def test():
return test(100, (30 + b, c) + 1)
# --- simple
if 1:
#? 4
a = 1, 2
return test(100, a)
# +++
if 1:
return test(100, (1, 2))

View file

@ -0,0 +1,17 @@
"""
Test coverage for renaming is mostly being done by testing
`Script.usages`.
"""
# --- simple
def test1():
#? 7 blabla
test1()
AssertionError
return test1, test1.not_existing
# +++
def blabla():
blabla()
AssertionError
return blabla, blabla.not_existing

View file

@ -0,0 +1,444 @@
#!/usr/bin/env python
"""
|jedi| is mostly being tested by what I would call "Blackbox Tests". These
tests are just testing the interface and do input/output testing. This makes a
lot of sense for |jedi|. Jedi supports so many different code structures, that
it is just stupid to write 200'000 unittests in the manner of
``regression.py``. Also, it is impossible to do doctests/unittests on most of
the internal data structures. That's why |jedi| uses mostly these kind of
tests.
There are different kind of tests:
- completions / goto_definitions ``#?``
- goto_assignments: ``#!``
- usages: ``#<``
How to run tests?
+++++++++++++++++
Jedi uses pytest_ to run unit and integration tests. To run tests,
simply run ``py.test``. You can also use tox_ to run tests for
multiple Python versions.
.. _pytest: http://pytest.org
.. _tox: http://testrun.org/tox
Integration test cases are located in ``test/completion`` directory
and each test case is indicated by either the comment ``#?`` (completions /
definitions), ``#!`` (assignments), or ``#<`` (usages).
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.
In addition to standard `-k` and `-m` options in py.test, you can use
`-T` (`--test-files`) option to specify integration test cases to run.
It takes the format of ``FILE_NAME[:LINE[,LINE[,...]]]`` where
``FILE_NAME`` is a file in ``test/completion`` and ``LINE`` is a line
number of the test comment. Here is some recipes:
Run tests only in ``basic.py`` and ``imports.py``::
py.test test/test_integration.py -T basic.py -T imports.py
Run test at line 4, 6, and 8 in ``basic.py``::
py.test test/test_integration.py -T basic.py:4,6,8
See ``py.test --help`` for more information.
If you want to debug a test, just use the ``--pdb`` option.
Alternate Test Runner
+++++++++++++++++++++
If you don't like the output of ``py.test``, there's an alternate test runner
that you can start by running ``./run.py``. The above example could be run by::
./run.py basic 4 6 8 50-80
The advantage of this runner is simplicity and more customized error reports.
Using both runners will help you to have a quicker overview of what's
happening.
Auto-Completion
+++++++++++++++
Uses comments to specify a test in the next line. The comment says which
results are expected. The comment always begins with `#?`. The last row
symbolizes the cursor.
For example::
#? ['real']
a = 3; a.rea
Because it follows ``a.rea`` and a is an ``int``, which has a ``real``
property.
Goto Definitions
++++++++++++++++
Definition 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
++++++++++++++++
Tests look like this::
abc = 1
#! ['abc=1']
abc
Additionally it is possible to specify the column by adding a number, which
describes the position of the test (otherwise it's just the end of line)::
#! 2 ['abc=1']
abc
Usages
++++++
Tests look like this::
abc = 1
#< abc@1,0 abc@3,0
abc
"""
import os
import re
import sys
import operator
from ast import literal_eval
from io import StringIO
from functools import reduce
import jedi
from jedi._compatibility import unicode, is_py3
from jedi.parser import Parser, load_grammar
from jedi.api.classes import Definition
TEST_COMPLETIONS = 0
TEST_DEFINITIONS = 1
TEST_ASSIGNMENTS = 2
TEST_USAGES = 3
class IntegrationTestCase(object):
def __init__(self, test_type, correct, line_nr, column, start, line,
path=None, skip=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
self.skip = skip
@property
def module_name(self):
return os.path.splitext(os.path.basename(self.path))[0]
@property
def line_nr_test(self):
"""The test is always defined on the line before."""
return self.line_nr - 1
def __repr__(self):
return '<%s: %s:%s:%s>' % (self.__class__.__name__, self.module_name,
self.line_nr_test, self.line.rstrip())
def script(self):
return jedi.Script(self.source, self.line_nr, self.column, self.path)
def run(self, compare_cb):
testers = {
TEST_COMPLETIONS: self.run_completion,
TEST_DEFINITIONS: self.run_goto_definitions,
TEST_ASSIGNMENTS: self.run_goto_assignments,
TEST_USAGES: self.run_usages,
}
return testers[self.test_type](compare_cb)
def run_completion(self, compare_cb):
completions = self.script().completions()
#import cProfile; cProfile.run('script.completions()')
comp_str = set([c.name for c in completions])
return compare_cb(self, comp_str, set(literal_eval(self.correct)))
def run_goto_definitions(self, compare_cb):
script = self.script()
evaluator = script._evaluator
def comparison(definition):
suffix = '()' if definition.type == 'instance' else ''
return definition.desc_with_module + suffix
def definition(correct, correct_start, path):
should_be = set()
for match in re.finditer('(?:[^ ]+)', correct):
string = match.group(0)
parser = Parser(load_grammar(), string, start_symbol='eval_input')
parser.position_modifier.line = self.line_nr
element = parser.get_parsed_node()
element.parent = jedi.api.completion.get_user_scope(
script._get_module(),
(self.line_nr, self.column)
)
results = evaluator.eval_element(element)
if not results:
raise Exception('Could not resolve %s on line %s'
% (match.string, self.line_nr - 1))
should_be |= set(Definition(evaluator, r) for r in results)
# Because the objects have different ids, `repr`, then compare.
should = set(comparison(r) for r in should_be)
return should
should = definition(self.correct, self.start, script.path)
result = script.goto_definitions()
is_str = set(comparison(r) for r in result)
return compare_cb(self, is_str, should)
def run_goto_assignments(self, compare_cb):
result = self.script().goto_assignments()
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):
result = self.script().usages()
self.correct = self.correct.strip()
compare = sorted((r.module_name, r.line, r.column) for r in result)
wanted = []
if not self.correct:
positions = []
else:
positions = literal_eval(self.correct)
for pos_tup in positions:
if type(pos_tup[0]) == str:
# this means that there is a module specified
wanted.append(pos_tup)
else:
line = pos_tup[0]
if pos_tup[0] is not None:
line += self.line_nr
wanted.append((self.module_name, line, pos_tup[1]))
return compare_cb(self, compare, sorted(wanted))
def skip_python_version(line):
comp_map = {
'==': 'eq',
'<=': 'le',
'>=': 'ge',
'<': 'lt',
'>': 'gt',
}
# check for python minimal version number
match = re.match(r" *# *python *([<>]=?|==) *(\d+(?:\.\d+)?)$", line)
if match:
minimal_python_version = tuple(
map(int, match.group(2).split(".")))
operation = getattr(operator, comp_map[match.group(1)])
if not operation(sys.version_info, minimal_python_version):
return "Minimal python version %s %s" % (match.group(1), match.group(2))
return None
def collect_file_tests(path, lines, lines_to_execute):
def makecase(t):
return IntegrationTestCase(t, correct, line_nr, column,
start, line, path=path, skip=skip)
start = None
correct = None
test_type = None
skip = None
for line_nr, line in enumerate(lines, 1):
if correct is not None:
r = re.match('^(\d+)\s*(.*)$', correct)
if r:
column = int(r.group(1))
correct = r.group(2)
start += r.regs[2][0] # second group, start index
else:
column = len(line) - 1 # -1 for the \n
if test_type == '!':
yield makecase(TEST_ASSIGNMENTS)
elif test_type == '<':
yield makecase(TEST_USAGES)
elif correct.startswith('['):
yield makecase(TEST_COMPLETIONS)
else:
yield makecase(TEST_DEFINITIONS)
correct = None
else:
skip = skip or skip_python_version(line)
try:
r = re.search(r'(?:^|(?<=\s))#([?!<])\s*([^\n]*)', line)
# test_type is ? for completion and ! for goto_assignments
test_type = r.group(1)
correct = r.group(2)
# Quick hack to make everything work (not quite a bloody unicorn hack though).
if correct == '':
correct = ' '
start = r.start()
except AttributeError:
correct = None
else:
# Skip the test, if this is not specified test.
for l in lines_to_execute:
if isinstance(l, tuple) and l[0] <= line_nr <= l[1] \
or line_nr == l:
break
else:
if lines_to_execute:
correct = None
def collect_dir_tests(base_dir, test_files, check_thirdparty=False):
for f_name in os.listdir(base_dir):
files_to_execute = [a for a in test_files.items() if f_name.startswith(a[0])]
lines_to_execute = reduce(lambda x, y: x + y[1], files_to_execute, [])
if f_name.endswith(".py") and (not test_files or files_to_execute):
skip = None
if check_thirdparty:
lib = f_name.replace('_.py', '')
try:
# there is always an underline at the end.
# It looks like: completion/thirdparty/pylab_.py
__import__(lib)
except ImportError:
skip = 'Thirdparty-Library %s not found.' % lib
path = os.path.join(base_dir, f_name)
if is_py3:
source = open(path, encoding='utf-8').read()
else:
source = unicode(open(path).read(), 'UTF-8')
for case in collect_file_tests(path, StringIO(source),
lines_to_execute):
case.source = source
if skip:
case.skip = skip
yield case
docoptstr = """
Using run.py to make debugging easier with integration tests.
An alternative testing format, which is much more hacky, but very nice to
work with.
Usage:
run.py [--pdb] [--debug] [--thirdparty] [<rest>...]
run.py --help
Options:
-h --help Show this screen.
--pdb Enable pdb debugging on fail.
-d, --debug Enable text output debugging (please install ``colorama``).
--thirdparty Also run thirdparty tests (in ``completion/thirdparty``).
"""
if __name__ == '__main__':
import docopt
arguments = docopt.docopt(docoptstr)
import time
t_start = time.time()
# Sorry I didn't use argparse here. It's because argparse is not in the
# stdlib in 2.5.
import sys
if arguments['--debug']:
jedi.set_debug_function()
# get test list, that should be executed
test_files = {}
last = None
for arg in arguments['<rest>']:
match = re.match('(\d+)-(\d+)', arg)
if match:
start, end = match.groups()
test_files[last].append((int(start), int(end)))
elif arg.isdigit():
if last is None:
continue
test_files[last].append(int(arg))
else:
test_files[arg] = []
last = arg
# completion tests:
dir_ = os.path.dirname(os.path.realpath(__file__))
completion_test_dir = os.path.join(dir_, '../test/completion')
completion_test_dir = os.path.abspath(completion_test_dir)
summary = []
tests_fail = 0
# execute tests
cases = list(collect_dir_tests(completion_test_dir, test_files))
if test_files or arguments['--thirdparty']:
completion_test_dir += '/thirdparty'
cases += collect_dir_tests(completion_test_dir, test_files, True)
def file_change(current, tests, fails):
if current is not None:
current = os.path.basename(current)
print('%s \t\t %s tests and %s fails.' % (current, tests, fails))
def report(case, actual, desired):
if actual == desired:
return 0
else:
print("\ttest fail @%d, actual = %s, desired = %s"
% (case.line_nr - 1, actual, desired))
return 1
import traceback
current = cases[0].path if cases else None
count = fails = 0
for c in cases:
if c.skip:
continue
if current != c.path:
file_change(current, count, fails)
current = c.path
count = fails = 0
try:
if c.run(report):
tests_fail += 1
fails += 1
except Exception:
traceback.print_exc()
print("\ttest fail @%d" % (c.line_nr - 1))
tests_fail += 1
fails += 1
if arguments['--pdb']:
import pdb
pdb.post_mortem()
count += 1
file_change(current, count, fails)
print('\nSummary: (%s fails of %s tests) in %.3fs'
% (tests_fail, len(cases), time.time() - t_start))
for s in summary:
print(s)
exit_code = 1 if tests_fail else 0
sys.exit(exit_code)

View file

@ -0,0 +1,37 @@
def marks(code):
if '.' in code:
another(code[:code.index(',') - 1] + '!')
else:
another(code + '.')
def another(code2):
call(numbers(code2 + 'haha'))
marks('start1 ')
marks('start2 ')
def alphabet(code4):
if 1:
if 2:
return code4 + 'a'
else:
return code4 + 'b'
else:
if 2:
return code4 + 'c'
else:
return code4 + 'd'
def numbers(code5):
if 2:
return alphabet(code5 + '1')
else:
return alphabet(code5 + '2')
def call(code3):
code3 = numbers(numbers('end')) + numbers(code3)
code3.partition

View file

@ -0,0 +1,73 @@
# -----------------
# normal arguments (no keywords)
# -----------------
def simple(a):
return a
simple(1)
#! 6 type-error-too-few-arguments
simple()
#! 10 type-error-too-many-arguments
simple(1, 2)
#! 10 type-error-too-many-arguments
simple(1, 2, 3)
# -----------------
# keyword arguments
# -----------------
simple(a=1)
#! 7 type-error-keyword-argument
simple(b=1)
#! 10 type-error-too-many-arguments
simple(1, a=1)
def two_params(x, y):
return y
two_params(y=2, x=1)
two_params(1, y=2)
#! 11 type-error-multiple-values
two_params(1, x=2)
#! 17 type-error-too-many-arguments
two_params(1, 2, y=3)
# -----------------
# default arguments
# -----------------
def default(x, y=1, z=2):
return x
#! 7 type-error-too-few-arguments
default()
default(1)
default(1, 2)
default(1, 2, 3)
#! 17 type-error-too-many-arguments
default(1, 2, 3, 4)
default(x=1)
# -----------------
# class arguments
# -----------------
class Instance():
def __init__(self, foo):
self.foo = foo
Instance(1).foo
Instance(foo=1).foo
#! 12 type-error-too-many-arguments
Instance(1, 2).foo
#! 8 type-error-too-few-arguments
Instance().foo

View file

@ -0,0 +1,119 @@
class Cls():
class_attr = ''
def __init__(self, input):
self.instance_attr = 3
self.input = input
def f(self):
#! 12 attribute-error
return self.not_existing
def undefined_object(self, obj):
"""
Uses an arbitrary object and performs an operation on it, shouldn't
be a problem.
"""
obj.arbitrary_lookup
def defined_lookup(self, obj):
"""
`obj` is defined by a call into this function.
"""
obj.upper
#! 4 attribute-error
obj.arbitrary_lookup
#! 13 name-error
class_attr = a
Cls(1).defined_lookup('')
c = Cls(1)
c.class_attr
Cls.class_attr
#! 4 attribute-error
Cls.class_attr_error
c.instance_attr
#! 2 attribute-error
c.instance_attr_error
c.something = None
#! 12 name-error
something = a
something
# -----------------
# Unused array variables should still raise attribute errors.
# -----------------
# should not raise anything.
for loop_variable in [1, 2]:
#! 4 name-error
x = undefined
loop_variable
#! 28 name-error
for loop_variable in [1, 2, undefined]:
pass
#! 7 attribute-error
[1, ''.undefined_attr]
def return_one(something):
return 1
#! 14 attribute-error
return_one(''.undefined_attribute)
#! 12 name-error
[r for r in undefined]
#! 1 name-error
[undefined for r in [1, 2]]
[r for r in [1, 2]]
# some random error that showed up
class NotCalled():
def match_something(self, param):
seems_to_need_an_assignment = param
return [value.match_something() for value in []]
# -----------------
# decorators
# -----------------
#! 1 name-error
@undefined_decorator
def func():
return 1
# -----------------
# operators
# -----------------
string = '%s %s' % (1, 2)
# Shouldn't raise an error, because `string` is really just a string, not an
# array or something.
string.upper
# -----------------
# imports
# -----------------
# Star imports and the like in modules should not cause attribute errors in
# this module.
import import_tree
import_tree.a
import_tree.b
# This is something that raised an error, because it was using a complex
# mixture of Jedi fakes and compiled objects.
import _sre
#! 15 attribute-error
_sre.compile().not_existing

View file

@ -0,0 +1,46 @@
"""
Jedi issues warnings for possible errors if ``__getattr__``,
``__getattribute__`` or ``setattr`` are used.
"""
# -----------------
# __getattr*__
# -----------------
class Cls():
def __getattr__(self, name):
return getattr(str, name)
Cls().upper
#! 6 warning attribute-error
Cls().undefined
class Inherited(Cls):
pass
Inherited().upper
#! 12 warning attribute-error
Inherited().undefined
# -----------------
# setattr
# -----------------
class SetattrCls():
def __init__(self, dct):
# Jedi doesn't even try to understand such code
for k, v in dct.items():
setattr(self, k, v)
self.defined = 3
c = SetattrCls({'a': 'b'})
c.defined
#! 2 warning attribute-error
c.undefined

View file

@ -0,0 +1,46 @@
# -----------------
# Simple tests
# -----------------
import random
if random.choice([0, 1]):
x = ''
else:
x = 1
if random.choice([0, 1]):
y = ''
else:
y = 1
# A simple test
if x != 1:
x.upper()
else:
#! 2 attribute-error
x.upper()
pass
# This operation is wrong, because the types could be different.
#! 6 type-error-operation
z = x + y
# However, here we have correct types.
if x == y:
z = x + y
else:
#! 6 type-error-operation
z = x + y
# -----------------
# With a function
# -----------------
def addition(a, b):
if type(a) == type(b):
return a + b
else:
#! 9 type-error-operation
return a + b
addition(1, 1)
addition(1.0, '')

View file

@ -0,0 +1,11 @@
# ----------
# isinstance
# ----------
isinstance(1, int)
isinstance(1, (int, str))
#! 14 type-error-isinstance
isinstance(1, 1)
#! 14 type-error-isinstance
isinstance(1, [int, str])

View file

@ -0,0 +1,13 @@
class Base(object):
class Nested():
def foo():
pass
class X(Base.Nested):
pass
X().foo()
#! 4 attribute-error
X().bar()

View file

@ -0,0 +1,41 @@
[a + 1 for a in [1, 2]]
#! 3 type-error-operation
[a + '' for a in [1, 2]]
#! 3 type-error-operation
(a + '' for a in [1, 2])
#! 12 type-error-not-iterable
[a for a in 1]
tuple(str(a) for a in [1])
#! 8 type-error-operation
tuple(a + 3 for a in [''])
# ----------
# Some variables within are not defined
# ----------
#! 12 name-error
[1 for a in NOT_DEFINFED for b in a if 1]
#! 25 name-error
[1 for a in [1] for b in NOT_DEFINED if 1]
#! 12 name-error
[1 for a in NOT_DEFINFED for b in [1] if 1]
#! 19 name-error
(1 for a in [1] if NOT_DEFINED)
# ----------
# unbalanced sides.
# ----------
# ok
(1 for a, b in [(1, 2)])
#! 13 value-error-too-few-values
(1 for a, b, c in [(1, 2)])
#! 10 value-error-too-many-values
(1 for a, b in [(1, 2, 3)])

View file

@ -0,0 +1,13 @@
# classmethod
class TarFile():
@classmethod
def open(cls, name, **kwargs):
return cls.taropen(name, **kwargs)
@classmethod
def taropen(cls, name, **kwargs):
return name
# should just work
TarFile.open('hallo')

View file

@ -0,0 +1,7 @@
def generator():
yield 1
#! 11 type-error-not-subscriptable
generator()[0]
list(generator())[0]

View file

@ -0,0 +1,5 @@
"""
Another import tree, this time not for completion, but static analysis.
"""
from .a import *

View file

@ -0,0 +1 @@
from . import b

View file

@ -0,0 +1,25 @@
#! 7 import-error
import not_existing
import os
from os.path import abspath
#! 20 import-error
from os.path import not_existing
from datetime import date
date.today
#! 5 attribute-error
date.not_existing_attribute
#! 14 import-error
from datetime.date import today
#! 16 import-error
import datetime.date
#! 7 import-error
import not_existing_nested.date
import os.path

View file

@ -0,0 +1,21 @@
a, b = {'asdf': 3, 'b': 'str'}
a
x = [1]
x[0], b = {'a': 1, 'b': '2'}
dct = {3: ''}
for x in dct:
pass
#! 4 type-error-not-iterable
for x, y in dct:
pass
# Shouldn't cause issues, because if there are no types (or we don't know what
# the types are, we should just ignore it.
#! 0 value-error-too-few-values
a, b = []
#! 7 name-error
a, b = NOT_DEFINED

View file

@ -0,0 +1,7 @@
def raises():
raise KeyError()
def wrong_name():
#! 6 name-error
raise NotExistingException()

View file

@ -0,0 +1,16 @@
-1 + 1
1 + 1.0
#! 2 type-error-operation
1 + '1'
#! 2 type-error-operation
1 - '1'
-1 - - 1
-1 - int()
int() - float()
float() - 3.0
a = 3
b = ''
#! 2 type-error-operation
a + b

View file

@ -0,0 +1,11 @@
"""
Some special cases of Python 2.
"""
# python <= 2.7
# print is syntax:
print 1
print(1)
#! 6 name-error
print NOT_DEFINED

View file

@ -0,0 +1,119 @@
# -----------------
# *args
# -----------------
def simple(a):
return a
def nested(*args):
return simple(*args)
nested(1)
#! 6 type-error-too-few-arguments
nested()
def nested_no_call_to_function(*args):
return simple(1, *args)
def simple2(a, b, c):
return b
def nested(*args):
return simple2(1, *args)
def nested_twice(*args1):
return nested(*args1)
nested_twice(2, 3)
#! 13 type-error-too-few-arguments
nested_twice(2)
#! 19 type-error-too-many-arguments
nested_twice(2, 3, 4)
# A named argument can be located before *args.
def star_args_with_named(*args):
return simple2(c='', *args)
star_args_with_named(1, 2)
# -----------------
# **kwargs
# -----------------
def kwargs_test(**kwargs):
return simple2(1, **kwargs)
kwargs_test(c=3, b=2)
#! 12 type-error-too-few-arguments
kwargs_test(c=3)
#! 12 type-error-too-few-arguments
kwargs_test(b=2)
#! 22 type-error-keyword-argument
kwargs_test(b=2, c=3, d=4)
#! 12 type-error-multiple-values
kwargs_test(b=2, c=3, a=4)
def kwargs_nested(**kwargs):
return kwargs_test(b=2, **kwargs)
kwargs_nested(c=3)
#! 13 type-error-too-few-arguments
kwargs_nested()
#! 19 type-error-keyword-argument
kwargs_nested(c=2, d=4)
#! 14 type-error-multiple-values
kwargs_nested(c=2, a=4)
# TODO reenable
##! 14 type-error-multiple-values
#kwargs_nested(b=3, c=2)
# -----------------
# mixed *args/**kwargs
# -----------------
def simple_mixed(a, b, c):
return b
def mixed(*args, **kwargs):
return simple_mixed(1, *args, **kwargs)
mixed(1, 2)
mixed(1, c=2)
mixed(b=2, c=3)
mixed(c=4, b='')
# need separate functions, otherwise these might swallow the errors
def mixed2(*args, **kwargs):
return simple_mixed(1, *args, **kwargs)
#! 7 type-error-too-few-arguments
mixed2(c=2)
#! 7 type-error-too-few-arguments
mixed2(3)
#! 13 type-error-too-many-arguments
mixed2(3, 4, 5)
# TODO reenable
##! 13 type-error-too-many-arguments
#mixed2(3, 4, c=5)
#! 7 type-error-multiple-values
mixed2(3, b=5)
# -----------------
# plain wrong arguments
# -----------------
#! 12 type-error-star-star
simple(1, **[])
#! 12 type-error-star-star
simple(1, **1)
class A(): pass
#! 12 type-error-star-star
simple(1, **A())
#! 11 type-error-star
simple(1, *1)

View file

@ -0,0 +1,89 @@
try:
#! 4 attribute-error
str.not_existing
except TypeError:
pass
try:
str.not_existing
except AttributeError:
#! 4 attribute-error
str.not_existing
pass
try:
import not_existing_import
except ImportError:
pass
try:
#! 7 import-error
import not_existing_import
except AttributeError:
pass
# -----------------
# multi except
# -----------------
try:
str.not_existing
except (TypeError, AttributeError): pass
try:
str.not_existing
except ImportError:
pass
except (NotImplementedError, AttributeError): pass
try:
#! 4 attribute-error
str.not_existing
except (TypeError, NotImplementedError): pass
# -----------------
# detailed except
# -----------------
try:
str.not_existing
except ((AttributeError)): pass
try:
#! 4 attribute-error
str.not_existing
except [AttributeError]: pass
# Should be able to detect errors in except statement as well.
try:
pass
#! 7 name-error
except Undefined:
pass
# -----------------
# inheritance
# -----------------
try:
undefined
except Exception:
pass
# should catch everything
try:
undefined
except:
pass
# -----------------
# kind of similar: hasattr
# -----------------
if hasattr(str, 'undefined'):
str.undefined
str.upper
#! 4 attribute-error
str.undefined2
#! 4 attribute-error
int.undefined
else:
str.upper
#! 4 attribute-error
str.undefined

View file

@ -0,0 +1,179 @@
"""
Test all things related to the ``jedi.api`` module.
"""
from textwrap import dedent
from jedi import api
from jedi._compatibility import is_py3
from pytest import raises
from jedi.parser import utils
def test_preload_modules():
def check_loaded(*modules):
# +1 for None module (currently used)
assert len(parser_cache) == len(modules) + 1
for i in modules:
assert [i in k for k in parser_cache.keys() if k is not None]
temp_cache, utils.parser_cache = utils.parser_cache, {}
parser_cache = utils.parser_cache
api.preload_module('sys')
check_loaded() # compiled (c_builtin) modules shouldn't be in the cache.
api.preload_module('json', 'token')
check_loaded('json', 'token')
utils.parser_cache = temp_cache
def test_empty_script():
assert api.Script('')
def test_line_number_errors():
"""
Script should raise a ValueError if line/column numbers are not in a
valid range.
"""
s = 'hello'
# lines
with raises(ValueError):
api.Script(s, 2, 0)
with raises(ValueError):
api.Script(s, 0, 0)
# columns
with raises(ValueError):
api.Script(s, 1, len(s) + 1)
with raises(ValueError):
api.Script(s, 1, -1)
# ok
api.Script(s, 1, 0)
api.Script(s, 1, len(s))
def _check_number(source, result='float'):
completions = api.Script(source).completions()
assert completions[0].parent().name == result
def test_completion_on_number_literals():
# No completions on an int literal (is a float).
assert [c.name for c in api.Script('1.').completions()] \
== ['and', 'if', 'in', 'is', 'not', 'or']
# Multiple points after an int literal basically mean that there's a float
# and a call after that.
_check_number('1..')
_check_number('1.0.')
# power notation
_check_number('1.e14.')
_check_number('1.e-3.')
_check_number('9e3.')
assert api.Script('1.e3..').completions() == []
assert api.Script('1.e-13..').completions() == []
def test_completion_on_hex_literals():
assert api.Script('0x1..').completions() == []
_check_number('0x1.', 'int') # hexdecimal
# Completing binary literals doesn't work if they are not actually binary
# (invalid statements).
assert api.Script('0b2.b').completions() == []
_check_number('0b1.', 'int') # binary
_check_number('0x2e.', 'int')
_check_number('0xE7.', 'int')
_check_number('0xEa.', 'int')
# theoretically, but people can just check for syntax errors:
#assert api.Script('0x.').completions() == []
def test_completion_on_complex_literals():
assert api.Script('1j..').completions() == []
_check_number('1j.', 'complex')
_check_number('44.j.', 'complex')
_check_number('4.0j.', 'complex')
# No dot no completion - I thought, but 4j is actually a literall after
# which a keyword like or is allowed. Good times, haha!
assert (set([c.name for c in api.Script('4j').completions()]) ==
set(['if', 'and', 'in', 'is', 'not', 'or']))
def test_goto_assignments_on_non_name():
assert api.Script('for').goto_assignments() == []
assert api.Script('assert').goto_assignments() == []
if is_py3:
assert api.Script('True').goto_assignments() == []
else:
# In Python 2.7 True is still a name.
assert api.Script('True').goto_assignments()[0].description == 'class bool'
def test_goto_definitions_on_non_name():
assert api.Script('import x', column=0).goto_definitions() == []
def test_goto_definition_not_multiple():
"""
There should be only one Definition result if it leads back to the same
origin (e.g. instance method)
"""
s = dedent('''\
import random
class A():
def __init__(self, a):
self.a = 3
def foo(self):
pass
if random.randint(0, 1):
a = A(2)
else:
a = A(1)
a''')
assert len(api.Script(s).goto_definitions()) == 1
def test_usage_description():
descs = [u.description for u in api.Script("foo = ''; foo").usages()]
assert set(descs) == set(["foo = ''", 'foo'])
def test_get_line_code():
def get_line_code(source, line=None, **kwargs):
return api.Script(source, line=line).completions()[0].get_line_code(**kwargs)
# On builtin
assert get_line_code('') == ''
# On custom code
line = ' foo'
assert get_line_code('def foo():\n%s' % line) == line
# With before/after
line = ' foo'
source = 'def foo():\n%s\nother_line' % line
assert get_line_code(source, line=2) == line
assert get_line_code(source, line=2, after=1) == line + '\nother_line'
assert get_line_code(source, line=2, after=1, before=1) == source
def test_goto_assignments_follow_imports():
code = dedent("""
import inspect
inspect.isfunction""")
definition, = api.Script(code, column=0).goto_assignments(follow_imports=True)
assert 'inspect.py' in definition.module_path
assert definition.start_pos == (1, 0)
definition, = api.Script(code).goto_assignments(follow_imports=True)
assert 'inspect.py' in definition.module_path
assert definition.start_pos > (1, 0)

View file

@ -0,0 +1,62 @@
from itertools import chain
import jedi
from ..helpers import cwd_at
def test_import_empty():
""" github #340, return the full word. """
completion = jedi.Script("import ").completions()[0]
definition = completion.follow_definition()[0]
assert definition
def check_follow_definition_types(source):
# nested import
completions = jedi.Script(source, path='some_path.py').completions()
defs = chain.from_iterable(c.follow_definition() for c in completions)
return [d.type for d in defs]
def test_follow_import_incomplete():
"""
Completion on incomplete imports should always take the full completion
to do any evaluation.
"""
datetime = check_follow_definition_types("import itertool")
assert datetime == ['module']
# empty `from * import` parts
itert = jedi.Script("from itertools import ").completions()
definitions = [d for d in itert if d.name == 'chain']
assert len(definitions) == 1
assert [d.type for d in definitions[0].follow_definition()] == ['class']
# incomplete `from * import` part
datetime = check_follow_definition_types("from datetime import datetim")
assert set(datetime) == set(['class', 'instance']) # py33: builtin and pure py version
# os.path check
ospath = check_follow_definition_types("from os.path import abspat")
assert ospath == ['function']
# alias
alias = check_follow_definition_types("import io as abcd; abcd")
assert alias == ['module']
@cwd_at('test/completion/import_tree')
def test_follow_definition_nested_import():
types = check_follow_definition_types("import pkg.mod1; pkg")
assert types == ['module']
types = check_follow_definition_types("import pkg.mod1; pkg.mod1")
assert types == ['module']
types = check_follow_definition_types("import pkg.mod1; pkg.mod1.a")
assert types == ['instance']
def test_follow_definition_land_on_import():
types = check_follow_definition_types("import datetime; datetim")
assert types == ['module']

View file

@ -0,0 +1,389 @@
from textwrap import dedent
import inspect
from ..helpers import TestCase
from jedi import Script
from jedi import cache
from jedi._compatibility import is_py33
def assert_signature(source, expected_name, expected_index=0, line=None, column=None):
signatures = Script(source, line, column).call_signatures()
assert len(signatures) <= 1
if not signatures:
assert expected_name is None, \
'There are no signatures, but `%s` expected.' % expected_name
else:
assert signatures[0].name == expected_name
assert signatures[0].index == expected_index
return signatures[0]
class TestCallSignatures(TestCase):
def _run_simple(self, source, name, index=0, column=None, line=1):
assert_signature(source, name, index, line, column)
def test_valid_call(self):
assert_signature('str()', 'str', column=4)
def test_simple(self):
run = self._run_simple
# simple
s1 = "sorted(a, str("
run(s1, 'sorted', 0, 7)
run(s1, 'sorted', 1, 9)
run(s1, 'sorted', 1, 10)
run(s1, 'sorted', 1, 11)
run(s1, 'str', 0, 14)
s2 = "abs(), "
run(s2, 'abs', 0, 4)
run(s2, None, column=5)
run(s2, None)
s3 = "abs()."
run(s3, None, column=5)
run(s3, None)
def test_more_complicated(self):
run = self._run_simple
'''
s4 = 'abs(zip(), , set,'
run(s4, None, column=3)
run(s4, 'abs', 0, 4)
run(s4, 'zip', 0, 8)
run(s4, 'abs', 0, 9)
#run(s4, 'abs', 1, 10)
'''
s5 = "sorted(1,\nif 2:\n def a():"
run(s5, 'sorted', 0, 7)
run(s5, 'sorted', 1, 9)
s6 = "str().center("
run(s6, 'center', 0)
run(s6, 'str', 0, 4)
s7 = "str().upper().center("
s8 = "str(int[zip("
run(s7, 'center', 0)
run(s8, 'zip', 0)
run(s8, 'str', 0, 8)
run("import time; abc = time; abc.sleep(", 'sleep', 0)
def test_issue_57(self):
# jedi #57
s = "def func(alpha, beta): pass\n" \
"func(alpha='101',"
self._run_simple(s, 'func', 0, column=13, line=2)
def test_flows(self):
# jedi-vim #9
self._run_simple("with open(", 'open', 0)
# jedi-vim #11
self._run_simple("for sorted(", 'sorted', 0)
self._run_simple("for s in sorted(", 'sorted', 0)
def test_complex(self):
s = """
def abc(a,b):
pass
def a(self):
abc(
if 1:
pass
"""
assert_signature(s, 'abc', 0, line=6, column=24)
s = """
import re
def huhu(it):
re.compile(
return it * 2
"""
assert_signature(s, 'compile', 0, line=4, column=31)
# jedi-vim #70
s = """def foo("""
assert Script(s).call_signatures() == []
# jedi-vim #116
s = """import itertools; test = getattr(itertools, 'chain'); test("""
assert_signature(s, 'chain', 0)
def test_call_signature_on_module(self):
"""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() == []
def test_call_signatures_empty_parentheses_pre_space(self):
s = dedent("""\
def f(a, b):
pass
f( )""")
assert_signature(s, 'f', 0, line=3, column=3)
def test_multiple_signatures(self):
s = dedent("""\
if x:
def f(a, b):
pass
else:
def f(a, b):
pass
f(""")
assert len(Script(s).call_signatures()) == 2
def test_call_signatures_whitespace(self):
s = dedent("""\
abs(
def x():
pass
""")
assert_signature(s, 'abs', 0, line=1, column=5)
def test_decorator_in_class(self):
"""
There's still an implicit param, with a decorator.
Github issue #319.
"""
s = dedent("""\
def static(func):
def wrapped(obj, *args):
return f(type(obj), *args)
return wrapped
class C(object):
@static
def test(cls):
return 10
C().test(""")
signatures = Script(s).call_signatures()
assert len(signatures) == 1
x = [p.description for p in signatures[0].params]
assert x == ['*args']
def test_additional_brackets(self):
assert_signature('str((', 'str', 0)
def test_unterminated_strings(self):
assert_signature('str(";', 'str', 0)
def test_whitespace_before_bracket(self):
assert_signature('str (', 'str', 0)
assert_signature('str (";', 'str', 0)
assert_signature('str\n(', None)
def test_brackets_in_string_literals(self):
assert_signature('str (" (', 'str', 0)
assert_signature('str (" )', 'str', 0)
def test_function_definitions_should_break(self):
"""
Function definitions (and other tokens that cannot exist within call
signatures) should break and not be able to return a call signature.
"""
assert_signature('str(\ndef x', 'str', 0)
assert not Script('str(\ndef x(): pass').call_signatures()
def test_flow_call(self):
assert not Script('if (1').call_signatures()
def test_chained_calls(self):
source = dedent('''
class B():
def test2(self, arg):
pass
class A():
def test1(self):
return B()
A().test1().test2(''')
assert_signature(source, 'test2', 0)
def test_return(self):
source = dedent('''
def foo():
return '.'.join()''')
assert_signature(source, 'join', 0, column=len(" return '.'.join("))
class TestParams(TestCase):
def params(self, source, line=None, column=None):
signatures = Script(source, line, column).call_signatures()
assert len(signatures) == 1
return signatures[0].params
def test_param_name(self):
if not is_py33:
p = self.params('''int(''')
# int is defined as: `int(x[, base])`
assert p[0].name == 'x'
# `int` docstring has been redefined:
# http://bugs.python.org/issue14783
# TODO have multiple call signatures for int (like in the docstr)
#assert p[1].name == 'base'
p = self.params('''open(something,''')
assert p[0].name in ['file', 'name']
assert p[1].name == 'mode'
def test_builtins(self):
"""
The self keyword should be visible even for builtins, if not
instantiated.
"""
p = self.params('str.endswith(')
assert p[0].name == 'self'
assert p[1].name == 'suffix'
p = self.params('str().endswith(')
assert p[0].name == 'suffix'
def test_signature_is_definition():
"""
Through inheritance, a call 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.line == 1
signature.column == 6
# Now compare all the attributes that a CallSignature must also have.
for attr_name in dir(definition):
dont_scan = ['defined_names', 'line_nr', 'start_pos', 'documentation',
'doc', 'parent', 'goto_assignments']
if attr_name.startswith('_') or attr_name in dont_scan:
continue
attribute = getattr(definition, attr_name)
signature_attribute = getattr(signature, attr_name)
if inspect.ismethod(attribute):
assert attribute() == signature_attribute()
else:
assert attribute == signature_attribute
def test_no_signature():
# str doesn't have a __call__ method
assert Script('str()(').call_signatures() == []
s = dedent("""\
class X():
pass
X()(""")
assert Script(s).call_signatures() == []
assert len(Script(s, column=2).call_signatures()) == 1
def test_dict_literal_in_incomplete_call():
source = """\
import json
def foo():
json.loads(
json.load.return_value = {'foo': [],
'bar': True}
c = Foo()
"""
script = Script(dedent(source), line=4, column=15)
assert script.call_signatures()
def test_completion_interference():
"""Seems to cause problems, see also #396."""
cache.parser_cache.pop(None, None)
assert Script('open(').call_signatures()
# complete something usual, before doing the same call_signatures again.
assert Script('from datetime import ').completions()
assert Script('open(').call_signatures()
def test_keyword_argument_index():
def get(source, column=None):
return Script(source, column=column).call_signatures()[0]
assert get('sorted([], key=a').index == 2
assert get('sorted([], key=').index == 2
assert get('sorted([], no_key=a').index is None
kw_func = 'def foo(a, b): pass\nfoo(b=3, a=4)'
assert get(kw_func, column=len('foo(b')).index == 0
assert get(kw_func, column=len('foo(b=')).index == 1
assert get(kw_func, column=len('foo(b=3, a=')).index == 0
kw_func_simple = 'def foo(a, b): pass\nfoo(b=4)'
assert get(kw_func_simple, column=len('foo(b')).index == 0
assert get(kw_func_simple, column=len('foo(b=')).index == 1
args_func = 'def foo(*kwargs): pass\n'
assert get(args_func + 'foo(a').index == 0
assert get(args_func + 'foo(a, b').index == 0
kwargs_func = 'def foo(**kwargs): pass\n'
assert get(kwargs_func + 'foo(a=2').index == 0
assert get(kwargs_func + 'foo(a=2, b=2').index == 0
both = 'def foo(*args, **kwargs): pass\n'
assert get(both + 'foo(a=2').index == 1
assert get(both + 'foo(a=2, b=2').index == 1
assert get(both + 'foo(a=2, b=2)', column=len('foo(b=2, a=2')).index == 1
assert get(both + 'foo(a, b, c').index == 0
def test_bracket_start():
def bracket_start(src):
signatures = Script(src).call_signatures()
assert len(signatures) == 1
return signatures[0].bracket_start
assert bracket_start('str(') == (1, 3)
def test_different_caller():
"""
It's possible to not use names, but another function result or an array
index and then get the call signature of it.
"""
assert_signature('[str][0](', 'str', 0)
assert_signature('[str][0]()', 'str', 0, column=len('[str][0]('))
assert_signature('(str)(', 'str', 0)
assert_signature('(str)()', 'str', 0, column=len('(str)('))
def test_in_function():
code = dedent('''\
class X():
@property
def func(''')
assert not Script(code).call_signatures()
def test_lambda_params():
code = dedent('''\
my_lambda = lambda x: x+1
my_lambda(1)''')
sig, = Script(code, column=11).call_signatures()
assert sig.index == 0
assert sig.name == '<lambda>'
assert [p.name for p in sig.params] == ['x']

View file

@ -0,0 +1,354 @@
""" Test all things related to the ``jedi.api_classes`` module.
"""
from textwrap import dedent
from inspect import cleandoc
import pytest
from jedi import Script, defined_names, __doc__ as jedi_doc, names
from ..helpers import cwd_at
from ..helpers import TestCase
def test_is_keyword():
#results = Script('import ', 1, 1, None).goto_definitions()
#assert len(results) == 1 and results[0].is_keyword is True
results = Script('str', 1, 1, None).goto_definitions()
assert len(results) == 1 and results[0].is_keyword is False
def make_definitions():
"""
Return a list of definitions for parametrized tests.
:rtype: [jedi.api_classes.BaseDefinition]
"""
source = dedent("""
import sys
class C:
pass
x = C()
def f():
pass
def g():
yield
h = lambda: None
""")
definitions = []
definitions += defined_names(source)
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()
script2 = Script(source, 4, len('class C'), None)
definitions += script2.usages()
source_param = "def f(a): return a"
script_param = Script(source_param, 1, len(source_param), None)
definitions += script_param.goto_assignments()
return definitions
@pytest.mark.parametrize('definition', make_definitions())
def test_basedefinition_type(definition):
assert definition.type in ('module', 'class', 'instance', 'function',
'generator', 'statement', 'import', 'param')
def test_basedefinition_type_import():
def get_types(source, **kwargs):
return set([t.type for t in Script(source, **kwargs).completions()])
# import one level
assert get_types('import t') == set(['module'])
assert get_types('import ') == set(['module'])
assert get_types('import datetime; datetime') == set(['module'])
# from
assert get_types('from datetime import timedelta') == set(['class'])
assert get_types('from datetime import timedelta; timedelta') == set(['class'])
assert get_types('from json import tool') == set(['module'])
assert get_types('from json import tool; tool') == set(['module'])
# import two levels
assert get_types('import json.tool; json') == set(['module'])
assert get_types('import json.tool; json.tool') == set(['module'])
assert get_types('import json.tool; json.tool.main') == set(['function'])
assert get_types('import json.tool') == set(['module'])
assert get_types('import json.tool', column=9) == set(['module'])
def test_function_call_signature_in_doc():
defs = Script("""
def f(x, y=1, z='a'):
pass
f""").goto_definitions()
doc = defs[0].doc
assert "f(x, y=1, z='a')" in str(doc)
def test_class_call_signature():
defs = Script("""
class Foo:
def __init__(self, x, y=1, z='a'):
pass
Foo""").goto_definitions()
doc = defs[0].doc
assert "Foo(self, x, y=1, z='a')" in str(doc)
def test_position_none_if_builtin():
gotos = Script('import sys; sys.path').goto_assignments()
assert gotos[0].line is None
assert gotos[0].column is None
@cwd_at('.')
def test_completion_docstring():
"""
Jedi should follow imports in certain conditions
"""
def docstr(src, result):
c = Script(src).completions()[0]
assert c.docstring(raw=True, fast=False) == cleandoc(result)
c = Script('import jedi\njed').completions()[0]
assert c.docstring(fast=False) == cleandoc(jedi_doc)
docstr('import jedi\njedi.Scr', cleandoc(Script.__doc__))
docstr('abcd=3;abcd', '')
docstr('"hello"\nabcd=3\nabcd', 'hello')
# It works with a ; as well.
docstr('"hello"\nabcd=3;abcd', 'hello')
# Shouldn't work with a tuple.
docstr('"hello",0\nabcd=3\nabcd', '')
def test_completion_params():
c = Script('import string; string.capwords').completions()[0]
assert [p.name for p in c.params] == ['s', 'sep']
def test_signature_params():
def check(defs):
params = defs[0].params
assert len(params) == 1
assert params[0].name == 'bar'
s = dedent('''
def foo(bar):
pass
foo''')
check(Script(s).goto_definitions())
check(Script(s).goto_assignments())
check(Script(s + '\nbar=foo\nbar').goto_assignments())
def test_param_endings():
"""
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]
assert [p.description for p in sig.params] == ['a', 'b=5', 'c=""']
class TestIsDefinition(TestCase):
def _def(self, source, index=-1):
return names(dedent(source), references=True, all_scopes=True)[index]
def _bool_is_definitions(self, source):
ns = names(dedent(source), references=True, all_scopes=True)
# Assure that names are definitely sorted.
ns = sorted(ns, key=lambda name: (name.line, name.column))
return [name.is_definition() for name in ns]
def test_name(self):
d = self._def('name')
assert d.name == 'name'
assert not d.is_definition()
def test_stmt(self):
src = 'a = f(x)'
d = self._def(src, 0)
assert d.name == 'a'
assert d.is_definition()
d = self._def(src, 1)
assert d.name == 'f'
assert not d.is_definition()
d = self._def(src)
assert d.name == 'x'
assert not d.is_definition()
def test_import(self):
assert self._bool_is_definitions('import x as a') == [False, True]
assert self._bool_is_definitions('from x import y') == [False, True]
assert self._bool_is_definitions('from x.z import y') == [False, False, True]
class TestParent(TestCase):
def _parent(self, source, line=None, column=None):
defs = Script(dedent(source), line, column).goto_assignments()
assert len(defs) == 1
return defs[0].parent()
def test_parent(self):
parent = self._parent('foo=1\nfoo')
assert parent.type == 'module'
parent = self._parent('''
def spam():
if 1:
y=1
y''')
assert parent.name == 'spam'
assert parent.parent().type == 'module'
def test_on_function(self):
parent = self._parent('''\
def spam():
pass''', 1, len('def spam'))
assert parent.name == ''
assert parent.type == 'module'
def test_parent_on_completion(self):
parent = Script(dedent('''\
class Foo():
def bar(): pass
Foo().bar''')).completions()[0].parent()
assert parent.name == 'Foo'
assert parent.type == 'instance'
parent = Script('str.join').completions()[0].parent()
assert parent.name == 'str'
assert parent.type == 'class'
def test_type():
"""
Github issue #397, type should never raise an error.
"""
for c in Script('import os; os.path.').completions():
assert c.type
class TestGotoAssignments(TestCase):
"""
This tests the BaseDefinition.goto_assignments function, not the jedi
function. They are not really different in functionality, but really
different as an implementation.
"""
def test_repetition(self):
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()
assert ass[0].description == 'a = 1'
def test_named_params(self):
src = """\
def foo(a=1, bar=2):
pass
foo(bar=1)
"""
bar = names(dedent(src), references=True)[-1]
param = bar.goto_assignments()[0]
assert param.start_pos == (1, 13)
assert param.type == 'param'
def test_class_call(self):
src = 'from threading import Thread; Thread(group=1)'
n = names(src, references=True)[-1]
assert n.name == 'group'
param_def = n.goto_assignments()[0]
assert param_def.name == 'group'
assert param_def.type == 'param'
def test_parentheses(self):
n = names('("").upper', references=True)[-1]
assert n.goto_assignments()[0].name == 'upper'
def test_import(self):
nms = names('from json import load', references=True)
assert nms[0].name == 'json'
assert nms[0].type == 'import'
n = nms[0].goto_assignments()[0]
assert n.name == 'json'
assert n.type == 'module'
assert nms[1].name == 'load'
assert nms[1].type == 'import'
n = nms[1].goto_assignments()[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 == 'import'
n = nms[0].goto_assignments()[0]
assert n.name == 'os'
assert n.type == 'module'
n = nms[2].goto_assignments()[0]
assert n.name == 'path'
assert n.type == 'import'
nms = names('import os.path', references=True)
n = nms[0].goto_assignments()[0]
assert n.name == 'os'
assert n.type == 'module'
n = nms[1].goto_assignments()[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 ('ntpath', 'posixpath', 'os2emxpath')
assert n.type == 'module'
def test_import_alias(self):
nms = names('import json as foo', references=True)
assert nms[0].name == 'json'
assert nms[0].type == 'import'
n = nms[0].goto_assignments()[0]
assert n.name == 'json'
assert n.type == 'module'
assert nms[1].name == 'foo'
assert nms[1].type == 'import'
ass = nms[1].goto_assignments()
assert len(ass) == 1
assert ass[0].name == 'json'
assert ass[0].type == 'module'
def test_added_equals_to_params():
def run(rest_source):
source = dedent("""
def foo(bar, baz):
pass
""")
results = Script(source + rest_source).completions()
assert len(results) == 1
return results[0]
assert run('foo(bar').name_with_symbols == 'bar='
assert run('foo(bar').complete == '='
assert run('foo(bar, baz').complete == '='
assert run(' bar').name_with_symbols == 'bar'
assert run(' bar').complete == ''
x = run('foo(bar=isins').name_with_symbols
assert x == 'isinstance'

View file

@ -0,0 +1,9 @@
from textwrap import dedent
from jedi import Script
def test_in_whitespace():
code = dedent('''
def x():
pass''')
assert len(Script(code, column=2).completions()) > 20

View file

@ -0,0 +1,92 @@
"""
Tests for `api.defined_names`.
"""
from textwrap import dedent
from jedi import defined_names, names
from ..helpers import TestCase
class TestDefinedNames(TestCase):
def assert_definition_names(self, definitions, names_):
assert [d.name for d in definitions] == names_
def check_defined_names(self, source, names_):
definitions = names(dedent(source))
self.assert_definition_names(definitions, names_)
return definitions
def test_get_definitions_flat(self):
self.check_defined_names("""
import module
class Class:
pass
def func():
pass
data = None
""", ['module', 'Class', 'func', 'data'])
def test_dotted_assignment(self):
self.check_defined_names("""
x = Class()
x.y.z = None
""", ['x', 'z']) # TODO is this behavior what we want?
def test_multiple_assignment(self):
self.check_defined_names("""
x = y = None
""", ['x', 'y'])
def test_multiple_imports(self):
self.check_defined_names("""
from module import a, b
from another_module import *
""", ['a', 'b'])
def test_nested_definitions(self):
definitions = self.check_defined_names("""
class Class:
def f():
pass
def g():
pass
""", ['Class'])
subdefinitions = definitions[0].defined_names()
self.assert_definition_names(subdefinitions, ['f', 'g'])
self.assertEqual([d.full_name for d in subdefinitions],
['Class.f', 'Class.g'])
def test_nested_class(self):
definitions = self.check_defined_names("""
class L1:
class L2:
class L3:
def f(): pass
def f(): pass
def f(): pass
def f(): pass
""", ['L1', 'f'])
subdefs = definitions[0].defined_names()
subsubdefs = subdefs[0].defined_names()
self.assert_definition_names(subdefs, ['L2', 'f'])
self.assert_definition_names(subsubdefs, ['L3', 'f'])
self.assert_definition_names(subsubdefs[0].defined_names(), ['f'])
def test_follow_imports():
# github issue #344
imp = defined_names('import datetime')[0]
assert imp.name == 'datetime'
datetime_names = [str(d.name) for d in imp.defined_names()]
assert 'timedelta' in datetime_names
def test_names_twice():
source = dedent('''
def lol():
pass
''')
defs = names(source=source)
assert defs[0].defined_names() == []

View file

@ -0,0 +1,91 @@
"""
Tests for :attr:`.BaseDefinition.full_name`.
There are three kinds of test:
#. Test classes derived from :class:`MixinTestFullName`.
Child class defines :attr:`.operation` to alter how
the api definition instance is created.
#. :class:`TestFullDefinedName` is to test combination of
``obj.full_name`` and ``jedi.defined_names``.
#. Misc single-function tests.
"""
import textwrap
import pytest
import jedi
from ..helpers import TestCase
class MixinTestFullName(object):
operation = None
def check(self, source, desired):
script = jedi.Script(textwrap.dedent(source))
definitions = getattr(script, type(self).operation)()
for d in definitions:
self.assertEqual(d.full_name, desired)
def test_os_path_join(self):
self.check('import os; os.path.join', 'os.path.join')
def test_builtin(self):
self.check('TypeError', 'TypeError')
class TestFullNameWithGotoDefinitions(MixinTestFullName, TestCase):
operation = 'goto_definitions'
@pytest.mark.skipif('sys.version_info[0] < 3', reason='Python 2 also yields None.')
def test_tuple_mapping(self):
self.check("""
import re
any_re = re.compile('.*')
any_re""", '_sre.compile.SRE_Pattern')
def test_from_import(self):
self.check('from os import path', 'os.path')
class TestFullNameWithCompletions(MixinTestFullName, TestCase):
operation = 'completions'
class TestFullDefinedName(TestCase):
"""
Test combination of ``obj.full_name`` and ``jedi.defined_names``.
"""
def check(self, source, desired):
definitions = jedi.defined_names(textwrap.dedent(source))
full_names = [d.full_name for d in definitions]
self.assertEqual(full_names, desired)
def test_local_names(self):
self.check("""
def f(): pass
class C: pass
""", ['f', 'C'])
def test_imports(self):
self.check("""
import os
from os import path
from os.path import join
from os import path as opath
""", ['os', 'os.path', 'os.path.join', 'os.path'])
def test_sub_module():
"""
``full_name needs to check sys.path to actually find it's real path module
path.
"""
defs = jedi.Script('from jedi.api import classes; classes').goto_definitions()
assert [d.full_name for d in defs] == ['jedi.api.classes']
defs = jedi.Script('import jedi.api; jedi.api').goto_definitions()
assert [d.full_name for d in defs] == ['jedi.api']

View file

@ -0,0 +1,160 @@
"""
Tests of ``jedi.api.Interpreter``.
"""
from ..helpers import TestCase
import jedi
from jedi._compatibility import is_py33
from jedi.evaluate.compiled import mixed
class _GlobalNameSpace():
class SideEffectContainer():
pass
def get_completion(source, namespace):
i = jedi.Interpreter(source, [namespace])
completions = i.completions()
assert len(completions) == 1
return completions[0]
def test_builtin_details():
import keyword
class EmptyClass:
pass
variable = EmptyClass()
def func():
pass
cls = get_completion('EmptyClass', locals())
var = get_completion('variable', locals())
f = get_completion('func', locals())
m = get_completion('keyword', locals())
assert cls.type == 'class'
assert var.type == 'instance'
assert f.type == 'function'
assert m.type == 'module'
def test_nested_resolve():
class XX():
def x():
pass
cls = get_completion('XX', locals())
func = get_completion('XX.x', locals())
assert func.start_pos == (cls.start_pos[0] + 1, 12)
def test_side_effect_completion():
"""
In the repl it's possible to cause side effects that are not documented in
Python code, however we want references to Python code as well. Therefore
we need some mixed kind of magic for tests.
"""
_GlobalNameSpace.SideEffectContainer.foo = 1
side_effect = get_completion('SideEffectContainer', _GlobalNameSpace.__dict__)
# It's a class that contains MixedObject.
assert isinstance(side_effect._definition.base, mixed.MixedObject)
foo = get_completion('SideEffectContainer.foo', _GlobalNameSpace.__dict__)
assert foo.name == 'foo'
class TestInterpreterAPI(TestCase):
def check_interpreter_complete(self, source, namespace, completions,
**kwds):
script = jedi.Interpreter(source, [namespace], **kwds)
cs = script.completions()
actual = [c.name for c in cs]
self.assertEqual(sorted(actual), sorted(completions))
def test_complete_raw_function(self):
from os.path import join
self.check_interpreter_complete('join("").up',
locals(),
['upper'])
def test_complete_raw_function_different_name(self):
from os.path import join as pjoin
self.check_interpreter_complete('pjoin("").up',
locals(),
['upper'])
def test_complete_raw_module(self):
import os
self.check_interpreter_complete('os.path.join("a").up',
locals(),
['upper'])
def test_complete_raw_instance(self):
import datetime
dt = datetime.datetime(2013, 1, 1)
completions = ['time', 'timetz', 'timetuple']
if is_py33:
completions += ['timestamp']
self.check_interpreter_complete('(dt - dt).ti',
locals(),
completions)
def test_list(self):
array = ['haha', 1]
self.check_interpreter_complete('array[0].uppe',
locals(),
['upper'])
self.check_interpreter_complete('array[0].real',
locals(),
[])
# something different, no index given, still just return the right
self.check_interpreter_complete('array[int].real',
locals(),
['real'])
self.check_interpreter_complete('array[int()].real',
locals(),
['real'])
# inexistent index
self.check_interpreter_complete('array[2].upper',
locals(),
['upper'])
def test_slice(self):
class Foo():
bar = []
baz = 'xbarx'
self.check_interpreter_complete('getattr(Foo, baz[1:-1]).append',
locals(),
['append'])
def test_getitem_side_effects(self):
class Foo():
def __getitem__(self, index):
# possible side effects here, should therefore not call this.
return index
foo = Foo()
self.check_interpreter_complete('foo[0].', locals(), [])
def test_property_error(self):
class Foo():
@property
def bar(self):
raise ValueError
foo = Foo()
self.check_interpreter_complete('foo.bar', locals(), ['bar'])
self.check_interpreter_complete('foo.bar.baz', locals(), [])
def test_param_completion(self):
def foo(bar):
pass
lambd = lambda xyz: 3
self.check_interpreter_complete('foo(bar', locals(), ['bar'])
# TODO we're not yet using the Python3.5 inspect.signature, yet.
assert not jedi.Interpreter('lambd(xyz', [locals()]).completions()

View file

@ -0,0 +1,66 @@
# -*- coding: utf-8 -*-
"""
All character set and unicode related tests.
"""
from jedi import Script
from jedi._compatibility import u, unicode
def test_unicode_script():
""" normally no unicode objects are being used. (<=2.7) """
s = unicode("import datetime; datetime.timedelta")
completions = Script(s).completions()
assert len(completions)
assert type(completions[0].description) is unicode
s = u("author='öä'; author")
completions = Script(s).completions()
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()
assert type(completions[0].description) is unicode
def test_unicode_attribute():
""" github jedi-vim issue #94 """
s1 = u('#-*- coding: utf-8 -*-\nclass Person():\n'
' name = "e"\n\nPerson().name.')
completions1 = Script(s1).completions()
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()
assert 'strip' in [c.name for c in completions2]
def test_multibyte_script():
""" `jedi.Script` must accept multi-byte string source. """
try:
code = u("import datetime; datetime.d")
comment = u("# multi-byte comment あいうえおä")
s = (u('%s\n%s') % (code, comment)).encode('utf-8')
except NameError:
pass # python 3 has no unicode method
else:
assert len(Script(s, 1, len(code)).completions())
def test_goto_definition_at_zero():
"""At zero usually sometimes raises unicode issues."""
assert Script("a", 1, 1).goto_definitions() == []
s = Script("str", 1, 1).goto_definitions()
assert len(s) == 1
assert list(s)[0].description == 'class str'
assert Script("", 1, 0).goto_definitions() == []
def test_complete_at_zero():
s = Script("str", 1, 3).completions()
assert len(s) == 1
assert list(s)[0].name == 'str'
s = Script("", 1, 0).completions()
assert len(s) > 0

View file

@ -0,0 +1,6 @@
import jedi
def test_import_usage():
s = jedi.Script("from .. import foo", line=1, column=18, path="foo.py")
assert [usage.line for usage in s.usages()] == [1]

View file

@ -0,0 +1,109 @@
"""
Test all things related to the ``jedi.cache`` module.
"""
import time
import pytest
import jedi
from jedi import settings, cache
from jedi.parser.utils import ParserCacheItem, ParserPickling
ParserPicklingCls = type(ParserPickling)
ParserPickling = ParserPicklingCls()
def test_modulepickling_change_cache_dir(monkeypatch, tmpdir):
"""
ParserPickling should not save old cache when cache_directory is changed.
See: `#168 <https://github.com/davidhalter/jedi/pull/168>`_
"""
dir_1 = str(tmpdir.mkdir('first'))
dir_2 = str(tmpdir.mkdir('second'))
item_1 = ParserCacheItem('fake parser 1')
item_2 = ParserCacheItem('fake parser 2')
path_1 = 'fake path 1'
path_2 = 'fake path 2'
monkeypatch.setattr(settings, 'cache_directory', dir_1)
ParserPickling.save_parser(path_1, item_1)
cached = load_stored_item(ParserPickling, path_1, item_1)
assert cached == item_1.parser
monkeypatch.setattr(settings, 'cache_directory', dir_2)
ParserPickling.save_parser(path_2, item_2)
cached = load_stored_item(ParserPickling, path_1, item_1)
assert cached is None
def load_stored_item(cache, path, item):
"""Load `item` stored at `path` in `cache`."""
return cache.load_parser(path, item.change_time - 1)
@pytest.mark.usefixtures("isolated_jedi_cache")
def test_modulepickling_delete_incompatible_cache():
item = ParserCacheItem('fake parser')
path = 'fake path'
cache1 = ParserPicklingCls()
cache1.version = 1
cache1.save_parser(path, item)
cached1 = load_stored_item(cache1, path, item)
assert cached1 == item.parser
cache2 = ParserPicklingCls()
cache2.version = 2
cached2 = load_stored_item(cache2, path, item)
assert cached2 is None
@pytest.mark.skipif('True', message='Currently the star import cache is not enabled.')
def test_star_import_cache_duration():
new = 0.01
old, jedi.settings.star_import_cache_validity = \
jedi.settings.star_import_cache_validity, new
dct = cache._time_caches['star_import_cache_validity']
old_dct = dict(dct)
dct.clear() # first empty...
# path needs to be not-None (otherwise caching effects are not visible)
jedi.Script('', 1, 0, '').completions()
time.sleep(2 * new)
jedi.Script('', 1, 0, '').completions()
# reset values
jedi.settings.star_import_cache_validity = old
assert len(dct) == 1
dct = old_dct
cache._star_import_cache = {}
def test_cache_call_signatures():
"""
See github issue #390.
"""
def check(column, call_name, path=None):
assert jedi.Script(s, 1, column, path).call_signatures()[0].name == call_name
s = 'str(int())'
for i in range(3):
check(8, 'int')
check(4, 'str')
# Can keep doing these calls and always get the right result.
# Now lets specify a source_path of boo and alternate these calls, it
# should still work.
for i in range(3):
check(8, 'int', 'boo')
check(4, 'str', 'boo')
def test_cache_line_split_issues():
"""Should still work even if there's a newline."""
assert jedi.Script('int(\n').call_signatures()[0].name == 'int'

View file

@ -0,0 +1,9 @@
import jedi
from jedi import debug
def test_simple():
jedi.set_debug_function()
debug.speed('foo')
debug.dbg('bar')
debug.warning('baz')
jedi.set_debug_function(None, False, False, False)

View file

@ -0,0 +1,14 @@
"""
This is a module that imports the *standard library* unittest,
despite there being a local "unittest" module. It specifies that it
wants the stdlib one with the ``absolute_import`` __future__ import.
The twisted equivalent of this module is ``twisted.trial._synctest``.
"""
from __future__ import absolute_import
import unittest
class Assertions(unittest.TestCase):
pass

View file

@ -0,0 +1,14 @@
"""
This is a module that shadows a builtin (intentionally).
It imports a local module, which in turn imports stdlib unittest (the
name shadowed by this module). If that is properly resolved, there's
no problem. However, if jedi doesn't understand absolute_imports, it
will get this module again, causing infinite recursion.
"""
from local_module import Assertions
class TestCase(Assertions):
def test(self):
self.assertT

View file

@ -0,0 +1,12 @@
#!/usr/bin/python
import sys
sys.path[0:0] = [
'/usr/lib/python3.4/site-packages',
'/tmp/.buildout/eggs/important_package.egg'
]
import important_package
if __name__ == '__main__':
sys.exit(important_package.main())

Some files were not shown because too many files have changed in this diff Show more