forked from VimPlug/jedi
Merge branch 'dev' into unicode_tokenize_fix2
Conflicts: AUTHORS.txt
This commit is contained in:
@@ -338,6 +338,11 @@ tuple((1,))[0]
|
||||
#? []
|
||||
list().__iterable
|
||||
|
||||
# With a list comprehension.
|
||||
for i in set(a for a in [1]):
|
||||
#? int()
|
||||
i
|
||||
|
||||
|
||||
# -----------------
|
||||
# Recursions
|
||||
@@ -352,3 +357,11 @@ def recursion1(foo):
|
||||
|
||||
#? int()
|
||||
recursion1([1,2])[0]
|
||||
|
||||
# -----------------
|
||||
# Merged Arrays
|
||||
# -----------------
|
||||
|
||||
for x in [1] + ['']:
|
||||
#? int() str()
|
||||
x
|
||||
|
||||
@@ -105,6 +105,13 @@ for i in b:
|
||||
#? float() str()
|
||||
a[0]
|
||||
|
||||
for i in [1,2,3]:
|
||||
#? int()
|
||||
i
|
||||
else:
|
||||
i
|
||||
|
||||
|
||||
# -----------------
|
||||
# range()
|
||||
# -----------------
|
||||
@@ -112,115 +119,6 @@ for i in range(10):
|
||||
#? int()
|
||||
i
|
||||
|
||||
# -----------------
|
||||
# list comprehensions
|
||||
# -----------------
|
||||
|
||||
# basics:
|
||||
|
||||
a = ['' for a in [1]]
|
||||
#? str()
|
||||
a[0]
|
||||
|
||||
a = [a for a in [1]]
|
||||
#? int()
|
||||
a[0]
|
||||
|
||||
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() str()
|
||||
a[0]
|
||||
|
||||
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
|
||||
#? str()
|
||||
[a for a in {1:'x'}][0]
|
||||
|
||||
##? str()
|
||||
{a-1:b for a,b in {1:'a', 3:1.0}.items()}[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
|
||||
([str for x in []])[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
|
||||
|
||||
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
|
||||
|
||||
|
||||
# -----------------
|
||||
# ternary operator
|
||||
# -----------------
|
||||
@@ -327,9 +225,10 @@ except ImportError as i_a:
|
||||
try:
|
||||
import math
|
||||
except ImportError, i_b:
|
||||
#? ['i_b']
|
||||
# TODO check this only in Python2
|
||||
##? ['i_b']
|
||||
i_b
|
||||
#? ImportError()
|
||||
##? ImportError()
|
||||
i_b
|
||||
|
||||
|
||||
|
||||
@@ -388,6 +388,8 @@ class PrivateVar():
|
||||
self.__var = 1
|
||||
#? int()
|
||||
self.__var
|
||||
#? ['__var']
|
||||
self.__var
|
||||
#? []
|
||||
PrivateVar().__var
|
||||
#?
|
||||
@@ -448,9 +450,26 @@ class TestX(object):
|
||||
# -----------------
|
||||
|
||||
class A(object):
|
||||
pass
|
||||
a = 3
|
||||
|
||||
#? ['mro']
|
||||
A.mro
|
||||
#? []
|
||||
A().mro
|
||||
|
||||
|
||||
# -----------------
|
||||
# mro resolution
|
||||
# -----------------
|
||||
|
||||
class B(A()):
|
||||
b = 3
|
||||
|
||||
#?
|
||||
B.a
|
||||
#?
|
||||
B().a
|
||||
#? int()
|
||||
B.b
|
||||
#? int()
|
||||
B().b
|
||||
|
||||
125
test/completion/comprehensions.py
Normal file
125
test/completion/comprehensions.py
Normal file
@@ -0,0 +1,125 @@
|
||||
# -----------------
|
||||
# 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() str()
|
||||
a[0]
|
||||
|
||||
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
|
||||
#? str()
|
||||
[a for a in {1:'x'}][0]
|
||||
|
||||
##? str()
|
||||
{a-1:b for a,b in {1:'a', 3:1.0}.items()}[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
|
||||
([str for x in []])[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
|
||||
|
||||
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
|
||||
|
||||
# -----------------
|
||||
# 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
|
||||
@@ -121,7 +121,7 @@ class SelfVars():
|
||||
@Decorator
|
||||
def __init__(self):
|
||||
"""
|
||||
init decorators should be ignored when looking up variables in the
|
||||
__init__ decorators should be ignored when looking up variables in the
|
||||
class.
|
||||
"""
|
||||
self.c = list
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# -----------------
|
||||
# sphinx style
|
||||
# -----------------
|
||||
def f(a, b, c, d, x):
|
||||
def sphinxy(a, b, c, d, x):
|
||||
""" asdfasdf
|
||||
:param a: blablabla
|
||||
:type a: str
|
||||
@@ -27,10 +27,10 @@ def f(a, b, c, d, x):
|
||||
x.lower
|
||||
|
||||
#? dict()
|
||||
f()
|
||||
sphinxy()
|
||||
|
||||
# wrong declarations
|
||||
def f(a, b, x):
|
||||
def sphinxy2(a, b, x):
|
||||
"""
|
||||
:param a: Forgot type declaration
|
||||
:type a:
|
||||
@@ -47,7 +47,7 @@ def f(a, b, x):
|
||||
x
|
||||
|
||||
#?
|
||||
f()
|
||||
sphinxy2()
|
||||
|
||||
# local classes -> github #370
|
||||
class ProgramNode():
|
||||
@@ -104,7 +104,7 @@ return_module_object().join
|
||||
# -----------------
|
||||
# epydoc style
|
||||
# -----------------
|
||||
def e(a, b):
|
||||
def epydoc(a, b):
|
||||
""" asdfasdf
|
||||
@type a: str
|
||||
@param a: blablabla
|
||||
@@ -121,7 +121,7 @@ def e(a, b):
|
||||
b[1]
|
||||
|
||||
#? list()
|
||||
e()
|
||||
epydoc()
|
||||
|
||||
|
||||
# Returns with param type only
|
||||
|
||||
@@ -1,108 +1,6 @@
|
||||
"""
|
||||
This is used for dynamic object completion.
|
||||
Jedi tries to guess the types with a backtracking approach.
|
||||
Checking for ``list.append`` and all the other possible array modifications.
|
||||
"""
|
||||
def func(a):
|
||||
#? 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)
|
||||
|
||||
# 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.append
|
||||
# -----------------
|
||||
@@ -344,13 +242,20 @@ class C():
|
||||
a[0]
|
||||
return a
|
||||
|
||||
def class_arr(self, el):
|
||||
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()
|
||||
@@ -359,7 +264,12 @@ C().blub2(1)[0]
|
||||
#? int()
|
||||
C().a[0]
|
||||
#? int()
|
||||
C().class_arr(1)[0]
|
||||
C().literal_arr(1)[0]
|
||||
|
||||
#? float()
|
||||
C().b[0]
|
||||
#? float()
|
||||
C().list_arr(1.0)[0]
|
||||
|
||||
# -----------------
|
||||
# array recursions
|
||||
@@ -394,14 +304,3 @@ def third():
|
||||
return list(b)
|
||||
#?
|
||||
third()[0]
|
||||
|
||||
# -----------------
|
||||
# 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,)]
|
||||
134
test/completion/dynamic_params.py
Normal file
134
test/completion/dynamic_params.py
Normal 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,)]
|
||||
@@ -266,6 +266,7 @@ class Something():
|
||||
def x(self, a, b=1):
|
||||
return a
|
||||
|
||||
#? int()
|
||||
Something().x(1)
|
||||
|
||||
|
||||
@@ -288,10 +289,15 @@ exe['b']
|
||||
#? int() float()
|
||||
exe['c']
|
||||
|
||||
a = 'a'
|
||||
exe2 = kwargs_func(**{a:3,
|
||||
b:4.0})
|
||||
'b':4.0})
|
||||
#? int()
|
||||
exe2['a']
|
||||
#? float()
|
||||
exe2['b']
|
||||
#? int() float()
|
||||
exe2['c']
|
||||
|
||||
# -----------------
|
||||
# *args / ** kwargs
|
||||
@@ -352,20 +358,20 @@ def nested_kw(**kwargs1):
|
||||
def nested_kw2(**kwargs2):
|
||||
return nested_kw(**kwargs2)
|
||||
|
||||
#? int()
|
||||
# invalid command, doesn't need to return anything
|
||||
#?
|
||||
nested_kw(b=1, c=1.0, list)
|
||||
#? int()
|
||||
nested_kw(b=1)
|
||||
#? int()
|
||||
# invalid command, doesn't need to return anything
|
||||
#?
|
||||
nested_kw(d=1.0, b=1, list)
|
||||
#? int()
|
||||
nested_kw(b=1)
|
||||
#? int()
|
||||
nested_kw(a=3.0, b=1)
|
||||
#? int()
|
||||
nested_kw(b=1, a=r"")
|
||||
#? []
|
||||
nested_kw('')
|
||||
nested_kw(1, '')
|
||||
#? []
|
||||
nested_kw(a='')
|
||||
|
||||
@@ -391,10 +397,12 @@ def nested_both(*args, **kwargs):
|
||||
def nested_both2(*args, **kwargs):
|
||||
return nested_both(*args, **kwargs)
|
||||
|
||||
#? int()
|
||||
# invalid commands, may return whatever.
|
||||
#? list
|
||||
nested_both('', b=1, c=1.0, list)
|
||||
#? int()
|
||||
#? list
|
||||
nested_both('', c=1.0, b=1, list)
|
||||
|
||||
#? []
|
||||
nested_both('')
|
||||
|
||||
@@ -432,23 +440,6 @@ nested_def2('', c=1.0, b=1)[1]
|
||||
#? []
|
||||
nested_def2('')[1]
|
||||
|
||||
# -----------------
|
||||
# function annotations (should be ignored at the moment)
|
||||
# -----------------
|
||||
def annot(a:3, *args:3):
|
||||
return a, args[0]
|
||||
|
||||
#? str()
|
||||
annot('', 1.0)[0]
|
||||
#? float()
|
||||
annot('', 1.0)[1]
|
||||
|
||||
def annot_ret(a:3) -> 3:
|
||||
return a
|
||||
|
||||
#? str()
|
||||
annot_ret('')
|
||||
|
||||
# -----------------
|
||||
# magic methods
|
||||
# -----------------
|
||||
|
||||
@@ -24,6 +24,13 @@ 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
|
||||
|
||||
@@ -93,7 +93,7 @@ ClassVar().x = ''
|
||||
|
||||
# Recurring use of the same var name, github #315
|
||||
def f(t=None):
|
||||
#! 9 ['t = None']
|
||||
#! 9 ['t=None']
|
||||
t = t or 1
|
||||
|
||||
# -----------------
|
||||
@@ -181,13 +181,38 @@ ab1(ClassDef);ab2(ClassDef);ab3(ClassDef)
|
||||
# -----------------
|
||||
|
||||
for i in range(1):
|
||||
#! ['for i in range(1): i']
|
||||
#! ['for i in range(1): i']
|
||||
i
|
||||
|
||||
for key, value in [(1,2)]:
|
||||
#! ['for key,value in [(1, 2)]: key']
|
||||
#! ['for key, value in [(1,2)]: key']
|
||||
key
|
||||
|
||||
for i in []:
|
||||
#! ['for i in []: i']
|
||||
#! ['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
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
a = 1
|
||||
from import_tree.random import a as c
|
||||
|
||||
foobarbaz = 3.0
|
||||
|
||||
@@ -69,16 +69,6 @@ def scope_nested2():
|
||||
#? ['rename1']
|
||||
import_tree.rename1
|
||||
|
||||
def from_names():
|
||||
#? ['mod1']
|
||||
from import_tree.pkg.
|
||||
#? ['path']
|
||||
from os.
|
||||
|
||||
def builtin_test():
|
||||
#? ['math']
|
||||
import math
|
||||
|
||||
def scope_from_import_variable():
|
||||
"""
|
||||
All of them shouldn't work, because "fake" imports don't work in python
|
||||
@@ -97,13 +87,28 @@ def scope_from_import_variable():
|
||||
|
||||
def scope_from_import_variable_with_parenthesis():
|
||||
from import_tree.mod2.fake import (
|
||||
a, c
|
||||
a, foobarbaz
|
||||
)
|
||||
|
||||
#?
|
||||
a
|
||||
#?
|
||||
c
|
||||
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
|
||||
|
||||
# -----------------
|
||||
# std lib modules
|
||||
@@ -121,9 +126,6 @@ import os
|
||||
#? ['dirname']
|
||||
os.path.dirname
|
||||
|
||||
#? os.path.join
|
||||
from os.path import join
|
||||
|
||||
from os.path import (
|
||||
expanduser
|
||||
)
|
||||
@@ -173,28 +175,6 @@ def func_with_import():
|
||||
#? ['sleep']
|
||||
func_with_import().sleep
|
||||
|
||||
# -----------------
|
||||
# completions within imports
|
||||
# -----------------
|
||||
|
||||
#? ['sqlite3']
|
||||
import sqlite3
|
||||
|
||||
#? ['classes']
|
||||
import classes
|
||||
|
||||
#? ['timedelta']
|
||||
from datetime 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
|
||||
|
||||
# -----------------
|
||||
# relative imports
|
||||
# -----------------
|
||||
@@ -231,65 +211,10 @@ from . import datetime as mod1
|
||||
#? []
|
||||
mod1.
|
||||
|
||||
#? str()
|
||||
imp_tree.a
|
||||
|
||||
#? ['some_variable']
|
||||
from . import some_variable
|
||||
#? ['arrays']
|
||||
from . import arrays
|
||||
#? []
|
||||
from . import import_tree as ren
|
||||
|
||||
|
||||
# -----------------
|
||||
# special positions -> edge cases
|
||||
# -----------------
|
||||
import datetime
|
||||
|
||||
#? 6 datetime
|
||||
from datetime.time import time
|
||||
|
||||
#? []
|
||||
import datetime.
|
||||
#? []
|
||||
import datetime.date
|
||||
|
||||
#? 18 ['import']
|
||||
from import_tree. import pkg
|
||||
#? 17 ['mod1', 'mod2', 'random', 'pkg', 'rename1', 'rename2', 'recurse_class1', 'recurse_class2']
|
||||
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 .. import run
|
||||
|
||||
#? []
|
||||
from not_a_module import
|
||||
|
||||
# self import
|
||||
# this can cause recursions
|
||||
from imports 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
|
||||
|
||||
# -----------------
|
||||
# packages
|
||||
# -----------------
|
||||
|
||||
@@ -10,7 +10,7 @@ there should never be any errors.
|
||||
##? 5
|
||||
's'()
|
||||
|
||||
#? ['upper']
|
||||
#? []
|
||||
str()).upper
|
||||
|
||||
# -----------------
|
||||
@@ -19,18 +19,25 @@ str()).upper
|
||||
def asdf(a or b): # multiple param names
|
||||
return a
|
||||
|
||||
#? int()
|
||||
#?
|
||||
asdf(2)
|
||||
|
||||
asdf = ''
|
||||
|
||||
from a import (b
|
||||
def blub():
|
||||
return 0
|
||||
def openbrace():
|
||||
def wrong_indents():
|
||||
asdf = 3
|
||||
asdf
|
||||
asdf(
|
||||
#? int()
|
||||
asdf
|
||||
def openbrace():
|
||||
asdf = 3
|
||||
asdf(
|
||||
#? int()
|
||||
asdf
|
||||
return 1
|
||||
|
||||
#? int()
|
||||
@@ -58,7 +65,7 @@ normalfunc()
|
||||
# dots in param
|
||||
def f(seq1...=None):
|
||||
return seq1
|
||||
#? int()
|
||||
#?
|
||||
f(1)
|
||||
|
||||
@
|
||||
@@ -96,14 +103,17 @@ try:
|
||||
#? str()
|
||||
""
|
||||
|
||||
def break(): pass
|
||||
# wrong ternary expression
|
||||
a = ''
|
||||
a = 1 if
|
||||
#? int()
|
||||
#? str()
|
||||
a
|
||||
|
||||
# No completions for for loops without the right syntax
|
||||
for for_local in :
|
||||
for_local
|
||||
#? ['for_local']
|
||||
#? []
|
||||
for_local
|
||||
#?
|
||||
for_local
|
||||
@@ -122,7 +132,7 @@ a3 = [for xyz in]
|
||||
a3[0]
|
||||
|
||||
a3 = [a4 for in 'b']
|
||||
#? str()
|
||||
#?
|
||||
a3[0]
|
||||
|
||||
a3 = [a4 for a in for x in y]
|
||||
@@ -137,10 +147,10 @@ a[0]
|
||||
|
||||
a = [a for a in [1,2]
|
||||
def break(): pass
|
||||
#? int()
|
||||
#?
|
||||
a[0]
|
||||
|
||||
#? ['real']
|
||||
#? []
|
||||
int()).real
|
||||
|
||||
# -----------------
|
||||
@@ -165,14 +175,39 @@ import datetime as
|
||||
|
||||
call = ''
|
||||
invalid = .call
|
||||
#? str()
|
||||
#?
|
||||
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()
|
||||
|
||||
@@ -55,11 +55,26 @@ a = lambda: 3
|
||||
a.__closure__
|
||||
|
||||
class C():
|
||||
def __init__(self):
|
||||
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):
|
||||
@@ -80,3 +95,12 @@ class Test(object):
|
||||
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]
|
||||
|
||||
104
test/completion/on_import.py
Normal file
104
test/completion/on_import.py
Normal file
@@ -0,0 +1,104 @@
|
||||
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
|
||||
#? 22 ['mod1']
|
||||
from import_tree.pkg. import mod1
|
||||
#? 17 ['mod1', 'mod2', 'random', 'pkg', 'rename1', 'rename2', 'recurse_class1', 'recurse_class2']
|
||||
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
|
||||
|
||||
@@ -89,6 +89,22 @@ 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
|
||||
# -----------------
|
||||
|
||||
@@ -68,6 +68,19 @@ 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
|
||||
# -----------------
|
||||
@@ -108,16 +121,6 @@ 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),
|
||||
b[1]
|
||||
|
||||
|
||||
# -----------------
|
||||
# syntax errors
|
||||
# -----------------
|
||||
|
||||
# strange slice
|
||||
z = sorted([1], key = lambda x : x):
|
||||
#? int()
|
||||
z[0]
|
||||
|
||||
|
||||
# -----------------
|
||||
# undefined names
|
||||
# -----------------
|
||||
|
||||
@@ -47,6 +47,17 @@ arr2.app
|
||||
#? int()
|
||||
arr.count(1)
|
||||
|
||||
x = []
|
||||
#?
|
||||
x.pop()
|
||||
x = [3]
|
||||
#? int()
|
||||
x.pop()
|
||||
x = []
|
||||
x.append(1.0)
|
||||
#? float()
|
||||
x.pop()
|
||||
|
||||
# -----------------
|
||||
# dicts
|
||||
# -----------------
|
||||
|
||||
@@ -3,26 +3,28 @@ 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)
|
||||
#< 4 (0,4), (3,0), (5,0), (17,0)
|
||||
def abc(): pass
|
||||
|
||||
#< 0 (-3,4), (0,0), (2,0)
|
||||
#< 0 (-3,4), (0,0), (2,0), (14,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 =
|
||||
|
||||
#< (-3,0), (0,0)
|
||||
#< (-17,4), (-14,0), (-12,0), (0,0)
|
||||
abc
|
||||
|
||||
abc = 5
|
||||
|
||||
|
||||
Abc = 3
|
||||
|
||||
@@ -47,12 +49,13 @@ class Abc():
|
||||
Abc.d.Abc
|
||||
|
||||
|
||||
#< 4 (0,4), (4,1)
|
||||
def blub():
|
||||
#< 4 (0,4), (5,1)
|
||||
def blubi():
|
||||
pass
|
||||
|
||||
|
||||
#< (-4,4), (0,1)
|
||||
@blub
|
||||
#< (-5,4), (0,1)
|
||||
@blubi
|
||||
def a(): pass
|
||||
|
||||
|
||||
@@ -96,7 +99,7 @@ from import_tree.rename1 import abc
|
||||
#< (0, 32),
|
||||
from import_tree.rename1 import not_existing
|
||||
|
||||
# Shouldn't work (would raise a NotFoundError, because there's no name.)
|
||||
# Shouldn't raise an error or do anything weird.
|
||||
from not_existing import *
|
||||
|
||||
# -----------------
|
||||
@@ -136,6 +139,9 @@ class TestInstanceVar():
|
||||
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():
|
||||
@@ -161,7 +167,7 @@ class Super(object):
|
||||
def base_method(self):
|
||||
#< 13 (0,13), (20,13)
|
||||
self.base_var = 1
|
||||
#< 13 (0,13), (24,13), (29,13)
|
||||
#< 13 (0,13),
|
||||
self.instance_var = 1
|
||||
|
||||
#< 8 (0,8),
|
||||
@@ -190,7 +196,7 @@ class TestClass(Super):
|
||||
|
||||
#< 9 (0,8),
|
||||
def just_a_method(self):
|
||||
#< (-5,13), (0,13), (-29,13)
|
||||
#< (-5,13), (0,13)
|
||||
self.instance_var
|
||||
|
||||
|
||||
|
||||
@@ -276,7 +276,7 @@ def collect_file_tests(lines, lines_to_execute):
|
||||
|
||||
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 a[0] in f_name]
|
||||
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
|
||||
|
||||
@@ -34,7 +34,7 @@ def two_params(x, y):
|
||||
two_params(y=2, x=1)
|
||||
two_params(1, y=2)
|
||||
|
||||
#! 10 type-error-multiple-values
|
||||
#! 11 type-error-multiple-values
|
||||
two_params(1, x=2)
|
||||
#! 17 type-error-too-many-arguments
|
||||
two_params(1, 2, y=3)
|
||||
|
||||
@@ -111,3 +111,9 @@ 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
def generator():
|
||||
yield 1
|
||||
|
||||
#! 11 type-error-generator
|
||||
#! 12 type-error-generator
|
||||
generator()[0]
|
||||
|
||||
list(generator())[0]
|
||||
|
||||
@@ -27,7 +27,7 @@ def nested_twice(*args1):
|
||||
return nested(*args1)
|
||||
|
||||
nested_twice(2, 3)
|
||||
#! 12 type-error-too-few-arguments
|
||||
#! 13 type-error-too-few-arguments
|
||||
nested_twice(2)
|
||||
#! 19 type-error-too-many-arguments
|
||||
nested_twice(2, 3, 4)
|
||||
@@ -47,13 +47,13 @@ def kwargs_test(**kwargs):
|
||||
return simple2(1, **kwargs)
|
||||
|
||||
kwargs_test(c=3, b=2)
|
||||
#! 11 type-error-too-few-arguments
|
||||
#! 12 type-error-too-few-arguments
|
||||
kwargs_test(c=3)
|
||||
#! 11 type-error-too-few-arguments
|
||||
#! 12 type-error-too-few-arguments
|
||||
kwargs_test(b=2)
|
||||
#! 22 type-error-keyword-argument
|
||||
kwargs_test(b=2, c=3, d=4)
|
||||
##! 11 type-error-multiple-values
|
||||
#! 12 type-error-multiple-values
|
||||
kwargs_test(b=2, c=3, a=4)
|
||||
|
||||
|
||||
@@ -65,10 +65,11 @@ kwargs_nested(c=3)
|
||||
kwargs_nested()
|
||||
#! 19 type-error-keyword-argument
|
||||
kwargs_nested(c=2, d=4)
|
||||
##! 13 type-error-multiple-values
|
||||
#! 14 type-error-multiple-values
|
||||
kwargs_nested(c=2, a=4)
|
||||
#! 13 type-error-multiple-values
|
||||
kwargs_nested(b=3, c=2)
|
||||
# TODO reenable
|
||||
##! 14 type-error-multiple-values
|
||||
#kwargs_nested(b=3, c=2)
|
||||
|
||||
# -----------------
|
||||
# mixed *args/**kwargs
|
||||
@@ -77,7 +78,6 @@ kwargs_nested(b=3, c=2)
|
||||
def simple_mixed(a, b, c):
|
||||
return b
|
||||
|
||||
|
||||
def mixed(*args, **kwargs):
|
||||
return simple_mixed(1, *args, **kwargs)
|
||||
|
||||
@@ -91,15 +91,16 @@ def mixed2(*args, **kwargs):
|
||||
return simple_mixed(1, *args, **kwargs)
|
||||
|
||||
|
||||
#! 6 type-error-too-few-arguments
|
||||
#! 7 type-error-too-few-arguments
|
||||
mixed2(c=2)
|
||||
#! 6 type-error-too-few-arguments
|
||||
#! 7 type-error-too-few-arguments
|
||||
mixed2(3)
|
||||
#! 13 type-error-too-many-arguments
|
||||
mixed2(3, 4, 5)
|
||||
#! 13 type-error-too-many-arguments
|
||||
mixed2(3, 4, c=5)
|
||||
#! 6 type-error-multiple-values
|
||||
# TODO reenable
|
||||
##! 13 type-error-too-many-arguments
|
||||
#mixed2(3, 4, c=5)
|
||||
#! 7 type-error-multiple-values
|
||||
mixed2(3, b=5)
|
||||
|
||||
# -----------------
|
||||
@@ -108,6 +109,11 @@ mixed2(3, b=5)
|
||||
|
||||
#! 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)
|
||||
|
||||
@@ -5,6 +5,7 @@ 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
|
||||
|
||||
|
||||
@@ -79,7 +80,10 @@ def test_completion_on_number_literals():
|
||||
def test_completion_on_hex_literals():
|
||||
assert api.Script('0x1..').completions() == []
|
||||
_check_number('0x1.', 'int') # hexdecimal
|
||||
_check_number('0b3.', 'int') # binary
|
||||
# Completing binary literals doesn't work if they are not actually binary
|
||||
# (invalid statements).
|
||||
assert api.Script('0b2.').completions() == []
|
||||
_check_number('0b1.', 'int') # binary
|
||||
_check_number('0o7.', 'int') # octal
|
||||
|
||||
_check_number('0x2e.', 'int')
|
||||
@@ -98,12 +102,19 @@ def test_completion_on_complex_literals():
|
||||
assert api.Script('4j').completions() == []
|
||||
|
||||
|
||||
def test_goto_assignments_on_non_statement():
|
||||
with raises(api.NotFoundError):
|
||||
api.Script('for').goto_assignments()
|
||||
def test_goto_assignments_on_non_name():
|
||||
assert api.Script('for').goto_assignments() == []
|
||||
|
||||
with raises(api.NotFoundError):
|
||||
api.Script('assert').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():
|
||||
|
||||
@@ -95,7 +95,7 @@ def test_function_call_signature_in_doc():
|
||||
pass
|
||||
f""").goto_definitions()
|
||||
doc = defs[0].doc
|
||||
assert "f(x, y = 1, z = 'a')" in str(doc)
|
||||
assert "f(x, y=1, z='a')" in str(doc)
|
||||
|
||||
|
||||
def test_class_call_signature():
|
||||
@@ -105,7 +105,7 @@ def test_class_call_signature():
|
||||
pass
|
||||
Foo""").goto_definitions()
|
||||
doc = defs[0].doc
|
||||
assert "Foo(self, x, y = 1, z = 'a')" in str(doc)
|
||||
assert "Foo(self, x, y=1, z='a')" in str(doc)
|
||||
|
||||
|
||||
def test_position_none_if_builtin():
|
||||
@@ -119,11 +119,21 @@ 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)
|
||||
|
||||
c = Script('import jedi\njedi.Scr').completions()[0]
|
||||
assert c.docstring(raw=True, fast=False) == cleandoc(Script.__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():
|
||||
@@ -148,6 +158,39 @@ def test_signature_params():
|
||||
check(Script(s + '\nbar=foo\nbar').goto_assignments())
|
||||
|
||||
|
||||
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()
|
||||
@@ -179,7 +222,7 @@ class TestParent(TestCase):
|
||||
def bar(): pass
|
||||
Foo().bar''')).completions()[0].parent()
|
||||
assert parent.name == 'Foo'
|
||||
assert parent.type == 'class'
|
||||
assert parent.type == 'instance'
|
||||
|
||||
parent = Script('str.join').completions()[0].parent()
|
||||
assert parent.name == 'str'
|
||||
@@ -219,3 +262,63 @@ class TestGotoAssignments(TestCase):
|
||||
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]
|
||||
assert n.name == 'path'
|
||||
assert n.type == 'import'
|
||||
|
||||
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'
|
||||
|
||||
@@ -22,6 +22,9 @@ class TestCallSignatures(TestCase):
|
||||
def _run_simple(self, source, name, index=0, column=None, line=1):
|
||||
self._run(source, name, index, line, column)
|
||||
|
||||
def test_valid_call(self):
|
||||
self._run('str()', 'str', column=4)
|
||||
|
||||
def test_simple(self):
|
||||
run = self._run_simple
|
||||
s7 = "str().upper().center("
|
||||
@@ -171,6 +174,27 @@ class TestCallSignatures(TestCase):
|
||||
def test_unterminated_strings(self):
|
||||
self._run('str(";', 'str', 0)
|
||||
|
||||
def test_whitespace_before_bracket(self):
|
||||
self._run('str (', 'str', 0)
|
||||
self._run('str (";', 'str', 0)
|
||||
# TODO this is not actually valid Python, the newline token should be
|
||||
# ignored.
|
||||
self._run('str\n(', 'str', 0)
|
||||
|
||||
def test_brackets_in_string_literals(self):
|
||||
self._run('str (" (', 'str', 0)
|
||||
self._run('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 not Script('str(\ndef x').call_signatures()
|
||||
|
||||
def test_flow_call(self):
|
||||
assert not Script('if (1').call_signatures()
|
||||
|
||||
|
||||
class TestParams(TestCase):
|
||||
def params(self, source, line=None, column=None):
|
||||
@@ -277,3 +301,12 @@ def test_signature_index():
|
||||
assert get(both + 'foo(a=2').index == 1
|
||||
assert get(both + 'foo(a=2, b=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)
|
||||
|
||||
@@ -10,10 +10,10 @@ from ..helpers import TestCase
|
||||
|
||||
class TestDefinedNames(TestCase):
|
||||
def assert_definition_names(self, definitions, names):
|
||||
self.assertEqual([d.name for d in definitions], names)
|
||||
assert [d.name for d in definitions] == names
|
||||
|
||||
def check_defined_names(self, source, names):
|
||||
definitions = api.defined_names(textwrap.dedent(source))
|
||||
definitions = api.names(textwrap.dedent(source))
|
||||
self.assert_definition_names(definitions, names)
|
||||
return definitions
|
||||
|
||||
@@ -31,7 +31,7 @@ class TestDefinedNames(TestCase):
|
||||
self.check_defined_names("""
|
||||
x = Class()
|
||||
x.y.z = None
|
||||
""", ['x'])
|
||||
""", ['x', 'z']) # TODO is this behavior what we want?
|
||||
|
||||
def test_multiple_assignment(self):
|
||||
self.check_defined_names("""
|
||||
|
||||
@@ -27,16 +27,14 @@ class MixinTestFullName(object):
|
||||
def check(self, source, desired):
|
||||
script = jedi.Script(textwrap.dedent(source))
|
||||
definitions = getattr(script, type(self).operation)()
|
||||
self.assertEqual(definitions[0].full_name, desired)
|
||||
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('type', 'type')
|
||||
|
||||
def test_from_import(self):
|
||||
self.check('from os import path', 'os.path')
|
||||
self.check('TypeError', 'TypeError')
|
||||
|
||||
|
||||
class TestFullNameWithGotoDefinitions(MixinTestFullName, TestCase):
|
||||
@@ -47,7 +45,10 @@ class TestFullNameWithGotoDefinitions(MixinTestFullName, TestCase):
|
||||
self.check("""
|
||||
import re
|
||||
any_re = re.compile('.*')
|
||||
any_re""", 're.RegexObject')
|
||||
any_re""", '_sre.compile.SRE_Pattern')
|
||||
|
||||
def test_from_import(self):
|
||||
self.check('from os import path', 'os.path')
|
||||
|
||||
|
||||
class TestFullNameWithCompletions(MixinTestFullName, TestCase):
|
||||
|
||||
@@ -67,7 +67,9 @@ def test_star_import_cache_duration():
|
||||
old, jedi.settings.star_import_cache_validity = \
|
||||
jedi.settings.star_import_cache_validity, new
|
||||
|
||||
cache._star_import_cache = {} # first empty...
|
||||
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)
|
||||
@@ -75,7 +77,8 @@ def test_star_import_cache_duration():
|
||||
|
||||
# reset values
|
||||
jedi.settings.star_import_cache_validity = old
|
||||
assert len(cache._star_import_cache) == 1
|
||||
assert len(dct) == 1
|
||||
dct = old_dct
|
||||
cache._star_import_cache = {}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
/path/from/egg-link
|
||||
@@ -4,7 +4,7 @@ Python 2.X)
|
||||
"""
|
||||
import jedi
|
||||
from jedi._compatibility import u
|
||||
from jedi.parser import Parser
|
||||
from jedi.parser import Parser, load_grammar
|
||||
from .. import helpers
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ def test_explicit_absolute_imports():
|
||||
"""
|
||||
Detect modules with ``from __future__ import absolute_import``.
|
||||
"""
|
||||
parser = Parser(u("from __future__ import absolute_import"), "test.py")
|
||||
parser = Parser(load_grammar(), u("from __future__ import absolute_import"), "test.py")
|
||||
assert parser.module.has_explicit_absolute_import
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ def test_no_explicit_absolute_imports():
|
||||
"""
|
||||
Detect modules without ``from __future__ import absolute_import``.
|
||||
"""
|
||||
parser = Parser(u("1"), "test.py")
|
||||
parser = Parser(load_grammar(), u("1"), "test.py")
|
||||
assert not parser.module.has_explicit_absolute_import
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ def test_dont_break_imports_without_namespaces():
|
||||
assume that all imports have non-``None`` namespaces.
|
||||
"""
|
||||
src = u("from __future__ import absolute_import\nimport xyzzy")
|
||||
parser = Parser(src, "test.py")
|
||||
parser = Parser(load_grammar(), src, "test.py")
|
||||
assert parser.module.has_explicit_absolute_import
|
||||
|
||||
|
||||
|
||||
29
test/test_evaluate/test_annotations.py
Normal file
29
test/test_evaluate/test_annotations.py
Normal file
@@ -0,0 +1,29 @@
|
||||
from textwrap import dedent
|
||||
|
||||
import jedi
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.skipif('sys.version_info[0] < 3')
|
||||
def test_simple_annotations():
|
||||
"""
|
||||
Annotations only exist in Python 3.
|
||||
At the moment we ignore them. So they should be parsed and not interfere
|
||||
with anything.
|
||||
"""
|
||||
|
||||
source = dedent("""\
|
||||
def annot(a:3):
|
||||
return a
|
||||
|
||||
annot('')""")
|
||||
|
||||
assert [d.name for d in jedi.Script(source, ).goto_definitions()] == ['str']
|
||||
|
||||
source = dedent("""\
|
||||
|
||||
def annot_ret(a:3) -> 3:
|
||||
return a
|
||||
|
||||
annot_ret('')""")
|
||||
assert [d.name for d in jedi.Script(source, ).goto_definitions()] == ['str']
|
||||
@@ -6,7 +6,7 @@ from jedi.evaluate.sys_path import (_get_parent_dir_with_file,
|
||||
_get_buildout_scripts,
|
||||
_check_module)
|
||||
from jedi.evaluate import Evaluator
|
||||
from jedi.parser import Parser
|
||||
from jedi.parser import Parser, load_grammar
|
||||
|
||||
from ..helpers import cwd_at
|
||||
|
||||
@@ -35,8 +35,9 @@ def test_append_on_non_sys_path():
|
||||
|
||||
d = Dummy()
|
||||
d.path.append('foo')"""))
|
||||
p = Parser(SRC)
|
||||
paths = _check_module(Evaluator(), p.module)
|
||||
grammar = load_grammar()
|
||||
p = Parser(grammar, SRC)
|
||||
paths = _check_module(Evaluator(grammar), p.module)
|
||||
assert len(paths) > 0
|
||||
assert 'foo' not in paths
|
||||
|
||||
@@ -45,8 +46,9 @@ def test_path_from_invalid_sys_path_assignment():
|
||||
SRC = dedent(u("""
|
||||
import sys
|
||||
sys.path = 'invalid'"""))
|
||||
p = Parser(SRC)
|
||||
paths = _check_module(Evaluator(), p.module)
|
||||
grammar = load_grammar()
|
||||
p = Parser(grammar, SRC)
|
||||
paths = _check_module(Evaluator(grammar), p.module)
|
||||
assert len(paths) > 0
|
||||
assert 'invalid' not in paths
|
||||
|
||||
@@ -67,7 +69,8 @@ def test_path_from_sys_path_assignment():
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(important_package.main())"""))
|
||||
p = Parser(SRC)
|
||||
paths = _check_module(Evaluator(), p.module)
|
||||
grammar = load_grammar()
|
||||
p = Parser(grammar, SRC)
|
||||
paths = _check_module(Evaluator(grammar), p.module)
|
||||
assert 1 not in paths
|
||||
assert '/home/test/.buildout/eggs/important_package.egg' in paths
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
from jedi._compatibility import builtins, is_py3
|
||||
from jedi.parser.representation import Function
|
||||
from jedi.parser import load_grammar
|
||||
from jedi.parser.tree import Function
|
||||
from jedi.evaluate import compiled, representation
|
||||
from jedi.evaluate import Evaluator
|
||||
from jedi import Script
|
||||
|
||||
|
||||
def test_simple():
|
||||
e = Evaluator()
|
||||
e = Evaluator(load_grammar())
|
||||
bltn = compiled.CompiledObject(builtins)
|
||||
obj = compiled.CompiledObject('_str_', bltn)
|
||||
upper = e.find_types(obj, 'upper')
|
||||
@@ -17,7 +18,7 @@ def test_simple():
|
||||
|
||||
|
||||
def test_fake_loading():
|
||||
assert isinstance(compiled.create(Evaluator(), next), Function)
|
||||
assert isinstance(compiled.create(Evaluator(load_grammar()), next), Function)
|
||||
|
||||
string = compiled.builtin.get_subscope_by_name('str')
|
||||
from_name = compiled._create_from_name(
|
||||
@@ -29,7 +30,7 @@ def test_fake_loading():
|
||||
|
||||
|
||||
def test_fake_docstr():
|
||||
assert compiled.create(Evaluator(), next).raw_doc == next.__doc__
|
||||
assert compiled.create(Evaluator(load_grammar()), next).raw_doc == next.__doc__
|
||||
|
||||
|
||||
def test_parse_function_doc_illegal_docstr():
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
from jedi._compatibility import unicode
|
||||
|
||||
from jedi.evaluate import helpers
|
||||
from jedi.parser import representation as pr
|
||||
from jedi.parser import Parser
|
||||
|
||||
|
||||
def test_deep_ast_copy():
|
||||
name = pr.Name(object, [('hallo', (0, 0))], (0, 0), (0, 0))
|
||||
|
||||
# fast parent copy should switch parent
|
||||
new_name = helpers.deep_ast_copy(name)
|
||||
assert new_name.names[0].parent == new_name
|
||||
|
||||
|
||||
def test_statement_elements_in_statement():
|
||||
def get_stmt_els(string):
|
||||
p = Parser(unicode(string))
|
||||
return helpers.statement_elements_in_statement(p.module.statements[0])
|
||||
|
||||
# list comprehension
|
||||
stmt_els = get_stmt_els('foo = [(bar(f), f) for f in baz]')
|
||||
# stmt_els: count all names: 6; + count all arrays: 2 = 8
|
||||
assert len(stmt_els) == 8
|
||||
|
||||
# lambda
|
||||
stmt_els = get_stmt_els('foo = [lambda x: y]')
|
||||
# stmt_els: count all names: 3; + count all arrays: 1 = 4
|
||||
assert len(stmt_els) == 4
|
||||
@@ -28,21 +28,11 @@ def test_import_not_in_sys_path():
|
||||
assert a[0].name == 'str'
|
||||
|
||||
|
||||
def setup_function(function):
|
||||
sys.path.append(os.path.join(
|
||||
os.path.dirname(__file__), 'flask-site-packages'))
|
||||
|
||||
|
||||
def teardown_function(function):
|
||||
path = os.path.join(os.path.dirname(__file__), 'flask-site-packages')
|
||||
sys.path.remove(path)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("script,name", [
|
||||
("from flask.ext import foo; foo.", "Foo"), # flask_foo.py
|
||||
("from flask.ext import bar; bar.", "Bar"), # flaskext/bar.py
|
||||
("from flask.ext import baz; baz.", "Baz"), # flask_baz/__init__.py
|
||||
("from flask.ext import moo; moo.", "Moo"), # flaskext/moo/__init__.py
|
||||
("from flask.ext import foo; foo.", "Foo"), # flask_foo.py
|
||||
("from flask.ext import bar; bar.", "Bar"), # flaskext/bar.py
|
||||
("from flask.ext import baz; baz.", "Baz"), # flask_baz/__init__.py
|
||||
("from flask.ext import moo; moo.", "Moo"), # flaskext/moo/__init__.py
|
||||
("from flask.ext.", "foo"),
|
||||
("from flask.ext.", "bar"),
|
||||
("from flask.ext.", "baz"),
|
||||
@@ -55,5 +45,9 @@ def teardown_function(function):
|
||||
def test_flask_ext(script, name):
|
||||
"""flask.ext.foo is really imported from flaskext.foo or flask_foo.
|
||||
"""
|
||||
assert name in [c.name for c in jedi.Script(script).completions()]
|
||||
|
||||
path = os.path.join(os.path.dirname(__file__), 'flask-site-packages')
|
||||
sys.path.append(path)
|
||||
try:
|
||||
assert name in [c.name for c in jedi.Script(script).completions()]
|
||||
finally:
|
||||
sys.path.remove(path)
|
||||
|
||||
@@ -29,9 +29,11 @@ def test_namespace_package():
|
||||
# completion
|
||||
completions = jedi.Script('from pkg import ').completions()
|
||||
names = [str(c.name) for c in completions] # str because of unicode
|
||||
compare = ['foo', 'ns1_file', 'ns1_folder', 'ns2_folder', 'ns2_file']
|
||||
compare = ['foo', 'ns1_file', 'ns1_folder', 'ns2_folder', 'ns2_file',
|
||||
'pkg_resources', 'pkgutil', '__name__', '__path__',
|
||||
'__package__', '__file__', '__doc__']
|
||||
# must at least contain these items, other items are not important
|
||||
assert not (set(compare) - set(names))
|
||||
assert set(compare) == set(names)
|
||||
|
||||
tests = {
|
||||
'from pkg import ns2_folder as x': 'ns2_folder!',
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
from jedi._compatibility import u
|
||||
from jedi.parser import Parser
|
||||
from jedi.evaluate import precedence
|
||||
|
||||
|
||||
def parse_tree(statement_string, is_slice=False):
|
||||
p = Parser(u(statement_string), no_docstr=True)
|
||||
stmt = p.module.statements[0]
|
||||
if is_slice:
|
||||
# get the part of the execution that is the slice
|
||||
stmt = stmt.expression_list()[0].next[0]
|
||||
iterable = stmt.expression_list()
|
||||
pr = precedence.create_precedence(iterable)
|
||||
if isinstance(pr, precedence.Precedence):
|
||||
return pr.parse_tree(strip_literals=True)
|
||||
else:
|
||||
try:
|
||||
return pr.value # Literal
|
||||
except AttributeError:
|
||||
return pr
|
||||
|
||||
|
||||
def test_simple():
|
||||
assert parse_tree('1+2') == (1, '+', 2)
|
||||
assert parse_tree('+2') == (None, '+', 2)
|
||||
assert parse_tree('1+2-3') == ((1, '+', 2), '-', 3)
|
||||
|
||||
|
||||
def test_prefixed():
|
||||
assert parse_tree('--2') == (None, '-', (None, '-', 2))
|
||||
assert parse_tree('1 and not - 2') == (1, 'and', (None, 'not', (None, '-', 2)))
|
||||
|
||||
|
||||
def test_invalid():
|
||||
"""Should just return a simple operation."""
|
||||
assert parse_tree('1 +') == 1
|
||||
assert parse_tree('+') is None
|
||||
|
||||
assert parse_tree('* 1') == 1
|
||||
assert parse_tree('1 * * 1') == (1, '*', 1)
|
||||
|
||||
# invalid operator
|
||||
assert parse_tree('1 not - 1') == (1, '-', 1)
|
||||
assert parse_tree('1 - not ~1') == (1, '-', (None, '~', 1))
|
||||
|
||||
# not not allowed
|
||||
assert parse_tree('1 is not not 1') == (1, 'is not', 1)
|
||||
|
||||
|
||||
def test_multi_part():
|
||||
assert parse_tree('1 not in 2') == (1, 'not in', 2)
|
||||
assert parse_tree('1 is not -1') == (1, 'is not', (None, '-', 1))
|
||||
assert parse_tree('1 is 1') == (1, 'is', 1)
|
||||
|
||||
|
||||
def test_power():
|
||||
assert parse_tree('2 ** 3 ** 4') == (2, '**', (3, '**', 4))
|
||||
|
||||
|
||||
def test_slice():
|
||||
"""
|
||||
Should be parsed as normal operators. This is not proper Python syntax,
|
||||
but the warning shouldn't be given in the precedence generation.
|
||||
"""
|
||||
assert parse_tree('[0][2+1:3]', is_slice=True) == ((2, '+', 1), ':', 3)
|
||||
assert parse_tree('[0][:]', is_slice=True) == (None, ':', None)
|
||||
assert parse_tree('[0][1:]', is_slice=True) == (1, ':', None)
|
||||
assert parse_tree('[0][:2]', is_slice=True) == (None, ':', 2)
|
||||
|
||||
# 3 part slice
|
||||
assert parse_tree('[0][:2:1]', is_slice=True) == ((None, ':', 2), ':', 1)
|
||||
@@ -5,7 +5,7 @@ from jedi import Script
|
||||
|
||||
def get_definition_and_evaluator(source):
|
||||
d = Script(dedent(source)).goto_definitions()[0]
|
||||
return d._name.parent.parent, d._evaluator
|
||||
return d._name.parent, d._evaluator
|
||||
|
||||
|
||||
def test_function_execution():
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import os
|
||||
|
||||
from jedi._compatibility import unicode
|
||||
from jedi.parser import Parser
|
||||
from jedi.parser import Parser, load_grammar
|
||||
from jedi.evaluate import sys_path, Evaluator
|
||||
|
||||
|
||||
def test_paths_from_assignment():
|
||||
def paths(src):
|
||||
stmt = Parser(unicode(src)).module.statements[0]
|
||||
return list(sys_path._paths_from_assignment(Evaluator(), stmt))
|
||||
grammar = load_grammar()
|
||||
stmt = Parser(grammar, unicode(src)).module.statements[0]
|
||||
return list(sys_path._paths_from_assignment(Evaluator(grammar), stmt))
|
||||
|
||||
assert paths('sys.path[0:0] = ["a"]') == ['a']
|
||||
assert paths('sys.path = ["b", 1, x + 3, y, "c"]') == ['b', 'c']
|
||||
@@ -14,3 +17,15 @@ def test_paths_from_assignment():
|
||||
|
||||
# Fail for complicated examples.
|
||||
assert paths('sys.path, other = ["a"], 2') == []
|
||||
|
||||
|
||||
def test_get_sys_path(monkeypatch):
|
||||
monkeypatch.setenv('VIRTUAL_ENV', os.path.join(os.path.dirname(__file__),
|
||||
'egg-link', 'venv'))
|
||||
def sitepackages_dir(venv):
|
||||
return os.path.join(venv, 'lib', 'python3.4', 'site-packages')
|
||||
|
||||
monkeypatch.setattr('jedi.evaluate.sys_path._get_venv_sitepackages',
|
||||
sitepackages_dir)
|
||||
|
||||
assert '/path/from/egg-link' in sys_path.get_sys_path()
|
||||
|
||||
@@ -16,11 +16,22 @@ def test_goto_definition_on_import():
|
||||
|
||||
@cwd_at('jedi')
|
||||
def test_complete_on_empty_import():
|
||||
assert Script("from datetime import").completions()[0].name == 'import'
|
||||
# should just list the files in the directory
|
||||
assert 10 < len(Script("from .", path='').completions()) < 30
|
||||
assert 10 < len(Script("from . import", 1, 5, '').completions()) < 30
|
||||
assert 10 < len(Script("from . import classes", 1, 5, '').completions()) < 30
|
||||
assert len(Script("import").completions()) == 0
|
||||
|
||||
# Global import
|
||||
assert len(Script("from . import", 1, 5, '').completions()) > 30
|
||||
# relative import
|
||||
assert 10 < len(Script("from . import", 1, 6, '').completions()) < 30
|
||||
|
||||
# Global import
|
||||
assert len(Script("from . import classes", 1, 5, '').completions()) > 30
|
||||
# relative import
|
||||
assert 10 < len(Script("from . import classes", 1, 6, '').completions()) < 30
|
||||
|
||||
wanted = set(['ImportError', 'import', 'ImportWarning'])
|
||||
assert set([c.name for c in Script("import").completions()]) == wanted
|
||||
if not is_py26: # python 2.6 doesn't always come with a library `import*`.
|
||||
assert len(Script("import import", path='').completions()) > 0
|
||||
|
||||
@@ -63,6 +74,7 @@ def test_after_from():
|
||||
completions = Script(source, column=column).completions()
|
||||
assert [c.name for c in completions] == result
|
||||
|
||||
check('\nfrom os. ', ['path'])
|
||||
check('\nfrom os ', ['import'])
|
||||
check('from os ', ['import'])
|
||||
check('\nfrom os import whatever', ['import'], len('from os im'))
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
"""
|
||||
Test of keywords and ``jedi.keywords``
|
||||
"""
|
||||
import jedi
|
||||
from jedi import Script, common
|
||||
import pytest
|
||||
from jedi._compatibility import is_py3
|
||||
from jedi import Script
|
||||
|
||||
|
||||
def test_goto_assignments_keyword():
|
||||
@@ -18,13 +17,13 @@ def test_goto_assignments_keyword():
|
||||
def test_keyword():
|
||||
""" github jedi-vim issue #44 """
|
||||
defs = Script("print").goto_definitions()
|
||||
assert [d.doc for d in defs]
|
||||
if is_py3:
|
||||
assert [d.doc for d in defs]
|
||||
else:
|
||||
assert defs == []
|
||||
|
||||
with pytest.raises(jedi.NotFoundError):
|
||||
Script("import").goto_assignments()
|
||||
assert Script("import").goto_assignments() == []
|
||||
|
||||
completions = Script("import", 1, 1).completions()
|
||||
assert len(completions) == 0
|
||||
with common.ignored(jedi.NotFoundError): # TODO shouldn't throw that.
|
||||
defs = Script("assert").goto_definitions()
|
||||
assert len(defs) == 1
|
||||
assert len(completions) > 10 and 'if' in [c.name for c in completions]
|
||||
assert Script("assert").goto_definitions() == []
|
||||
|
||||
13
test/test_new_parser.py
Normal file
13
test/test_new_parser.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from jedi._compatibility import u
|
||||
from jedi.parser import Parser, load_grammar
|
||||
|
||||
|
||||
def test_basic_parsing():
|
||||
def compare(string):
|
||||
"""Generates the AST object and then regenerates the code."""
|
||||
assert Parser(load_grammar(), string).module.get_code() == string
|
||||
|
||||
compare(u('\na #pass\n'))
|
||||
compare(u('wblabla* 1\t\n'))
|
||||
compare(u('def x(a, b:3): pass\n'))
|
||||
compare(u('assert foo\n'))
|
||||
@@ -3,6 +3,7 @@ from textwrap import dedent
|
||||
import jedi
|
||||
from jedi._compatibility import u
|
||||
from jedi import cache
|
||||
from jedi.parser import load_grammar
|
||||
from jedi.parser.fast import FastParser
|
||||
|
||||
|
||||
@@ -12,15 +13,15 @@ def test_add_to_end():
|
||||
help of caches, this is an example that didn't work.
|
||||
"""
|
||||
|
||||
a = """
|
||||
class Abc():
|
||||
def abc(self):
|
||||
self.x = 3
|
||||
a = dedent("""
|
||||
class Abc():
|
||||
def abc(self):
|
||||
self.x = 3
|
||||
|
||||
class Two(Abc):
|
||||
def h(self):
|
||||
self
|
||||
""" # ^ here is the first completion
|
||||
class Two(Abc):
|
||||
def h(self):
|
||||
self
|
||||
""") # ^ here is the first completion
|
||||
|
||||
b = " def g(self):\n" \
|
||||
" self."
|
||||
@@ -54,30 +55,369 @@ def test_carriage_return_splitting():
|
||||
pass
|
||||
'''))
|
||||
source = source.replace('\n', '\r\n')
|
||||
p = FastParser(source)
|
||||
assert [str(n) for n in p.module.get_defined_names()] == ['Foo']
|
||||
p = FastParser(load_grammar(), source)
|
||||
assert [n.value for lst in p.module.names_dict.values() for n in lst] == ['Foo']
|
||||
|
||||
|
||||
def test_split_parts():
|
||||
cache.parser_cache.pop(None, None)
|
||||
|
||||
def splits(source):
|
||||
class Mock(FastParser):
|
||||
def __init__(self, *args):
|
||||
self.number_of_splits = 0
|
||||
|
||||
return tuple(FastParser._split_parts(Mock(None, None), source))
|
||||
|
||||
def test(*parts):
|
||||
assert splits(''.join(parts)) == parts
|
||||
|
||||
test('a\n\n', 'def b(): pass\n', 'c\n')
|
||||
test('a\n', 'def b():\n pass\n', 'c\n')
|
||||
|
||||
|
||||
def check_fp(src, number_parsers_used, number_of_splits=None, number_of_misses=0):
|
||||
if number_of_splits is None:
|
||||
number_of_splits = number_parsers_used
|
||||
|
||||
p = FastParser(load_grammar(), u(src))
|
||||
cache.save_parser(None, None, p, pickling=False)
|
||||
|
||||
# TODO Don't change get_code, the whole thing should be the same.
|
||||
# -> Need to refactor the parser first, though.
|
||||
assert src == p.module.get_code()
|
||||
assert p.number_of_splits == number_of_splits
|
||||
assert p.number_parsers_used == number_parsers_used
|
||||
assert p.number_of_misses == number_of_misses
|
||||
return p.module
|
||||
|
||||
|
||||
def test_change_and_undo():
|
||||
|
||||
def fp(src):
|
||||
p = FastParser(u(src))
|
||||
cache.save_parser(None, None, p, pickling=False)
|
||||
|
||||
# TODO Don't change get_code, the whole thing should be the same.
|
||||
# -> Need to refactor the parser first, though.
|
||||
assert src == p.module.get_code()[:-1]
|
||||
|
||||
# Empty the parser cache for the path None.
|
||||
cache.parser_cache.pop(None, None)
|
||||
func_before = 'def func():\n pass\n'
|
||||
fp(func_before + 'a')
|
||||
fp(func_before + 'b')
|
||||
fp(func_before + 'a')
|
||||
# Parse the function and a.
|
||||
check_fp(func_before + 'a', 2)
|
||||
# Parse just b.
|
||||
check_fp(func_before + 'b', 1, 2)
|
||||
# b has changed to a again, so parse that.
|
||||
check_fp(func_before + 'a', 1, 2)
|
||||
# Same as before no parsers should be used.
|
||||
check_fp(func_before + 'a', 0, 2)
|
||||
|
||||
# Getting rid of an old parser: Still no parsers used.
|
||||
check_fp('a', 0, 1)
|
||||
# Now the file has completely change and we need to parse.
|
||||
check_fp('b', 1, 1)
|
||||
# And again.
|
||||
check_fp('a', 1, 1)
|
||||
|
||||
|
||||
def test_positions():
|
||||
# Empty the parser cache for the path None.
|
||||
cache.parser_cache.pop(None, None)
|
||||
fp('a')
|
||||
fp('b')
|
||||
fp('a')
|
||||
|
||||
func_before = 'class A:\n pass\n'
|
||||
m = check_fp(func_before + 'a', 2)
|
||||
assert m.start_pos == (1, 0)
|
||||
assert m.end_pos == (3, 1)
|
||||
|
||||
m = check_fp('a', 0, 1)
|
||||
assert m.start_pos == (1, 0)
|
||||
assert m.end_pos == (1, 1)
|
||||
|
||||
|
||||
def test_if():
|
||||
src = dedent('''\
|
||||
def func():
|
||||
x = 3
|
||||
if x:
|
||||
def y():
|
||||
return x
|
||||
return y()
|
||||
|
||||
func()
|
||||
''')
|
||||
|
||||
# Two parsers needed, one for pass and one for the function.
|
||||
check_fp(src, 2)
|
||||
assert [d.name for d in jedi.Script(src, 8, 6).goto_definitions()] == ['int']
|
||||
|
||||
|
||||
def test_if_simple():
|
||||
src = dedent('''\
|
||||
if 1:
|
||||
a = 3
|
||||
''')
|
||||
check_fp(src + 'a', 1)
|
||||
check_fp(src + "else:\n a = ''\na", 1)
|
||||
|
||||
|
||||
def test_for():
|
||||
src = dedent("""\
|
||||
for a in [1,2]:
|
||||
a
|
||||
|
||||
for a1 in 1,"":
|
||||
a1
|
||||
""")
|
||||
check_fp(src, 1)
|
||||
|
||||
|
||||
def test_class_with_class_var():
|
||||
src = dedent("""\
|
||||
class SuperClass:
|
||||
class_super = 3
|
||||
def __init__(self):
|
||||
self.foo = 4
|
||||
pass
|
||||
""")
|
||||
check_fp(src, 3)
|
||||
|
||||
|
||||
def test_func_with_if():
|
||||
src = dedent("""\
|
||||
def recursion(a):
|
||||
if foo:
|
||||
return recursion(a)
|
||||
else:
|
||||
if bar:
|
||||
return inexistent
|
||||
else:
|
||||
return a
|
||||
""")
|
||||
check_fp(src, 1)
|
||||
|
||||
|
||||
def test_decorator():
|
||||
src = dedent("""\
|
||||
class Decorator():
|
||||
@memoize
|
||||
def dec(self, a):
|
||||
return a
|
||||
""")
|
||||
check_fp(src, 2)
|
||||
|
||||
|
||||
def test_nested_funcs():
|
||||
src = dedent("""\
|
||||
def memoize(func):
|
||||
def wrapper(*args, **kwargs):
|
||||
return func(*args, **kwargs)
|
||||
return wrapper
|
||||
""")
|
||||
check_fp(src, 3)
|
||||
|
||||
|
||||
def test_class_and_if():
|
||||
src = dedent("""\
|
||||
class V:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
if 1:
|
||||
c = 3
|
||||
|
||||
def a_func():
|
||||
return 1
|
||||
|
||||
# COMMENT
|
||||
a_func()""")
|
||||
check_fp(src, 5, 5)
|
||||
assert [d.name for d in jedi.Script(src).goto_definitions()] == ['int']
|
||||
|
||||
|
||||
def test_func_with_for_and_comment():
|
||||
# The first newline is important, leave it. It should not trigger another
|
||||
# parser split.
|
||||
src = dedent("""\
|
||||
|
||||
def func():
|
||||
pass
|
||||
|
||||
|
||||
for a in [1]:
|
||||
# COMMENT
|
||||
a""")
|
||||
check_fp(src, 2)
|
||||
# We don't need to parse the for loop, but we need to parse the other two,
|
||||
# because the split is in a different place.
|
||||
check_fp('a\n' + src, 2, 3)
|
||||
|
||||
|
||||
def test_multi_line_params():
|
||||
src = dedent("""\
|
||||
def x(a,
|
||||
b):
|
||||
pass
|
||||
|
||||
foo = 1
|
||||
""")
|
||||
check_fp(src, 2)
|
||||
|
||||
|
||||
def test_one_statement_func():
|
||||
src = dedent("""\
|
||||
first
|
||||
def func(): a
|
||||
""")
|
||||
check_fp(src + 'second', 3)
|
||||
# Empty the parser cache, because we're not interested in modifications
|
||||
# here.
|
||||
cache.parser_cache.pop(None, None)
|
||||
check_fp(src + 'def second():\n a', 3)
|
||||
|
||||
|
||||
def test_class_func_if():
|
||||
src = dedent("""\
|
||||
class Class:
|
||||
def func(self):
|
||||
if 1:
|
||||
a
|
||||
else:
|
||||
b
|
||||
|
||||
pass
|
||||
""")
|
||||
check_fp(src, 3)
|
||||
|
||||
|
||||
def test_for_on_one_line():
|
||||
src = dedent("""\
|
||||
foo = 1
|
||||
for x in foo: pass
|
||||
|
||||
def hi():
|
||||
pass
|
||||
""")
|
||||
check_fp(src, 2)
|
||||
|
||||
src = dedent("""\
|
||||
def hi():
|
||||
for x in foo: pass
|
||||
pass
|
||||
|
||||
pass
|
||||
""")
|
||||
check_fp(src, 2)
|
||||
|
||||
src = dedent("""\
|
||||
def hi():
|
||||
for x in foo: pass
|
||||
|
||||
def nested():
|
||||
pass
|
||||
""")
|
||||
check_fp(src, 2)
|
||||
|
||||
|
||||
def test_multi_line_for():
|
||||
src = dedent("""\
|
||||
for x in [1,
|
||||
2]:
|
||||
pass
|
||||
|
||||
pass
|
||||
""")
|
||||
check_fp(src, 1)
|
||||
|
||||
|
||||
def test_wrong_indentation():
|
||||
src = dedent("""\
|
||||
def func():
|
||||
a
|
||||
b
|
||||
a
|
||||
""")
|
||||
check_fp(src, 1)
|
||||
|
||||
src = dedent("""\
|
||||
def complex():
|
||||
def nested():
|
||||
a
|
||||
b
|
||||
a
|
||||
|
||||
def other():
|
||||
pass
|
||||
""")
|
||||
check_fp(src, 3)
|
||||
|
||||
|
||||
def test_open_parentheses():
|
||||
func = 'def func():\n a'
|
||||
p = FastParser(load_grammar(), u('isinstance(\n\n' + func))
|
||||
# As you can see, the isinstance call cannot be seen anymore after
|
||||
# get_code, because it isn't valid code.
|
||||
assert p.module.get_code() == '\n\n' + func
|
||||
assert p.number_of_splits == 2
|
||||
assert p.number_parsers_used == 2
|
||||
cache.save_parser(None, None, p, pickling=False)
|
||||
|
||||
# Now with a correct parser it should work perfectly well.
|
||||
check_fp('isinstance()\n' + func, 1, 2)
|
||||
|
||||
|
||||
def test_strange_parentheses():
|
||||
src = dedent("""
|
||||
class X():
|
||||
a = (1
|
||||
if 1 else 2)
|
||||
def x():
|
||||
pass
|
||||
""")
|
||||
check_fp(src, 2)
|
||||
|
||||
|
||||
def test_backslash():
|
||||
src = dedent(r"""
|
||||
a = 1\
|
||||
if 1 else 2
|
||||
def x():
|
||||
pass
|
||||
""")
|
||||
check_fp(src, 2)
|
||||
|
||||
src = dedent(r"""
|
||||
def x():
|
||||
a = 1\
|
||||
if 1 else 2
|
||||
def y():
|
||||
pass
|
||||
""")
|
||||
# The dangling if leads to not splitting where we theoretically could
|
||||
# split.
|
||||
check_fp(src, 2)
|
||||
|
||||
src = dedent(r"""
|
||||
def first():
|
||||
if foo \
|
||||
and bar \
|
||||
or baz:
|
||||
pass
|
||||
def second():
|
||||
pass
|
||||
""")
|
||||
check_fp(src, 2)
|
||||
|
||||
|
||||
|
||||
def test_fake_parentheses():
|
||||
"""
|
||||
The fast parser splitting counts parentheses, but not as correct tokens.
|
||||
Therefore parentheses in string tokens are included as well. This needs to
|
||||
be accounted for.
|
||||
"""
|
||||
src = dedent(r"""
|
||||
def x():
|
||||
a = (')'
|
||||
if 1 else 2)
|
||||
def y():
|
||||
pass
|
||||
def z():
|
||||
pass
|
||||
""")
|
||||
check_fp(src, 3, 2, 1)
|
||||
|
||||
|
||||
def test_incomplete_function():
|
||||
|
||||
@@ -3,7 +3,7 @@ import difflib
|
||||
import pytest
|
||||
|
||||
from jedi._compatibility import u
|
||||
from jedi.parser import Parser
|
||||
from jedi.parser import Parser, load_grammar
|
||||
|
||||
code_basic_features = u('''
|
||||
"""A mod docstring"""
|
||||
@@ -44,21 +44,19 @@ def diff_code_assert(a, b, n=4):
|
||||
def test_basic_parsing():
|
||||
"""Validate the parsing features"""
|
||||
|
||||
prs = Parser(code_basic_features)
|
||||
prs = Parser(load_grammar(), code_basic_features)
|
||||
diff_code_assert(
|
||||
code_basic_features,
|
||||
prs.module.get_code2()
|
||||
prs.module.get_code()
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.skipif('True', reason='Not yet working.')
|
||||
def test_operators():
|
||||
src = u('5 * 3')
|
||||
prs = Parser(src)
|
||||
prs = Parser(load_grammar(), src)
|
||||
diff_code_assert(src, prs.module.get_code())
|
||||
|
||||
|
||||
@pytest.mark.skipif('True', reason='Broke get_code support for yield/return statements.')
|
||||
def test_get_code():
|
||||
"""Use the same code that the parser also generates, to compare"""
|
||||
s = u('''"""a docstring"""
|
||||
@@ -84,4 +82,24 @@ def method_with_docstring():
|
||||
"""class docstr"""
|
||||
pass
|
||||
''')
|
||||
assert Parser(s).module.get_code() == s
|
||||
assert Parser(load_grammar(), s).module.get_code() == s
|
||||
|
||||
|
||||
def test_end_newlines():
|
||||
"""
|
||||
The Python grammar explicitly needs a newline at the end. Jedi though still
|
||||
wants to be able, to return the exact same code without the additional new
|
||||
line the parser needs.
|
||||
"""
|
||||
def test(source, end_pos):
|
||||
module = Parser(load_grammar(), u(source)).module
|
||||
assert module.get_code() == source
|
||||
assert module.end_pos == end_pos
|
||||
|
||||
test('a', (1, 1))
|
||||
test('a\n', (2, 0))
|
||||
test('a\nb', (2, 1))
|
||||
test('a\n#comment\n', (3, 0))
|
||||
test('a\n#comment', (2, 8))
|
||||
test('a#comment', (1, 9))
|
||||
test('def a():\n pass', (2, 5))
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import jedi
|
||||
from jedi._compatibility import u, is_py3
|
||||
from jedi.parser import Parser
|
||||
from jedi.parser import Parser, load_grammar
|
||||
from jedi.parser.user_context import UserContextParser
|
||||
from jedi.parser import representation as pr
|
||||
from jedi.parser import tree as pt
|
||||
from textwrap import dedent
|
||||
|
||||
|
||||
@@ -13,50 +14,50 @@ def test_user_statement_on_import():
|
||||
" time)")
|
||||
|
||||
for pos in [(2, 1), (2, 4)]:
|
||||
p = UserContextParser(s, None, pos, None).user_stmt()
|
||||
assert isinstance(p, pr.Import)
|
||||
assert p.defunct is False
|
||||
p = UserContextParser(load_grammar(), s, None, pos, None).user_stmt()
|
||||
assert isinstance(p, pt.Import)
|
||||
assert [str(n) for n in p.get_defined_names()] == ['time']
|
||||
|
||||
|
||||
class TestCallAndName():
|
||||
def get_call(self, source):
|
||||
stmt = Parser(u(source), no_docstr=True).module.statements[0]
|
||||
return stmt.expression_list()[0]
|
||||
# Get the simple_stmt and then the first one.
|
||||
simple_stmt = Parser(load_grammar(), u(source)).module.children[0]
|
||||
return simple_stmt.children[0]
|
||||
|
||||
def test_name_and_call_positions(self):
|
||||
call = self.get_call('name\nsomething_else')
|
||||
assert str(call.name) == 'name'
|
||||
assert call.name.start_pos == call.start_pos == (1, 0)
|
||||
assert call.name.end_pos == call.end_pos == (1, 4)
|
||||
name = self.get_call('name\nsomething_else')
|
||||
assert str(name) == 'name'
|
||||
assert name.start_pos == (1, 0)
|
||||
assert name.end_pos == (1, 4)
|
||||
|
||||
call = self.get_call('1.0\n')
|
||||
assert call.value == 1.0
|
||||
assert call.start_pos == (1, 0)
|
||||
assert call.end_pos == (1, 3)
|
||||
leaf = self.get_call('1.0\n')
|
||||
assert leaf.value == '1.0'
|
||||
assert leaf.eval() == 1.0
|
||||
assert leaf.start_pos == (1, 0)
|
||||
assert leaf.end_pos == (1, 3)
|
||||
|
||||
def test_call_type(self):
|
||||
call = self.get_call('hello')
|
||||
assert isinstance(call, pr.Call)
|
||||
assert type(call.name) == pr.Name
|
||||
assert isinstance(call, pt.Name)
|
||||
|
||||
def test_literal_type(self):
|
||||
literal = self.get_call('1.0')
|
||||
assert isinstance(literal, pr.Literal)
|
||||
assert type(literal.value) == float
|
||||
assert isinstance(literal, pt.Literal)
|
||||
assert type(literal.eval()) == float
|
||||
|
||||
literal = self.get_call('1')
|
||||
assert isinstance(literal, pr.Literal)
|
||||
assert type(literal.value) == int
|
||||
assert isinstance(literal, pt.Literal)
|
||||
assert type(literal.eval()) == int
|
||||
|
||||
literal = self.get_call('"hello"')
|
||||
assert isinstance(literal, pr.Literal)
|
||||
assert literal.value == 'hello'
|
||||
assert isinstance(literal, pt.Literal)
|
||||
assert literal.eval() == 'hello'
|
||||
|
||||
|
||||
class TestSubscopes():
|
||||
def get_sub(self, source):
|
||||
return Parser(u(source)).module.subscopes[0]
|
||||
return Parser(load_grammar(), u(source)).module.subscopes[0]
|
||||
|
||||
def test_subscope_names(self):
|
||||
name = self.get_sub('class Foo: pass').name
|
||||
@@ -72,7 +73,7 @@ class TestSubscopes():
|
||||
|
||||
class TestImports():
|
||||
def get_import(self, source):
|
||||
return Parser(source).module.imports[0]
|
||||
return Parser(load_grammar(), source).module.imports[0]
|
||||
|
||||
def test_import_names(self):
|
||||
imp = self.get_import(u('import math\n'))
|
||||
@@ -87,13 +88,13 @@ class TestImports():
|
||||
|
||||
|
||||
def test_module():
|
||||
module = Parser(u('asdf'), 'example.py', no_docstr=True).module
|
||||
module = Parser(load_grammar(), u('asdf'), 'example.py').module
|
||||
name = module.name
|
||||
assert str(name) == 'example'
|
||||
assert name.start_pos == (1, 0)
|
||||
assert name.end_pos == (1, 7)
|
||||
|
||||
module = Parser(u('asdf'), no_docstr=True).module
|
||||
module = Parser(load_grammar(), u('asdf')).module
|
||||
name = module.name
|
||||
assert str(name) == ''
|
||||
assert name.start_pos == (1, 0)
|
||||
@@ -106,7 +107,7 @@ def test_end_pos():
|
||||
def func():
|
||||
y = None
|
||||
'''))
|
||||
parser = Parser(s)
|
||||
parser = Parser(load_grammar(), s)
|
||||
scope = parser.module.subscopes[0]
|
||||
assert scope.start_pos == (3, 0)
|
||||
assert scope.end_pos == (5, 0)
|
||||
@@ -119,14 +120,15 @@ def test_carriage_return_statements():
|
||||
# this is a namespace package
|
||||
'''))
|
||||
source = source.replace('\n', '\r\n')
|
||||
stmt = Parser(source).module.statements[0]
|
||||
stmt = Parser(load_grammar(), source).module.statements[0]
|
||||
assert '#' not in stmt.get_code()
|
||||
|
||||
|
||||
def test_incomplete_list_comprehension():
|
||||
""" Shouldn't raise an error, same bug as #418. """
|
||||
s = Parser(u('(1 for def')).module.statements[0]
|
||||
assert s.expression_list()
|
||||
# With the old parser this actually returned a statement. With the new
|
||||
# parser only valid statements generate one.
|
||||
assert Parser(load_grammar(), u('(1 for def')).module.statements == []
|
||||
|
||||
|
||||
def test_hex_values_in_docstring():
|
||||
@@ -138,8 +140,43 @@ def test_hex_values_in_docstring():
|
||||
return 1
|
||||
'''
|
||||
|
||||
doc = Parser(dedent(u(source))).module.subscopes[0].raw_doc
|
||||
doc = Parser(load_grammar(), dedent(u(source))).module.subscopes[0].raw_doc
|
||||
if is_py3:
|
||||
assert doc == '\xff'
|
||||
else:
|
||||
assert doc == u('<EFBFBD>')
|
||||
|
||||
|
||||
def test_error_correction_with():
|
||||
source = """
|
||||
with open() as f:
|
||||
try:
|
||||
f."""
|
||||
comps = jedi.Script(source).completions()
|
||||
assert len(comps) > 30
|
||||
# `open` completions have a closed attribute.
|
||||
assert [1 for c in comps if c.name == 'closed']
|
||||
|
||||
|
||||
def test_newline_positions():
|
||||
endmarker = Parser(load_grammar(), u('a\n')).module.children[-1]
|
||||
assert endmarker.end_pos == (2, 0)
|
||||
new_line = endmarker.get_previous()
|
||||
assert new_line.start_pos == (1, 1)
|
||||
assert new_line.end_pos == (2, 0)
|
||||
|
||||
|
||||
def test_end_pos_error_correction():
|
||||
"""
|
||||
Source code without ending newline are given one, because the Python
|
||||
grammar needs it. However, they are removed again. We still want the right
|
||||
end_pos, even if something breaks in the parser (error correction).
|
||||
"""
|
||||
s = u('def x():\n .')
|
||||
m = Parser(load_grammar(), s).module
|
||||
func = m.children[0]
|
||||
assert func.type == 'funcdef'
|
||||
# This is not exactly correct, but ok, because it doesn't make a difference
|
||||
# at all. We just want to make sure that the module end_pos is correct!
|
||||
assert func.end_pos == (3, 0)
|
||||
assert m.end_pos == (2, 2)
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
from jedi.parser import Parser
|
||||
from jedi.parser import representation as pr
|
||||
from jedi._compatibility import u
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
def test_import_is_nested():
|
||||
imp = Parser(u('import ')).module.imports[0]
|
||||
# should not raise an error, even if it's not a complete import
|
||||
assert not imp.is_nested()
|
||||
|
||||
|
||||
@pytest.mark.skipif('True', 'Reenable this later, module should also have a scope_names_generator.')
|
||||
def test_module_scope_name_generator():
|
||||
assert pr.Module().scope_names_generator()
|
||||
@@ -1,27 +1,101 @@
|
||||
from jedi._compatibility import u
|
||||
# -*- coding: utf-8 # This file contains Unicode characters.
|
||||
|
||||
from io import StringIO
|
||||
from token import NEWLINE, STRING, INDENT
|
||||
|
||||
from jedi._compatibility import u, is_py3
|
||||
from jedi.parser.token import NAME
|
||||
from jedi import parser
|
||||
from token import STRING
|
||||
|
||||
|
||||
from ..helpers import unittest
|
||||
|
||||
|
||||
class TokenTest(unittest.TestCase):
|
||||
def test_end_pos_one_line(self):
|
||||
parsed = parser.Parser(u('''
|
||||
parsed = parser.Parser(parser.load_grammar(), u('''
|
||||
def testit():
|
||||
a = "huhu"
|
||||
'''))
|
||||
tok = parsed.module.subscopes[0].statements[0]._token_list[2]
|
||||
self.assertEqual(tok.end_pos, (3, 14))
|
||||
tok = parsed.module.subscopes[0].statements[0].children[2]
|
||||
assert tok.end_pos == (3, 14)
|
||||
|
||||
def test_end_pos_multi_line(self):
|
||||
parsed = parser.Parser(u('''
|
||||
parsed = parser.Parser(parser.load_grammar(), u('''
|
||||
def testit():
|
||||
a = """huhu
|
||||
asdfasdf""" + "h"
|
||||
'''))
|
||||
tok = parsed.module.subscopes[0].statements[0]._token_list[2]
|
||||
self.assertEqual(tok.end_pos, (4, 11))
|
||||
tok = parsed.module.subscopes[0].statements[0].children[2].children[0]
|
||||
assert tok.end_pos == (4, 11)
|
||||
|
||||
def test_simple_no_whitespace(self):
|
||||
# Test a simple one line string, no preceding whitespace
|
||||
simple_docstring = u('"""simple one line docstring"""')
|
||||
simple_docstring_io = StringIO(simple_docstring)
|
||||
tokens = parser.tokenize.generate_tokens(simple_docstring_io.readline)
|
||||
token_list = list(tokens)
|
||||
_, value, _, prefix = token_list[0]
|
||||
assert prefix == ''
|
||||
assert value == '"""simple one line docstring"""'
|
||||
|
||||
def test_simple_with_whitespace(self):
|
||||
# Test a simple one line string with preceding whitespace and newline
|
||||
simple_docstring = u(' """simple one line docstring""" \r\n')
|
||||
simple_docstring_io = StringIO(simple_docstring)
|
||||
tokens = parser.tokenize.generate_tokens(simple_docstring_io.readline)
|
||||
token_list = list(tokens)
|
||||
assert token_list[0][0] == INDENT
|
||||
typ, value, start_pos, prefix = token_list[1]
|
||||
assert prefix == ' '
|
||||
assert value == '"""simple one line docstring"""'
|
||||
assert typ == STRING
|
||||
typ, value, start_pos, prefix = token_list[2]
|
||||
assert prefix == ' '
|
||||
assert typ == NEWLINE
|
||||
|
||||
def test_function_whitespace(self):
|
||||
# Test function definition whitespace identification
|
||||
fundef = u('''def test_whitespace(*args, **kwargs):
|
||||
x = 1
|
||||
if x > 0:
|
||||
print(True)
|
||||
''')
|
||||
fundef_io = StringIO(fundef)
|
||||
tokens = parser.tokenize.generate_tokens(fundef_io.readline)
|
||||
token_list = list(tokens)
|
||||
for _, value, _, prefix in token_list:
|
||||
if value == 'test_whitespace':
|
||||
assert prefix == ' '
|
||||
if value == '(':
|
||||
assert prefix == ''
|
||||
if value == '*':
|
||||
assert prefix == ''
|
||||
if value == '**':
|
||||
assert prefix == ' '
|
||||
if value == 'print':
|
||||
assert prefix == ' '
|
||||
if value == 'if':
|
||||
assert prefix == ' '
|
||||
|
||||
def test_identifier_contains_unicode(self):
|
||||
fundef = u('''
|
||||
def 我あφ():
|
||||
pass
|
||||
''')
|
||||
fundef_io = StringIO(fundef)
|
||||
if is_py3:
|
||||
tokens = parser.tokenize.generate_tokens(fundef_io.readline)
|
||||
token_list = list(tokens)
|
||||
identifier_token = next(
|
||||
(token for token in token_list if token[1] == '我あφ'),
|
||||
None
|
||||
)
|
||||
self.assertIsNotNone(identifier_token)
|
||||
assert identifier_token[0] == NAME
|
||||
else:
|
||||
pass
|
||||
|
||||
def test_quoted_strings(self):
|
||||
|
||||
@@ -45,4 +119,4 @@ asdfasdf""" + "h"
|
||||
def test_tokenizer_with_string_literal_backslash():
|
||||
import jedi
|
||||
c = jedi.Script("statement = u'foo\\\n'; statement").goto_definitions()
|
||||
assert c[0]._name.parent.parent.obj == 'foo'
|
||||
assert c[0]._name.parent.obj == 'foo'
|
||||
|
||||
@@ -15,7 +15,7 @@ from jedi._compatibility import u
|
||||
from jedi import Script
|
||||
from jedi import api
|
||||
from jedi.evaluate import imports
|
||||
from jedi.parser import Parser
|
||||
from jedi.parser import Parser, load_grammar
|
||||
|
||||
#jedi.set_debug_function()
|
||||
|
||||
@@ -55,7 +55,7 @@ class TestRegression(TestCase):
|
||||
|
||||
assert should2 == diff_line
|
||||
|
||||
self.assertRaises(jedi.NotFoundError, get_def, cls)
|
||||
assert get_def(cls) == []
|
||||
|
||||
@pytest.mark.skipif('True', reason='Skip for now, test case is not really supported.')
|
||||
@cwd_at('jedi')
|
||||
@@ -98,13 +98,12 @@ class TestRegression(TestCase):
|
||||
self.assertEqual([d.description for d in defs],
|
||||
['def f', 'class C'])
|
||||
|
||||
def test_end_pos(self):
|
||||
def test_end_pos_line(self):
|
||||
# jedi issue #150
|
||||
s = u("x()\nx( )\nx( )\nx ( )")
|
||||
parser = Parser(s)
|
||||
for i, s in enumerate(parser.module.statements, 3):
|
||||
for c in s.expression_list():
|
||||
self.assertEqual(c.next.end_pos[1], i)
|
||||
parser = Parser(load_grammar(), s)
|
||||
for i, s in enumerate(parser.module.statements):
|
||||
assert s.end_pos == (i + 1, i + 3)
|
||||
|
||||
def check_definition_by_marker(self, source, after_cursor, names):
|
||||
r"""
|
||||
@@ -170,4 +169,4 @@ def test_loading_unicode_files_with_bad_global_charset(monkeypatch, tmpdir):
|
||||
f.write(data)
|
||||
s = Script("from test1 import foo\nfoo.",
|
||||
line=2, column=4, path=filename2)
|
||||
s.complete()
|
||||
s.completions()
|
||||
|
||||
Reference in New Issue
Block a user