Merge branch 'refactor'

This commit is contained in:
Dave Halter
2020-03-21 02:54:07 +01:00
116 changed files with 4326 additions and 2483 deletions

View File

@@ -473,7 +473,7 @@ def test_func():
#? int()
tuple({1})[0]
# python >= 3.4
# python > 2.7
# -----------------
# PEP 3132 Extended Iterable Unpacking (star unpacking)
# -----------------

View File

@@ -242,7 +242,7 @@ def x():
# yield from
# -----------------
# python >= 3.4
# python > 2.7
def yield_from():
yield from iter([1])

View File

@@ -12,6 +12,8 @@ def from_names_goto():
def builtin_test():
#? ['math']
import math
#? ['mmap']
import mmap
# -----------------
# completions within imports

View File

@@ -1,6 +1,6 @@
""" Pep-0484 type hinting """
# python >= 3.4
# python > 2.7
class A():

View File

@@ -283,7 +283,7 @@ def testnewtype2(y):
y
#? []
y.
# python >= 3.4
# python > 2.7
class TestDefaultDict(typing.DefaultDict[str, int]):
def setdud(self):
@@ -311,7 +311,7 @@ for key in x.keys():
for value in x.values():
#? int()
value
# python >= 3.4
# python > 2.7
"""
@@ -341,9 +341,8 @@ typing.Optional[0]
TYPE_VARX = typing.TypeVar('TYPE_VARX')
TYPE_VAR_CONSTRAINTSX = typing.TypeVar('TYPE_VAR_CONSTRAINTSX', str, int)
# TODO there should at least be some results.
#? []
TYPE_VARX.
#? ['__class__']
TYPE_VARX.__clas
#! ["TYPE_VARX = typing.TypeVar('TYPE_VARX')"]
TYPE_VARX

View File

@@ -130,7 +130,7 @@ def test_p(monkeypatch):
#? ['setattr']
monkeypatch.setatt
# python > 3.4
# python > 2.7
#? ['capsysbinary']
def test_p(capsysbin

View File

@@ -359,7 +359,7 @@ class Test(metaclass=Meta):
# Enum
# -----------------
# python >= 3.4
# python > 2.7
import enum
class X(enum.Enum):

View File

@@ -1,4 +1,4 @@
# python >= 3.4
# python > 2.7
from stub_folder import with_stub, stub_only, with_stub_folder, stub_only_folder
# -------------------------

View File

@@ -76,9 +76,11 @@ def pytest_generate_tests(metafunc):
if 'refactor_case' in metafunc.fixturenames:
base_dir = metafunc.config.option.refactor_case_dir
cases = list(refactor.collect_dir_tests(base_dir, test_files))
metafunc.parametrize(
'refactor_case',
refactor.collect_dir_tests(base_dir, test_files))
'refactor_case', cases,
ids=[c.refactor_type + '-' + c.name for c in cases]
)
if 'static_analysis_case' in metafunc.fixturenames:
base_dir = os.path.join(os.path.dirname(__file__), 'static_analysis')

View File

@@ -2,7 +2,7 @@
import sys
sys.path[0:0] = [
'/usr/lib/python3.4/site-packages',
'/usr/lib/python3.8/site-packages',
'/tmp/.buildout/eggs/important_package.egg'
]

116
test/refactor.py Executable file → Normal file
View File

@@ -1,99 +1,103 @@
#!/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.**
Refactoring tests work a little bit similar to integration tests. But the idea
is here to compare two versions of code. If you want to add a new test case,
just look at the existing ones in the ``test/refactor`` folder and copy them.
"""
from __future__ import with_statement
import os
import platform
import re
import sys
from parso import split_lines
from functools import reduce
import jedi
from jedi import refactoring
from .helpers import test_dir
class RefactoringCase(object):
def __init__(self, name, source, line_nr, index, path,
new_name, start_line_test, desired):
def __init__(self, name, code, line_nr, index, path, kwargs, type_, desired_result):
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
self._code = code
self._line_nr = line_nr
self._index = index
self._path = path
self._kwargs = kwargs
self.type = type_
self._desired_result = desired_result
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 get_desired_result(self):
def run(self):
refactor_object = self.refactor()
if platform.system().lower() == 'windows' and self.type == 'diff':
# Windows uses backslashes to separate paths.
lines = split_lines(self._desired_result, keepends=True)
for i, line in enumerate(lines):
if re.search(' import_tree/', line):
lines[i] = line.replace('/', '\\')
return ''.join(lines)
return self._desired_result
# try to get the right excerpt of the newfile
f = refactor_object.new_files()[self.path]
lines = f.splitlines()[self.start_line_test:]
@property
def refactor_type(self):
f_name = os.path.basename(self._path)
return f_name.replace('.py', '')
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 refactor(self, environment):
project = jedi.Project(os.path.join(test_dir, 'refactor'))
script = jedi.Script(self._code, path=self._path, project=project, environment=environment)
refactor_func = getattr(script, self.refactor_type)
return refactor_func(self._line_nr, self._index, **self._kwargs)
def __repr__(self):
return '<%s: %s:%s>' % (self.__class__.__name__,
self.name, self.line_nr - 1)
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):
def _collect_file_tests(code, path, lines_to_execute):
r = r'^# -{5,} ?([^\n]*)\n((?:(?!\n# \+{5,}).)*\n)' \
r'# \+{5,}\n((?:(?!\n# -{5,}).)*\n)'
match = None
for match in re.finditer(r, code, 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
first = match.group(2)
second = match.group(3)
# get the line with the position of the operation
p = re.match(r'((?:(?!#\?).)*)#\? (\d*) ?([^\n]*)', first, re.DOTALL)
p = re.match(r'((?:(?!#\?).)*)#\? (\d*)( error| text|) ?([^\n]*)', first, re.DOTALL)
if p is None:
print("Please add a test start.")
raise Exception("Please add a test start.")
continue
until = p.group(1)
index = int(p.group(2))
new_name = p.group(3)
type_ = p.group(3).strip() or 'diff'
if p.group(4):
kwargs = eval(p.group(4))
else:
kwargs = {}
line_nr = start_line_test + until.count('\n') + 2
line_nr = 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)
yield RefactoringCase(name, first, line_nr, index, path, kwargs, type_, second)
if match is None:
raise Exception("Didn't match any test")
if match.end() != len(code):
raise Exception("Didn't match until the end of the file in %s" % path)
def collect_dir_tests(base_dir, test_files):
if sys.version_info[0] == 2:
return
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):
with open(path, newline='') as f:
code = f.read()
for case in _collect_file_tests(code, path, lines_to_execute):
yield case

View File

@@ -1,47 +0,0 @@
# --- 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,447 @@
# -------------------------------------------------- in-module-1
glob = 3
#? 11 text {'new_name': 'a'}
test(100, (glob.a + b, c) + 1)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
glob = 3
#? 11 text {'new_name': 'a'}
def a(b):
return glob.a + b
test(100, (a(b), c) + 1)
# -------------------------------------------------- in-module-2
#? 0 text {'new_name': 'ab'}
100 + 1 * 2
# ++++++++++++++++++++++++++++++++++++++++++++++++++
#? 0 text {'new_name': 'ab'}
def ab():
return 100 + 1 * 2
ab()
# -------------------------------------------------- in-function-1
def f(x):
#? 11 text {'new_name': 'ab'}
return x + 1 * 2
# ++++++++++++++++++++++++++++++++++++++++++++++++++
def ab(x):
return x + 1 * 2
def f(x):
#? 11 text {'new_name': 'ab'}
return ab(x)
# -------------------------------------------------- in-function-with-dec
@classmethod
def f(x):
#? 11 text {'new_name': 'ab'}
return x + 1 * 2
# ++++++++++++++++++++++++++++++++++++++++++++++++++
def ab(x):
return x + 1 * 2
@classmethod
def f(x):
#? 11 text {'new_name': 'ab'}
return ab(x)
# -------------------------------------------------- in-method-1
class X:
def z(self): pass
def f(x, b):
#? 11 text {'new_name': 'ab'}
return x + b * 2
# ++++++++++++++++++++++++++++++++++++++++++++++++++
class X:
def z(self): pass
def ab(x, b):
return x + b * 2
def f(x, b):
#? 11 text {'new_name': 'ab'}
return x.ab(b)
# -------------------------------------------------- in-method-2
glob1 = 1
class X:
def g(self): pass
def f(self, b, c):
#? 11 text {'new_name': 'ab'}
return self.g() or self.f(b) ^ glob1 & b
# ++++++++++++++++++++++++++++++++++++++++++++++++++
glob1 = 1
class X:
def g(self): pass
def ab(self, b):
return self.g() or self.f(b) ^ glob1 & b
def f(self, b, c):
#? 11 text {'new_name': 'ab'}
return self.ab(b)
# -------------------------------------------------- in-method-order
class X:
def f(self, b, c):
#? 18 text {'new_name': 'b'}
return b | self.a
# ++++++++++++++++++++++++++++++++++++++++++++++++++
class X:
def b(self, b):
return b | self.a
def f(self, b, c):
#? 18 text {'new_name': 'b'}
return self.b(b)
# -------------------------------------------------- in-classmethod-1
class X:
@classmethod
def f(x):
#? 16 text {'new_name': 'ab'}
return 25
# ++++++++++++++++++++++++++++++++++++++++++++++++++
class X:
@classmethod
def ab(x):
return 25
@classmethod
def f(x):
#? 16 text {'new_name': 'ab'}
return x.ab()
# -------------------------------------------------- in-staticmethod-1
class X(int):
@staticmethod
def f(x):
#? 16 text {'new_name': 'ab'}
return 25 | 3
# ++++++++++++++++++++++++++++++++++++++++++++++++++
def ab():
return 25 | 3
class X(int):
@staticmethod
def f(x):
#? 16 text {'new_name': 'ab'}
return ab()
# -------------------------------------------------- in-class-1
class Ya():
a = 3
#? 11 text {'new_name': 'f'}
c = a + 2
# ++++++++++++++++++++++++++++++++++++++++++++++++++
def f(a):
return a + 2
class Ya():
a = 3
#? 11 text {'new_name': 'f'}
c = f(a)
# -------------------------------------------------- in-closure
def x(z):
def y(x):
#? 15 text {'new_name': 'f'}
return -x * z
# ++++++++++++++++++++++++++++++++++++++++++++++++++
def f(x, z):
return -x * z
def x(z):
def y(x):
#? 15 text {'new_name': 'f'}
return f(x, z)
# -------------------------------------------------- with-range-1
#? 0 text {'new_name': 'a', 'until_line': 4}
v1 = 3
v2 = 2
x = test(v1 + v2 * v3)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
#? 0 text {'new_name': 'a', 'until_line': 4}
def a(test, v3):
v1 = 3
v2 = 2
x = test(v1 + v2 * v3)
return x
x = a(test, v3)
# -------------------------------------------------- with-range-2
#? 2 text {'new_name': 'a', 'until_line': 6, 'until_column': 4}
#foo
v1 = 3
v2 = 2
x, y = test(v1 + v2 * v3)
#raaaa
y
# ++++++++++++++++++++++++++++++++++++++++++++++++++
#? 2 text {'new_name': 'a', 'until_line': 6, 'until_column': 4}
def a(test, v3):
#foo
v1 = 3
v2 = 2
x, y = test(v1 + v2 * v3)
#raaaa
return y
y = a(test, v3)
y
# -------------------------------------------------- with-range-3
#foo
#? 2 text {'new_name': 'a', 'until_line': 5, 'until_column': 4}
v1 = 3
v2 = 2
x, y = test(v1 + v2 * v3)
#raaaa
y
# ++++++++++++++++++++++++++++++++++++++++++++++++++
#foo
#? 2 text {'new_name': 'a', 'until_line': 5, 'until_column': 4}
def a(test, v3):
v1 = 3
v2 = 2
x, y = test(v1 + v2 * v3)
return y
y = a(test, v3)
#raaaa
y
# -------------------------------------------------- with-range-func-1
import os
# comment1
@dec
# comment2
def x(v1):
#foo
#? 2 text {'new_name': 'a', 'until_line': 9, 'until_column': 5}
v2 = 2
if 1:
x, y = os.listdir(v1 + v2 * v3)
#bar
return x, y
# ++++++++++++++++++++++++++++++++++++++++++++++++++
import os
# comment1
def a(v1, v3):
v2 = 2
if 1:
x, y = os.listdir(v1 + v2 * v3)
return x, y
@dec
# comment2
def x(v1):
#foo
#? 2 text {'new_name': 'a', 'until_line': 9, 'until_column': 5}
x, y = a(v1, v3)
#bar
return x, y
# -------------------------------------------------- with-range-func-2
import os
# comment1
# comment2
def x(v1):
#? 2 text {'new_name': 'a', 'until_line': 10, 'until_column': 0}
#foo
v2 = 2
if 1:
x, y = os.listdir(v1 + v2 * v3)
#bar
return y
x
# ++++++++++++++++++++++++++++++++++++++++++++++++++
import os
# comment1
# comment2
def a(v1, v3):
#foo
v2 = 2
if 1:
x, y = os.listdir(v1 + v2 * v3)
#bar
return y
def x(v1):
#? 2 text {'new_name': 'a', 'until_line': 10, 'until_column': 0}
y = a(v1, v3)
return y
x
# -------------------------------------------------- with-range-func-3
def x(v1):
#? 2 text {'new_name': 'func', 'until_line': 6, 'until_column': 4}
#foo
v2 = 2
x = v1 * 2
y = 3
#bar
return x
x
# ++++++++++++++++++++++++++++++++++++++++++++++++++
def func(v1):
#foo
v2 = 2
x = v1 * 2
return x
def x(v1):
#? 2 text {'new_name': 'func', 'until_line': 6, 'until_column': 4}
x = func(v1)
y = 3
#bar
return x
x
# -------------------------------------------------- in-class-range-1
class X1:
#? 11 text {'new_name': 'f', 'until_line': 4}
a = 3
c = a + 2
# ++++++++++++++++++++++++++++++++++++++++++++++++++
def f():
a = 3
c = a + 2
return c
class X1:
#? 11 text {'new_name': 'f', 'until_line': 4}
c = f()
# -------------------------------------------------- in-method-range-1
glob1 = 1
class X:
# ha
def g(self): pass
# haha
def f(self, b, c):
#? 11 text {'new_name': 'ab', 'until_line': 12, 'until_column': 28}
#foo
local1 = 3
local2 = 4
x= self.g() or self.f(b) ^ glob1 & b is local1
# bar
# ++++++++++++++++++++++++++++++++++++++++++++++++++
glob1 = 1
class X:
# ha
def g(self): pass
# haha
def ab(self, b):
#foo
local1 = 3
local2 = 4
x= self.g() or self.f(b) ^ glob1 & b is local1
return x
def f(self, b, c):
#? 11 text {'new_name': 'ab', 'until_line': 12, 'until_column': 28}
x = self.ab(b)
# bar
# -------------------------------------------------- in-method-range-2
glob1 = 1
class X:
# comment
def f(self, b, c):
#? 11 text {'new_name': 'ab', 'until_line': 11, 'until_column': 10}
#foo
local1 = 3
local2 = 4
return local1 * glob1 * b
# bar
# ++++++++++++++++++++++++++++++++++++++++++++++++++
glob1 = 1
class X:
# comment
def ab(self, b):
#foo
local1 = 3
local2 = 4
return local1 * glob1 * b
# bar
def f(self, b, c):
#? 11 text {'new_name': 'ab', 'until_line': 11, 'until_column': 10}
return self.ab(b)
# -------------------------------------------------- in-method-range-3
glob1 = 1
class X:
def f(self, b, c):
local1, local2 = 3, 4
#foo
#? 11 text {'new_name': 'ab', 'until_line': 7, 'until_column': 29}
return local1 & glob1 & b
# bar
local2
# ++++++++++++++++++++++++++++++++++++++++++++++++++
glob1 = 1
class X:
def ab(self, local1, b):
return local1 & glob1 & b
def f(self, b, c):
local1, local2 = 3, 4
#foo
#? 11 text {'new_name': 'ab', 'until_line': 7, 'until_column': 29}
return self.ab(local1, b)
# bar
local2
# -------------------------------------------------- in-method-no-param
glob1 = 1
class X:
def f():
#? 11 text {'new_name': 'ab', 'until_line': 5, 'until_column': 22}
return glob1 + 2
# ++++++++++++++++++++++++++++++++++++++++++++++++++
glob1 = 1
class X:
def ab():
return glob1 + 2
def f():
#? 11 text {'new_name': 'ab', 'until_line': 5, 'until_column': 22}
return ab()
# -------------------------------------------------- random-return-1
def x():
#? 0 error {'new_name': 'ab', 'until_line': 5, 'until_column': 10}
if x:
return 1
return 1
# ++++++++++++++++++++++++++++++++++++++++++++++++++
Can only extract return statements if they are at the end.
# -------------------------------------------------- random-return-2
def x():
#? 0 error {'new_name': 'ab', 'until_line': 5, 'until_column': 10}
#
return
pass
# ++++++++++++++++++++++++++++++++++++++++++++++++++
Can only extract return statements if they are at the end.
# -------------------------------------------------- random-yield-1
def x():
#? 0 error {'new_name': 'ab', 'until_line': 5, 'until_column': 10}
#
if (yield 1):
return
pass
# ++++++++++++++++++++++++++++++++++++++++++++++++++
Cannot extract yield statements.
# -------------------------------------------------- random-yield-2
def x():
#? 0 error {'new_name': 'ab', 'until_line': 4, 'until_column': 10}
#
try:
yield
finally:
pass
# ++++++++++++++++++++++++++++++++++++++++++++++++++
Cannot extract yield statements.

View File

@@ -0,0 +1,251 @@
# -------------------------------------------------- simple-1
def test():
#? 35 text {'new_name': 'a'}
return test(100, (30 + b, c) + 1)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
def test():
#? 35 text {'new_name': 'a'}
a = (30 + b, c) + 1
return test(100, a)
# -------------------------------------------------- simple-2
def test():
#? 25 text {'new_name': 'a'}
return test(100, (30 + b, c) + 1)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
def test():
#? 25 text {'new_name': 'a'}
a = 30 + b
return test(100, (a, c) + 1)
# -------------------------------------------------- simple-3
#? 13 text {'new_name': 'zzx.x'}
test(100, {1 |1: 2 + 3})
# ++++++++++++++++++++++++++++++++++++++++++++++++++
#? 13 text {'new_name': 'zzx.x'}
zzx.x = 1 |1
test(100, {zzx.x: 2 + 3})
# -------------------------------------------------- multiline-1
def test():
#? 30 text {'new_name': 'x'}
return test(1, (30 + b, c)
+ 1)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
def test():
#? 30 text {'new_name': 'x'}
x = (30 + b, c)
+ 1
return test(1, x)
# -------------------------------------------------- multiline-2
def test():
#? 25 text {'new_name': 'x'}
return test(1, (30 + b, c)
+ 1)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
def test():
#? 25 text {'new_name': 'x'}
x = 30 + b
return test(1, (x, c)
+ 1)
# -------------------------------------------------- for-param-error-1
#? 10 error {'new_name': 'x'}
def test(p1):
return
# ++++++++++++++++++++++++++++++++++++++++++++++++++
Cannot extract a name that defines something
# -------------------------------------------------- for-param-error-2
#? 12 error {'new_name': 'x'}
def test(p1= 3):
return
# ++++++++++++++++++++++++++++++++++++++++++++++++++
Cannot extract a "param"
# -------------------------------------------------- for-param-1
#? 12 text {'new_name': 'x'}
def test(p1=20):
return
# ++++++++++++++++++++++++++++++++++++++++++++++++++
#? 12 text {'new_name': 'x'}
x = 20
def test(p1=x):
return
# -------------------------------------------------- for-something
#? 12 text {'new_name': 'x'}
def test(p1=20):
return
# ++++++++++++++++++++++++++++++++++++++++++++++++++
#? 12 text {'new_name': 'x'}
x = 20
def test(p1=x):
return
# -------------------------------------------------- class-inheritance-1
#? 12 text {'new_name': 'x'}
class Foo(foo.Bar):
pass
# ++++++++++++++++++++++++++++++++++++++++++++++++++
#? 12 text {'new_name': 'x'}
x = foo.Bar
class Foo(x):
pass
# -------------------------------------------------- class-inheritance-2
#? 16 text {'new_name': 'x'}
class Foo(foo.Bar):
pass
# ++++++++++++++++++++++++++++++++++++++++++++++++++
#? 16 text {'new_name': 'x'}
x = foo.Bar
class Foo(x):
pass
# -------------------------------------------------- keyword-pass
#? 12 error {'new_name': 'x'}
def x(): pass
# ++++++++++++++++++++++++++++++++++++++++++++++++++
Cannot extract a "simple_stmt"
# -------------------------------------------------- keyword-continue
#? 5 error {'new_name': 'x'}
continue
# ++++++++++++++++++++++++++++++++++++++++++++++++++
Cannot extract a "simple_stmt"
# -------------------------------------------------- keyword-None
if 1:
#? 4 text {'new_name': 'x'}
None
# ++++++++++++++++++++++++++++++++++++++++++++++++++
if 1:
#? 4 text {'new_name': 'x'}
x = None
x
# -------------------------------------------------- with-tuple
#? 4 text {'new_name': 'x'}
x + 1, 3
# ++++++++++++++++++++++++++++++++++++++++++++++++++
#? 4 text {'new_name': 'x'}
x = x + 1
x, 3
# -------------------------------------------------- range-1
#? 4 text {'new_name': 'x', 'until_column': 9}
y + 1, 3
# ++++++++++++++++++++++++++++++++++++++++++++++++++
#? 4 text {'new_name': 'x', 'until_column': 9}
x = y + 1, 3
x
# -------------------------------------------------- range-2
#? 1 text {'new_name': 'x', 'until_column': 3}
y + 1, 3
# ++++++++++++++++++++++++++++++++++++++++++++++++++
#? 1 text {'new_name': 'x', 'until_column': 3}
x = y + 1
x, 3
# -------------------------------------------------- range-3
#? 1 text {'new_name': 'x', 'until_column': 6}
y + 1, 3
# ++++++++++++++++++++++++++++++++++++++++++++++++++
#? 1 text {'new_name': 'x', 'until_column': 6}
x = y + 1
x, 3
# -------------------------------------------------- range-4
#? 1 text {'new_name': 'x', 'until_column': 1}
y + 1, 3
# ++++++++++++++++++++++++++++++++++++++++++++++++++
#? 1 text {'new_name': 'x', 'until_column': 1}
x = y
x + 1, 3
# -------------------------------------------------- addition-1
#? 4 text {'new_name': 'x', 'until_column': 9}
z = y + 1 + 2+ 3, 3
# ++++++++++++++++++++++++++++++++++++++++++++++++++
#? 4 text {'new_name': 'x', 'until_column': 9}
x = y + 1
z = x + 2+ 3, 3
# -------------------------------------------------- addition-2
#? 8 text {'new_name': 'x', 'until_column': 12}
z = y +1 + 2+ 3, 3
# ++++++++++++++++++++++++++++++++++++++++++++++++++
#? 8 text {'new_name': 'x', 'until_column': 12}
x = 1 + 2
z = y +x+ 3, 3
# -------------------------------------------------- addition-3
#? 10 text {'new_name': 'x', 'until_column': 14}
z = y + 1 + 2+ 3, 3
# ++++++++++++++++++++++++++++++++++++++++++++++++++
#? 10 text {'new_name': 'x', 'until_column': 14}
x = 1 + 2+ 3
z = y + x, 3
# -------------------------------------------------- addition-4
#? 13 text {'new_name': 'x', 'until_column': 17}
z = y + (1 + 2)+ 3, 3
# ++++++++++++++++++++++++++++++++++++++++++++++++++
#? 13 text {'new_name': 'x', 'until_column': 17}
x = (1 + 2)+ 3
z = y + x, 3
# -------------------------------------------------- mult-add-1
#? 8 text {'new_name': 'x', 'until_column': 11}
z = foo(y+1*2+3, 3)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
#? 8 text {'new_name': 'x', 'until_column': 11}
x = y+1
z = foo(x*2+3, 3)
# -------------------------------------------------- mult-add-2
#? 12 text {'new_name': 'x', 'until_column': 15}
z = foo(y+1*2+3)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
#? 12 text {'new_name': 'x', 'until_column': 15}
x = 2+3
z = foo(y+1*x)
# -------------------------------------------------- mult-add-3
#? 9 text {'new_name': 'x', 'until_column': 13}
z = (y+1*2+3)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
#? 9 text {'new_name': 'x', 'until_column': 13}
x = (y+1*2+3)
z = x
# -------------------------------------------------- extract-weird-1
#? 0 error {'new_name': 'x', 'until_column': 7}
foo = 3
# ++++++++++++++++++++++++++++++++++++++++++++++++++
Cannot extract a "expr_stmt"
# -------------------------------------------------- extract-weird-2
#? 0 error {'new_name': 'x', 'until_column': 5}
def x():
foo = 3
# ++++++++++++++++++++++++++++++++++++++++++++++++++
Cannot extract a "funcdef"
# -------------------------------------------------- extract-weird-3
def x():
#? 4 error {'new_name': 'x', 'until_column': 8}
if 1:
pass
# ++++++++++++++++++++++++++++++++++++++++++++++++++
Cannot extract a "if_stmt"
# -------------------------------------------------- extract-weird-4
#? 4 error {'new_name': 'x', 'until_column': 7}
x = foo = 4
# ++++++++++++++++++++++++++++++++++++++++++++++++++
Cannot extract a name that defines something
# -------------------------------------------------- keyword-None
#? 4 text {'new_name': 'x', 'until_column': 7}
yy = not foo or bar
# ++++++++++++++++++++++++++++++++++++++++++++++++++
#? 4 text {'new_name': 'x', 'until_column': 7}
x = not foo
yy = x or bar
# -------------------------------------------------- augassign
yy = ()
#? 6 text {'new_name': 'x', 'until_column': 10}
yy += 3, 4
# ++++++++++++++++++++++++++++++++++++++++++++++++++
yy = ()
#? 6 text {'new_name': 'x', 'until_column': 10}
x = 3, 4
yy += x
# -------------------------------------------------- if-else
#? 9 text {'new_name': 'x', 'until_column': 22}
yy = foo(a if y else b)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
#? 9 text {'new_name': 'x', 'until_column': 22}
x = a if y else b
yy = foo(x)
# -------------------------------------------------- lambda
#? 8 text {'new_name': 'x', 'until_column': 17}
y = foo(lambda x: 3, 5)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
#? 8 text {'new_name': 'x', 'until_column': 17}
x = lambda x: 3
y = foo(x, 5)

View File

@@ -0,0 +1 @@
inline_var = 5 + 3

View File

@@ -0,0 +1,2 @@
def pkgx():
pass

View File

@@ -0,0 +1 @@
def pkgx() -> int: ...

View File

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

View File

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

View File

@@ -0,0 +1 @@
foobar = 3

View File

@@ -1,18 +1,243 @@
# --- simple
# -------------------------------------------------- no-name-error
#? 0 error
1
# ++++++++++++++++++++++++++++++++++++++++++++++++++
There is no name under the cursor
# -------------------------------------------------- multi-equal-error
def test():
#? 4 error
a = b = 3
return test(100, a)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
Cannot inline a statement with multiple definitions
# -------------------------------------------------- no-definition-error
#? 5 error
test(a)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
No definition found to inline
# -------------------------------------------------- multi-names-error
#? 0 error
a, b[1] = 3
test(a)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
Cannot inline a statement with multiple definitions
# -------------------------------------------------- addition-error
#? 0 error
a = 2
a += 3
test(a)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
Cannot inline a name with multiple definitions
# -------------------------------------------------- only-addition-error
#? 0 error
a += 3
test(a)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
Cannot inline a statement with "+="
# -------------------------------------------------- with-annotation
foobarb: int = 1
#? 5
test(foobarb)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
--- inline.py
+++ inline.py
@@ -1,4 +1,3 @@
-foobarb: int = 1
#? 5
-test(foobarb)
+test(1)
# -------------------------------------------------- only-annotation-error
a: int
#? 5 error
test(a)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
Cannot inline a statement that is defined by an annotation
# -------------------------------------------------- builtin
import math
#? 7 error
math.cos
# ++++++++++++++++++++++++++++++++++++++++++++++++++
Cannot inline builtins/extensions
# -------------------------------------------------- module-error
from import_tree import inline_mod
#? 11 error
test(inline_mod)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
Cannot inline imports or modules
# -------------------------------------------------- module-works
from import_tree import inline_mod
#? 22
test(x, inline_mod. inline_var.conjugate)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
--- import_tree/inline_mod.py
+++ import_tree/inline_mod.py
@@ -1,2 +1 @@
-inline_var = 5 + 3
--- inline.py
+++ inline.py
@@ -1,4 +1,4 @@
from import_tree import inline_mod
#? 22
-test(x, inline_mod. inline_var.conjugate)
+test(x, (5 + 3).conjugate)
# -------------------------------------------------- class
class A: pass
#? 5 error
test(A)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
Cannot inline a class
# -------------------------------------------------- function
def foo(a):
return a + 1
#? 5 error
test(foo(1))
# ++++++++++++++++++++++++++++++++++++++++++++++++++
Cannot inline a function
# -------------------------------------------------- for-stmt
for x in []:
#? 9 error
test(x)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
Cannot inline a for_stmt
# -------------------------------------------------- simple
def test():
#? 4
a = (30 + b, c) + 1
return test(100, a)
# +++
def test():
return test(100, (30 + b, c) + 1)
# --- simple
# ++++++++++++++++++++++++++++++++++++++++++++++++++
--- inline.py
+++ inline.py
@@ -1,5 +1,4 @@
def test():
#? 4
- a = (30 + b, c) + 1
- return test(100, a)
+ return test(100, (30 + b, c) + 1)
# -------------------------------------------------- tuple
if 1:
#? 4
a = 1, 2
return test(100, a)
# +++
if 1:
return test(100, (1, 2))
# ++++++++++++++++++++++++++++++++++++++++++++++++++
--- inline.py
+++ inline.py
@@ -1,5 +1,4 @@
if 1:
#? 4
- a = 1, 2
- return test(100, a)
+ return test(100, (1, 2))
# -------------------------------------------------- multiplication-add-parens1
a = 1+2
#? 11
test(100 * a)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
--- inline.py
+++ inline.py
@@ -1,4 +1,3 @@
-a = 1+2
#? 11
-test(100 * a)
+test(100 * (1+2))
# -------------------------------------------------- multiplication-add-parens2
a = 1+2
#? 11
(x, 100 * a)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
--- inline.py
+++ inline.py
@@ -1,4 +1,3 @@
-a = 1+2
#? 11
-(x, 100 * a)
+(x, 100 * (1+2))
# -------------------------------------------------- multiplication-add-parens3
x
a = 1+2
#? 9
(100 ** a)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
--- inline.py
+++ inline.py
@@ -1,5 +1,4 @@
x
-a = 1+2
#? 9
-(100 ** a)
+(100 ** (1+2))
# -------------------------------------------------- no-add-parens1
x
a = 1+2
#? 5
test(a)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
--- inline.py
+++ inline.py
@@ -1,5 +1,4 @@
x
-a = 1+2
#? 5
-test(a)
+test(1+2)
# -------------------------------------------------- no-add-parens2
a = 1+2
#? 9
test(3, a)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
--- inline.py
+++ inline.py
@@ -1,4 +1,3 @@
-a = 1+2
#? 9
-test(3, a)
+test(3, 1+2)
# -------------------------------------------------- no-add-parens3
a = 1|2
#? 5
(3, a)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
--- inline.py
+++ inline.py
@@ -1,4 +1,3 @@
-a = 1|2
#? 5
-(3, a)
+(3, 1|2)
# -------------------------------------------------- comment
a = 1 and 2 # foo
#? 9
(3, 3 * a)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
--- inline.py
+++ inline.py
@@ -1,4 +1,4 @@
-a = 1 and 2 # foo
+ # foo
#? 9
-(3, 3 * a)
+(3, 3 * (1 and 2))
# -------------------------------------------------- semicolon
a = 1, 2 ; b = 3
#? 9
(3, 3 == a)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
--- inline.py
+++ inline.py
@@ -1,4 +1,4 @@
-a = 1, 2 ; b = 3
+ b = 3
#? 9
-(3, 3 == a)
+(3, 3 == (1, 2))
# -------------------------------------------------- no-tree-name
a = 1 + 2
#? 0
a.conjugate
# ++++++++++++++++++++++++++++++++++++++++++++++++++
--- inline.py
+++ inline.py
@@ -1,4 +1,3 @@
-a = 1 + 2
#? 0
-a.conjugate
+(1 + 2).conjugate

View File

@@ -3,15 +3,233 @@ Test coverage for renaming is mostly being done by testing
`Script.get_references`.
"""
# --- simple
# -------------------------------------------------- no-name
#? 0 error {'new_name': 'blabla'}
1
# ++++++++++++++++++++++++++++++++++++++++++++++++++
There is no name under the cursor
# -------------------------------------------------- simple
def test1():
#? 7 blabla
#? 7 {'new_name': 'blabla'}
test1()
AssertionError
return test1, test1.not_existing
# +++
def blabla():
blabla()
AssertionError
return blabla, blabla.not_existing
# ++++++++++++++++++++++++++++++++++++++++++++++++++
--- rename.py
+++ rename.py
@@ -1,6 +1,6 @@
-def test1():
+def blabla():
#? 7 {'new_name': 'blabla'}
- test1()
+ blabla()
AssertionError
- return test1, test1.not_existing
+ return blabla, blabla.not_existing
# -------------------------------------------------- var-not-found
undefined_var
#? 0 {'new_name': 'lala'}
undefined_var
# ++++++++++++++++++++++++++++++++++++++++++++++++++
--- rename.py
+++ rename.py
@@ -1,4 +1,4 @@
undefined_var
#? 0 {'new_name': 'lala'}
-undefined_var
+lala
# -------------------------------------------------- different-scopes
def x():
#? 7 {'new_name': 'v'}
some_var = 3
some_var
def y():
some_var = 3
some_var
# ++++++++++++++++++++++++++++++++++++++++++++++++++
--- rename.py
+++ rename.py
@@ -1,7 +1,7 @@
def x():
#? 7 {'new_name': 'v'}
- some_var = 3
- some_var
+ v = 3
+ v
def y():
some_var = 3
some_var
# -------------------------------------------------- keyword-param1
#? 22 {'new_name': 'lala'}
def mykeywordparam1(param1):
str(param1)
mykeywordparam1(1)
mykeywordparam1(param1=3)
mykeywordparam1(x, param1=2)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
--- rename.py
+++ rename.py
@@ -1,7 +1,7 @@
#? 22 {'new_name': 'lala'}
-def mykeywordparam1(param1):
- str(param1)
+def mykeywordparam1(lala):
+ str(lala)
mykeywordparam1(1)
-mykeywordparam1(param1=3)
-mykeywordparam1(x, param1=2)
+mykeywordparam1(lala=3)
+mykeywordparam1(x, lala=2)
# -------------------------------------------------- keyword-param2
def mykeywordparam2(param1):
str(param1)
mykeywordparam2(1)
mykeywordparam2(param1=3)
#? 22 {'new_name': 'lala'}
mykeywordparam2(x, param1=2)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
--- rename.py
+++ rename.py
@@ -1,7 +1,7 @@
-def mykeywordparam2(param1):
- str(param1)
+def mykeywordparam2(lala):
+ str(lala)
mykeywordparam2(1)
-mykeywordparam2(param1=3)
+mykeywordparam2(lala=3)
#? 22 {'new_name': 'lala'}
-mykeywordparam2(x, param1=2)
+mykeywordparam2(x, lala=2)
# -------------------------------------------------- import
from import_tree.some_mod import foobar
#? 0 {'new_name': 'renamed'}
foobar
# ++++++++++++++++++++++++++++++++++++++++++++++++++
--- import_tree/some_mod.py
+++ import_tree/some_mod.py
@@ -1,2 +1,2 @@
-foobar = 3
+renamed = 3
--- rename.py
+++ rename.py
@@ -1,4 +1,4 @@
-from import_tree.some_mod import foobar
+from import_tree.some_mod import renamed
#? 0 {'new_name': 'renamed'}
-foobar
+renamed
# -------------------------------------------------- module
from import_tree import some_mod
#? 0 {'new_name': 'renamedm'}
some_mod
# ++++++++++++++++++++++++++++++++++++++++++++++++++
rename from import_tree/some_mod.py
rename to import_tree/renamedm.py
--- rename.py
+++ rename.py
@@ -1,4 +1,4 @@
-from import_tree import some_mod
+from import_tree import renamedm
#? 0 {'new_name': 'renamedm'}
-some_mod
+renamedm
# -------------------------------------------------- import-not-found
#? 20 {'new_name': 'lala'}
import undefined_import
haha( undefined_import)
# ++++++++++++++++++++++++++++++++++++++++++++++++++
--- rename.py
+++ rename.py
@@ -1,4 +1,4 @@
#? 20 {'new_name': 'lala'}
-import undefined_import
-haha( undefined_import)
+import lala
+haha( lala)
# -------------------------------------------------- in-package-with-stub
#? 31 {'new_name': 'renamedm'}
from import_tree.pkgx import pkgx
# ++++++++++++++++++++++++++++++++++++++++++++++++++
--- import_tree/pkgx/__init__.py
+++ import_tree/pkgx/__init__.py
@@ -1,3 +1,3 @@
-def pkgx():
+def renamedm():
pass
--- import_tree/pkgx/__init__.pyi
+++ import_tree/pkgx/__init__.pyi
@@ -1,2 +1,2 @@
-def pkgx() -> int: ...
+def renamedm() -> int: ...
--- import_tree/pkgx/mod.pyi
+++ import_tree/pkgx/mod.pyi
@@ -1,2 +1,2 @@
-from . import pkgx
+from . import renamedm
--- rename.py
+++ rename.py
@@ -1,3 +1,3 @@
#? 31 {'new_name': 'renamedm'}
-from import_tree.pkgx import pkgx
+from import_tree.pkgx import renamedm
# -------------------------------------------------- package-with-stub
#? 18 {'new_name': 'renamedp'}
from import_tree.pkgx
# ++++++++++++++++++++++++++++++++++++++++++++++++++
rename from import_tree/pkgx
rename to import_tree/renamedp
--- import_tree/pkgx/mod2.py
+++ import_tree/renamedp/mod2.py
@@ -1,2 +1,2 @@
-from .. import pkgx
+from .. import renamedp
--- rename.py
+++ rename.py
@@ -1,3 +1,3 @@
#? 18 {'new_name': 'renamedp'}
-from import_tree.pkgx
+from import_tree.renamedp
# -------------------------------------------------- weird-package-mix
if random_undefined_variable:
from import_tree.pkgx import pkgx
else:
from import_tree import pkgx
#? 4 {'new_name': 'rename'}
pkgx
# ++++++++++++++++++++++++++++++++++++++++++++++++++
rename from import_tree/pkgx
rename to import_tree/rename
--- import_tree/pkgx/__init__.py
+++ import_tree/rename/__init__.py
@@ -1,3 +1,3 @@
-def pkgx():
+def rename():
pass
--- import_tree/pkgx/__init__.pyi
+++ import_tree/rename/__init__.pyi
@@ -1,2 +1,2 @@
-def pkgx() -> int: ...
+def rename() -> int: ...
--- import_tree/pkgx/mod.pyi
+++ import_tree/rename/mod.pyi
@@ -1,2 +1,2 @@
-from . import pkgx
+from . import rename
--- import_tree/pkgx/mod2.py
+++ import_tree/rename/mod2.py
@@ -1,2 +1,2 @@
-from .. import pkgx
+from .. import rename
--- rename.py
+++ rename.py
@@ -1,7 +1,7 @@
if random_undefined_variable:
- from import_tree.pkgx import pkgx
+ from import_tree.rename import rename
else:
- from import_tree import pkgx
+ from import_tree import rename
#? 4 {'new_name': 'rename'}
-pkgx
+rename

View File

@@ -1,14 +1,11 @@
#!/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.
|jedi| is mostly being tested by what I would call "integration tests". These
tests are testing type inference with the public API. This makes a
lot of sense for |jedi|. Also, it is hard to write doctests/unittests for
the internal data structures.
There are different kind of tests:
There are different kinds of tests:
- completions / inference ``#?``
- goto: ``#!``
@@ -18,29 +15,31 @@ How to run tests?
+++++++++++++++++
Jedi uses pytest_ to run unit and integration tests. To run tests,
simply run ``pytest``. You can also use tox_ to run tests for
multiple Python versions.
simply run ``pytest``.
.. _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 /
inference), ``#!`` (goto), or ``#<`` (references).
Most integration test cases are located in the ``test/completion`` directory
and each test case starts with one of these comments:
- ``#?`` (completions / inference)
- ``#!`` (goto)
- ``#<`` (references)
There is also support for third party libraries. In a normal test run they are
not being executed, you have to provide a ``--thirdparty`` option.
In addition to standard `-k` and `-m` options in pytest, you can use the
`-T` (`--test-files`) option to specify integration test cases to run.
In addition to pytest's ``-k`` and ``-m`` options, you can use the
``-T`` (``--test-files`) option to specify which test cases should 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:
number of the test comment. Here are some examples:
Run tests only in ``basic.py`` and ``imports.py``::
Run tests only in ``completion/basic.py`` and ``completion/imports.py``::
pytest test/test_integration.py -T basic.py -T imports.py
Run test at line 4, 6, and 8 in ``basic.py``::
Run test at line 4, 6, and 8 in ``completion/basic.py``::
pytest test/test_integration.py -T basic.py:4,6,8
@@ -57,38 +56,30 @@ 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 Tests
+++++++++++++++++++++
Auto-Completion
Uses a comment to specify a test on the next line. The comment defines the
expected completions. The comment always begins with `#?`. The last row
symbolizes the cursor. For example::
#? ['upper']
a = 'foo'; a.upp
Inference Tests
+++++++++++++++
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.
Inference
+++++++++
Inference tests use the same symbols like completion tests. This is
possible because the completion tests are defined with a list::
Inference tests look very simliar. The difference is that inference tests don't
use brackets::
#? int()
ab = 3; ab
Goto
++++
Goto Tests
++++++++++
Tests look like this::
Goto Tests look like this::
abc = 1
#! ['abc=1']
@@ -100,13 +91,13 @@ describes the position of the test (otherwise it's just the end of line)::
#! 2 ['abc=1']
abc
References
++++++++++
Reference Tests
+++++++++++++++
Tests look like this::
abc = 1
#< abc@1,0 abc@3,0
#< (1,0), (3,0)
abc
"""
import os
@@ -124,7 +115,7 @@ import pytest
import jedi
from jedi import debug
from jedi._compatibility import unicode, is_py3
from jedi.api.classes import Definition
from jedi.api.classes import Name
from jedi.api.completion import get_user_context
from jedi import parser_utils
from jedi.api.environment import get_default_environment, get_system_environment
@@ -227,7 +218,7 @@ class IntegrationTestCase(BaseTestCase):
def comparison(definition):
suffix = '()' if definition.type == 'instance' else ''
return definition.desc_with_module + suffix
return definition.full_name + suffix
def definition(correct, correct_start, path):
should_be = set()
@@ -244,7 +235,7 @@ class IntegrationTestCase(BaseTestCase):
raise Exception('Could not resolve %s on line %s'
% (match.string, self.line_nr - 1))
should_be |= set(Definition(inference_state, r.name) for r in results)
should_be |= set(Name(inference_state, r.name) for r in results)
debug.dbg('Finished getting types', color='YELLOW')
# Because the objects have different ids, `repr`, then compare.
@@ -411,7 +402,7 @@ def collect_dir_tests(base_dir, test_files, check_thirdparty=False):
path = os.path.join(base_dir, f_name)
if is_py3:
with open(path, encoding='utf-8') as f:
with open(path, encoding='utf-8', newline='') as f:
source = f.read()
else:
with open(path) as f:
@@ -440,7 +431,7 @@ Options:
--pdb Enable pdb debugging on fail.
-d, --debug Enable text output debugging (please install ``colorama``).
--thirdparty Also run thirdparty tests (in ``completion/thirdparty``).
--env <dotted> A Python version, like 2.7, 3.4, etc.
--env <dotted> A Python version, like 2.7, 3.8, etc.
"""
if __name__ == '__main__':
import docopt

View File

@@ -141,7 +141,7 @@ def test_infer_on_generator(Script):
def test_goto_definition_not_multiple(Script):
"""
There should be only one Definition result if it leads back to the same
There should be only one result if it leads back to the same
origin (e.g. instance method)
"""

View File

@@ -304,7 +304,7 @@ def test_builtins(Script):
def test_signature_is_definition(Script):
"""
Through inheritance, a signature is a sub class of Definition.
Through inheritance, a signature is a sub class of Name.
Check if the attributes match.
"""
s = """class Spam(): pass\nSpam"""
@@ -316,7 +316,8 @@ def test_signature_is_definition(Script):
# Now compare all the attributes that a Signature must also have.
for attr_name in dir(definition):
dont_scan = ['defined_names', 'parent', 'goto_assignments', 'infer',
'params', 'get_signatures', 'execute', 'goto']
'params', 'get_signatures', 'execute', 'goto',
'desc_with_module']
if attr_name.startswith('_') or attr_name in dont_scan:
continue

View File

@@ -23,7 +23,7 @@ def test_basedefinition_type(Script, get_names):
"""
Return a list of definitions for parametrized tests.
:rtype: [jedi.api_classes.BaseDefinition]
:rtype: [jedi.api_classes.BaseName]
"""
source = dedent("""
import sys
@@ -193,7 +193,7 @@ def test_hashlib_params(Script, environment):
if environment.version_info < (3,):
pytest.skip()
script = Script(source='from hashlib import sha256')
script = Script('from hashlib import sha256')
c, = script.complete()
sig, = c.get_signatures()
assert [p.name for p in sig.params] == ['arg']
@@ -278,7 +278,7 @@ def test_parent_on_function(Script):
code = 'def spam():\n pass'
def_, = Script(code).goto(line=1, column=len('def spam'))
parent = def_.parent()
assert parent.name == ''
assert parent.name == '__main__'
assert parent.type == 'module'
@@ -328,7 +328,7 @@ def test_parent_on_closure(Script):
assert foo.parent().name == 'inner'
assert foo.parent().parent().name == 'bar'
assert foo.parent().parent().parent().name == 'Foo'
assert foo.parent().parent().parent().parent().name == ''
assert foo.parent().parent().parent().parent().name == '__main__'
assert inner_func.parent().name == 'bar'
assert inner_func.parent().parent().name == 'Foo'
@@ -344,7 +344,7 @@ def test_parent_on_comprehension(Script):
assert [name.name for name in ns] == ['spam', 'i']
assert ns[0].parent().name == ''
assert ns[0].parent().name == '__main__'
assert ns[0].parent().type == 'module'
assert ns[1].parent().name == 'spam'
assert ns[1].parent().type == 'function'
@@ -375,7 +375,7 @@ def test_type_II(Script):
"""
This tests the BaseDefinition.goto function, not the jedi
This tests the BaseName.goto function, not the jedi
function. They are not really different in functionality, but really
different as an implementation.
"""

View File

@@ -6,7 +6,7 @@ from textwrap import dedent
import pytest
from ..helpers import root_dir
from jedi.api.helpers import start_match, fuzzy_match
from jedi.api.helpers import _start_match, _fuzzy_match
from jedi._compatibility import scandir
@@ -92,11 +92,11 @@ def test_complete_expanduser(Script):
non_dots = [p for p in possibilities if not p.name.startswith('.') and len(p.name) > 1]
item = non_dots[0]
line = "'~%s%s'" % (os.sep, item.name)
s = Script(line, line=1, column=len(line)-1)
s = Script(line)
expected_name = item.name
if item.is_dir():
expected_name += os.path.sep
assert expected_name in [c.name for c in s.completions()]
assert expected_name in [c.name for c in s.complete(column=len(line)-1)]
def test_fake_subnodes(Script):
@@ -312,62 +312,66 @@ def test_file_path_completions(Script, file, code, column, expected):
assert [c.complete for c in comps] == expected
def test_file_path_should_have_completions(Script):
assert Script('r"').complete() # See GH #1503
_dict_keys_completion_tests = [
('ints[', 5, ['1', '50', Ellipsis]),
('ints[]', 5, ['1', '50', Ellipsis]),
('ints[1]', 5, ['1', '50', Ellipsis]),
('ints[1]', 6, ['']),
('ints[1', 5, ['1', '50', Ellipsis]),
('ints[1', 6, ['']),
('ints[', 5, ['1', '50', Ellipsis]),
('ints[]', 5, ['1', '50', Ellipsis]),
('ints[1]', 5, ['1', '50', Ellipsis]),
('ints[1]', 6, ['']),
('ints[1', 5, ['1', '50', Ellipsis]),
('ints[1', 6, ['']),
('ints[5]', 5, ['1', '50', Ellipsis]),
('ints[5]', 6, ['0']),
('ints[50', 5, ['1', '50', Ellipsis]),
('ints[5', 6, ['0']),
('ints[ 5', None, ['0']),
('ints [ 5', None, ['0']),
('ints[50', 6, ['0']),
('ints[50', 7, ['']),
('ints[5]', 5, ['1', '50', Ellipsis]),
('ints[5]', 6, ['0']),
('ints[50', 5, ['1', '50', Ellipsis]),
('ints[5', 6, ['0']),
('ints[ 5', None, ['0']),
('ints [ 5', None, ['0']),
('ints[50', 6, ['0']),
('ints[50', 7, ['']),
('strs[', 5, ["'asdf'", "'fbar'", "'foo'", Ellipsis]),
('strs[]', 5, ["'asdf'", "'fbar'", "'foo'", Ellipsis]),
("strs['", 6, ["asdf'", "fbar'", "foo'"]),
("strs[']", 6, ["asdf'", "fbar'", "foo'"]),
('strs["]', 6, ['asdf"', 'fbar"', 'foo"']),
('strs["""]', 6, ['asdf', 'fbar', 'foo']),
('strs["""]', 8, ['asdf"""', 'fbar"""', 'foo"""']),
('strs[b"]', 8, []),
('strs[r"asd', 10, ['f"']),
('strs[r"asd"', 10, ['f']),
('strs[R"asd', 10, ['f"']),
('strs[ R"asd', None, ['f"']),
('strs[\tR"asd', None, ['f"']),
('strs[\nR"asd', None, ['f"']),
('strs[f"asd', 10, []),
('strs[br"""asd', 13, ['f"""']),
('strs[br"""asd"""', 13, ['f']),
('strs[ \t"""asd"""', 13, ['f']),
('strs[', 5, ["'asdf'", "'fbar'", "'foo'", Ellipsis]),
('strs[]', 5, ["'asdf'", "'fbar'", "'foo'", Ellipsis]),
("strs['", 6, ["asdf'", "fbar'", "foo'"]),
("strs[']", 6, ["asdf'", "fbar'", "foo'"]),
('strs["]', 6, ['asdf"', 'fbar"', 'foo"']),
('strs["""]', 6, ['asdf', 'fbar', 'foo']),
('strs["""]', 8, ['asdf"""', 'fbar"""', 'foo"""']),
('strs[b"]', 8, []),
('strs[r"asd', 10, ['f"']),
('strs[r"asd"', 10, ['f']),
('strs[R"asd', 10, ['f"']),
('strs[ R"asd', None, ['f"']),
('strs[\tR"asd', None, ['f"']),
('strs[\nR"asd', None, ['f"']),
('strs[f"asd', 10, []),
('strs[br"""asd', 13, ['f"""']),
('strs[br"""asd"""', 13, ['f']),
('strs[ \t"""asd"""', 13, ['f']),
('strs["f', 7, ['bar"', 'oo"']),
('strs["f"', 7, ['bar', 'oo']),
('strs["f]', 7, ['bar"', 'oo"']),
('strs["f"]', 7, ['bar', 'oo']),
('strs["f', 7, ['bar"', 'oo"']),
('strs["f"', 7, ['bar', 'oo']),
('strs["f]', 7, ['bar"', 'oo"']),
('strs["f"]', 7, ['bar', 'oo']),
('mixed[', 6, [r"'a\\sdf'", '1', '1.1', "b'foo'", Ellipsis]),
('mixed[1', 7, ['', '.1']),
('mixed[Non', 9, ['e']),
('mixed[', 6, [r"'a\\sdf'", '1', '1.1', "b'foo'", Ellipsis]),
('mixed[1', 7, ['', '.1']),
('mixed[Non', 9, ['e']),
('casted["f', 9, ['3"', 'bar"', 'oo"']),
('casted["f"', 9, ['3', 'bar', 'oo']),
('casted["f3', 10, ['"']),
('casted["f3"', 10, ['']),
('casted_mod["f', 13, ['3"', 'bar"', 'oo"', 'ull"', 'uuu"']),
('casted["f', 9, ['3"', 'bar"', 'oo"']),
('casted["f"', 9, ['3', 'bar', 'oo']),
('casted["f3', 10, ['"']),
('casted["f3"', 10, ['']),
('casted_mod["f', 13, ['3"', 'bar"', 'oo"', 'ull"', 'uuu"']),
('keywords["', None, ['a"']),
('keywords[Non', None, ['e']),
('keywords[Fa', None, ['lse']),
('keywords[Tr', None, ['ue']),
('keywords[str', None, ['', 's']),
('keywords["', None, ['a"']),
('keywords[Non', None, ['e']),
('keywords[Fa', None, ['lse']),
('keywords[Tr', None, ['ue']),
('keywords[str', None, ['', 's']),
]
@@ -399,15 +403,15 @@ def test_dict_keys_completions(Script, added_code, column, expected, skip_pre_py
def test_start_match():
assert start_match('Condition', 'C')
assert _start_match('Condition', 'C')
def test_fuzzy_match():
assert fuzzy_match('Condition', 'i')
assert not fuzzy_match('Condition', 'p')
assert fuzzy_match('Condition', 'ii')
assert not fuzzy_match('Condition', 'Ciito')
assert fuzzy_match('Condition', 'Cdiio')
assert _fuzzy_match('Condition', 'i')
assert not _fuzzy_match('Condition', 'p')
assert _fuzzy_match('Condition', 'ii')
assert not _fuzzy_match('Condition', 'Ciito')
assert _fuzzy_match('Condition', 'Cdiio')
def test_ellipsis_completion(Script):
@@ -446,7 +450,7 @@ def test_completion_cache(Script, module_injector):
@pytest.mark.parametrize('module', ['typing', 'os'])
def test_module_completions(Script, module):
for c in Script('import {module}; {module}.'.format(module=module)).completions():
for c in Script('import {module}; {module}.'.format(module=module)).complete():
# Just make sure that there are no errors
c.type
c.docstring()

View File

@@ -87,7 +87,7 @@ def test_version_info(Script):
sys.version_info"""))
c, = s.completions()
c, = s.complete()
assert c.docstring() == 'sys.version_info\n\nVersion information as a named tuple.'

View File

@@ -27,7 +27,7 @@ def test_find_system_environments():
@pytest.mark.parametrize(
'version',
['2.7', '3.4', '3.5', '3.6', '3.7']
['2.7', '3.5', '3.6', '3.7']
)
def test_versions(version):
try:
@@ -118,9 +118,10 @@ def test_create_environment_executable():
assert environment.executable == sys.executable
@pytest.mark.skipif(sys.version_info[0] == 2, reason="Ignore Python 2, because EOL")
def test_get_default_environment_from_env_does_not_use_safe(tmpdir, monkeypatch):
fake_python = os.path.join(str(tmpdir), 'fake_python')
with open(fake_python, 'w') as f:
with open(fake_python, 'w', newline='') as f:
f.write('')
def _get_subprocess(self):

View File

@@ -1,5 +1,5 @@
"""
Tests for :attr:`.BaseDefinition.full_name`.
Tests for :attr:`.BaseName.full_name`.
There are three kinds of test:
@@ -121,3 +121,10 @@ def test_param_name(Script):
name, = Script('class X:\n def foo(bar): bar''').goto()
assert name.type == 'param'
assert name.full_name is None
def test_variable_in_func(Script):
names = Script('def f(): x = 3').get_names(all_scopes=True)
x = names[-1]
assert x.name == 'x'
assert x.full_name == '__main__.f.x'

View File

@@ -123,23 +123,17 @@ def _assert_interpreter_complete(source, namespace, completions,
def test_complete_raw_function():
from os.path import join
_assert_interpreter_complete('join("").up',
locals(),
['upper'])
_assert_interpreter_complete('join("").up', locals(), ['upper'])
def test_complete_raw_function_different_name():
from os.path import join as pjoin
_assert_interpreter_complete('pjoin("").up',
locals(),
['upper'])
_assert_interpreter_complete('pjoin("").up', locals(), ['upper'])
def test_complete_raw_module():
import os
_assert_interpreter_complete('os.path.join("a").up',
locals(),
['upper'])
_assert_interpreter_complete('os.path.join("a").up', locals(), ['upper'])
def test_complete_raw_instance():
@@ -148,31 +142,19 @@ def test_complete_raw_instance():
completions = ['time', 'timetz', 'timetuple']
if is_py3:
completions += ['timestamp']
_assert_interpreter_complete('(dt - dt).ti',
locals(),
completions)
_assert_interpreter_complete('(dt - dt).ti', locals(), completions)
def test_list():
array = ['haha', 1]
_assert_interpreter_complete('array[0].uppe',
locals(),
['upper'])
_assert_interpreter_complete('array[0].real',
locals(),
[])
_assert_interpreter_complete('array[0].uppe', locals(), ['upper'])
_assert_interpreter_complete('array[0].real', locals(), [])
# something different, no index given, still just return the right
_assert_interpreter_complete('array[int].real',
locals(),
['real'])
_assert_interpreter_complete('array[int()].real',
locals(),
['real'])
_assert_interpreter_complete('array[int].real', locals(), ['real'])
_assert_interpreter_complete('array[int()].real', locals(), ['real'])
# inexistent index
_assert_interpreter_complete('array[2].upper',
locals(),
['upper'])
_assert_interpreter_complete('array[2].upper', locals(), ['upper'])
def test_getattr():
@@ -186,9 +168,7 @@ def test_slice():
class Foo1:
bar = []
baz = 'xbarx'
_assert_interpreter_complete('getattr(Foo1, baz[1:-1]).append',
locals(),
['append'])
_assert_interpreter_complete('getattr(Foo1, baz[1:-1]).append', locals(), ['append'])
def test_getitem_side_effects():
@@ -698,5 +678,5 @@ def bar():
def test_string_annotation(annotations, result, code):
x = lambda foo: 1
x.__annotations__ = annotations
defs = jedi.Interpreter(code or 'x()', [locals()]).goto_definitions()
defs = jedi.Interpreter(code or 'x()', [locals()]).infer()
assert [d.name for d in defs] == result

View File

@@ -1,6 +1,9 @@
import os
import sys
from ..helpers import get_example_dir, set_cwd, root_dir
import pytest
from ..helpers import get_example_dir, set_cwd, root_dir, test_dir
from jedi import Interpreter
from jedi.api import Project, get_default_project
@@ -38,3 +41,113 @@ def test_load_save_project(tmpdir):
loaded = Project.load(tmpdir.strpath)
assert loaded.added_sys_path == ['/foo']
@pytest.mark.parametrize(
'string, full_names, kwargs', [
('test_load_save_project', ['test_api.test_project.test_load_save_project'], {}),
('test_load_savep', [], dict(complete=True)),
('test_load_save_p', ['test_api.test_project.test_load_save_project'],
dict(complete=True)),
('test_load_save_p', ['test_api.test_project.test_load_save_project'],
dict(complete=True, all_scopes=True)),
('some_search_test_var', [], {}),
('some_search_test_var', ['test_api.test_project.test_search.some_search_test_var'],
dict(all_scopes=True)),
('some_search_test_var', ['test_api.test_project.test_search.some_search_test_var'],
dict(complete=True, all_scopes=True)),
('sample_int', ['helpers.sample_int'], {}),
('sample_int', ['helpers.sample_int'], dict(all_scopes=True)),
('sample_int.real', ['stub:builtins.int.real'], {}),
('class sample_int.real', [], {}),
('foo sample_int.real', [], {}),
('def sample_int.real', ['stub:builtins.int.real'], {}),
('function sample_int.real', ['stub:builtins.int.real'], {}),
# With modules
('test_project.test_search', ['test_api.test_project.test_search'], {}),
('test_project.test_searc', ['test_api.test_project.test_search'], dict(complete=True)),
('test_api.test_project.test_search', ['test_api.test_project.test_search'], {}),
('test_api.test_project.test_sear', ['test_api.test_project.test_search'],
dict(complete=True)),
# With namespace
('implicit_namespace_package.ns1.pkg',
['examples.implicit_namespace_package.ns1.pkg'], {}),
('implicit_namespace_package.ns1.pkg.ns1_file',
['examples.implicit_namespace_package.ns1.pkg.ns1_file'], {}),
('examples.implicit_namespace_package.ns1.pkg.ns1_file',
['examples.implicit_namespace_package.ns1.pkg.ns1_file'], {}),
('implicit_namespace_package.ns1.pkg.',
['examples.implicit_namespace_package.ns1.pkg.ns1_file'],
dict(complete=True)),
('implicit_namespace_package.',
['examples.implicit_namespace_package.ns1',
'examples.implicit_namespace_package.ns2'],
dict(complete=True)),
# With stubs
('with_python.module', ['examples.stub_packages.with_python.module'], {}),
('with_python.modul', ['examples.stub_packages.with_python.module'],
dict(complete=True)),
('no_python.foo', ['stub:examples.stub_packages.no_python.foo'], {}),
('no_python.fo', ['stub:examples.stub_packages.no_python.foo'],
dict(complete=True)),
('with_python-stubs.module', [], {}),
('no_python-stubs.foo', [], {}),
# Both locations are given, because they live in separate folders (one
# suffixed with -stubs.
('with_python', ['examples.stub_packages.with_python'], {}),
('no_python', ['stub:examples.stub_packages.no_python'], {}),
# Completion stubs
('stub_only', ['stub:completion.stub_folder.stub_only',
'stub:examples.stub_packages.with_python.stub_only'], {}),
('with_stub', ['completion.stub_folder.with_stub'], {}),
('with_stub.in_with_stub_both',
['completion.stub_folder.with_stub.in_with_stub_both'], {}),
('with_stub.in_with_stub_python',
['completion.stub_folder.with_stub.in_with_stub_python'], {}),
('with_stub.in_with_stub_stub',
['stub:completion.stub_folder.with_stub.in_with_stub_stub'], {}),
# Completion stubs: Folder
('with_stub_folder', ['completion.stub_folder.with_stub_folder'], {}),
('with_stub_folder.nested_with_stub',
['completion.stub_folder.with_stub_folder.nested_with_stub'], {}),
('nested_with_stub',
['completion.stub_folder.stub_only_folder.nested_with_stub',
'completion.stub_folder.with_stub_folder.nested_with_stub'], {}),
# On sys path
('sys.path', ['stub:sys.path'], {}),
('json.dumps', ['json.dumps'], {}), # stdlib + stub
('multiprocessing', ['multiprocessing'], {}),
('multiprocessin', ['multiprocessing'], dict(complete=True)),
]
)
@pytest.mark.skipif(sys.version_info < (3, 6), reason="Ignore Python 2, because EOL")
def test_search(string, full_names, kwargs, skip_pre_python36):
some_search_test_var = 1.0
project = Project(test_dir)
if kwargs.pop('complete', False) is True:
defs = project.complete_search(string, **kwargs)
else:
defs = project.search(string, **kwargs)
assert [('stub:' if d.is_stub() else '') + d.full_name for d in defs] == full_names
@pytest.mark.parametrize(
'string, completions, all_scopes', [
('SomeCl', ['ass'], False),
('twic', [], False),
('twic', ['e', 'e'], True),
('test_load_save_p', ['roject'], False),
]
)
@pytest.mark.skipif(sys.version_info < (3, 6), reason="Ignore Python 2, because EOL")
def test_complete_search(Script, string, completions, all_scopes, skip_pre_python36):
project = Project(test_dir)
defs = project.complete_search(string, all_scopes=all_scopes)
assert [d.complete for d in defs] == completions

View File

@@ -0,0 +1,64 @@
import os
import sys
from textwrap import dedent
import pytest
import jedi
@pytest.fixture(autouse=True)
def skip_old_python(skip_pre_python36):
if sys.version_info < (3, 6):
pytest.skip()
@pytest.fixture()
def dir_with_content(tmpdir):
with open(os.path.join(tmpdir.strpath, 'modx.py'), 'w', newline='') as f:
f.write('import modx\nfoo\n') # self reference
return tmpdir.strpath
def test_rename_mod(Script, dir_with_content):
script = Script(
'import modx; modx\n',
path=os.path.join(dir_with_content, 'some_script.py'),
project=jedi.Project(dir_with_content),
)
refactoring = script.rename(line=1, new_name='modr')
refactoring.apply()
p1 = os.path.join(dir_with_content, 'modx.py')
p2 = os.path.join(dir_with_content, 'modr.py')
expected_code = 'import modr\nfoo\n'
assert not os.path.exists(p1)
with open(p2, newline='') as f:
assert f.read() == expected_code
assert refactoring.get_renames() == [(p1, p2)]
assert refactoring.get_changed_files()[p1].get_new_code() == expected_code
assert refactoring.get_diff() == dedent('''\
rename from modx.py
rename to modr.py
--- modx.py
+++ modr.py
@@ -1,3 +1,3 @@
-import modx
+import modr
foo
--- some_script.py
+++ some_script.py
@@ -1,2 +1,2 @@
-import modx; modx
+import modr; modr
''').format(dir=dir_with_content)
def test_rename_none_path(Script):
refactoring = Script('foo', path=None).rename(new_name='bar')
with pytest.raises(jedi.RefactoringError, match='on a Script with path=None'):
refactoring.apply()
assert refactoring

View File

@@ -0,0 +1,92 @@
import os
import sys
import pytest
class SomeClass:
class SomeClass:
def twice(self, a):
something = os
return something
def twice(self, b):
pass
def some_function():
pass
@pytest.mark.parametrize(
'string, descriptions, kwargs', [
# No completions
('SomeClass', ['class SomeClass'], {}),
('SomeClass', ['class SomeClass', 'class SomeClass.SomeClass'], dict(all_scopes=True)),
('Some', [], dict(all_scopes=True)),
('os', ['module os'], {}),
('sys', ['module sys'], {}),
('sys.path', ['statement sys.path'], {}),
('sys.exit', ['function sys.exit'], {}),
('something', [], {}),
('something', ['statement SomeClass.SomeClass.twice.something'], dict(all_scopes=True)),
# Completions
('class Some', ['class SomeClass', 'class SomeClass.SomeClass'],
dict(all_scopes=True, complete=True)),
('class Some', ['class SomeClass'], dict(complete=True)),
('Some', ['class SomeClass', 'class SomeClass.SomeClass',
'statement SomeClass.SomeClass.twice.something',
'function SomeClass.some_function'], dict(all_scopes=True, complete=True)),
('some', ['class SomeClass', 'class SomeClass.SomeClass',
'statement SomeClass.SomeClass.twice.something',
'function SomeClass.some_function'], dict(all_scopes=True, complete=True)),
# Fuzzy
('class Smelss', ['class SomeClass'], dict(complete=True, fuzzy=True)),
('class Smelss', ['class SomeClass', 'class SomeClass.SomeClass'],
dict(complete=True, fuzzy=True, all_scopes=True)),
# Nested
('SomeClass.SomeClass', ['class SomeClass.SomeClass'],
dict(all_scopes=True)),
('SomeClass.SomeClass.twice', ['function SomeClass.SomeClass.twice'],
dict(all_scopes=True)),
('SomeClass.SomeClass.twice.__call__', ['function types.FunctionType.__call__'],
dict(all_scopes=True)),
('SomeClass.SomeClass.twice.something', [], dict(all_scopes=True)),
('SomeClass.twice', ['function SomeClass.twice', 'function SomeClass.SomeClass.twice'],
dict(all_scopes=True)),
# Nested completions
('SomeClass.twi', ['function SomeClass.twice', 'function SomeClass.SomeClass.twice'],
dict(all_scopes=True, complete=True)),
# Fuzzy unfortunately doesn't work
('SomeCl.twice', [], dict(all_scopes=True, complete=True, fuzzy=True)),
]
)
def test_simple_search(Script, string, descriptions, kwargs, skip_pre_python36):
if sys.version_info < (3, 6):
pytest.skip()
if kwargs.pop('complete', False) is True:
defs = Script(path=__file__).complete_search(string, **kwargs)
else:
defs = Script(path=__file__).search(string, **kwargs)
this_mod = 'test.test_api.test_search.'
assert [d.type + ' ' + d.full_name.replace(this_mod, '') for d in defs] == descriptions
@pytest.mark.parametrize(
'string, completions, fuzzy, all_scopes', [
('SomeCl', ['ass'], False, False),
('SomeCl', [None], True, False),
('twic', [], False, False),
('some_f', [], False, False),
('twic', ['e', 'e'], False, True),
('some_f', ['unction'], False, True),
]
)
def test_complete_search(Script, string, completions, fuzzy, all_scopes):
defs = Script(path=__file__).complete_search(string, fuzzy=fuzzy, all_scopes=all_scopes)
assert [d.complete for d in defs] == completions

View File

@@ -74,9 +74,3 @@ def test_wrong_encoding(Script, tmpdir):
project = Project('.', sys_path=[tmpdir.strpath])
c, = Script('import x; x.foo', project=project).complete()
assert c.name == 'foobar'
def test_encoding_parameter(Script):
name = u('')
s = Script(name.encode('latin-1'), encoding='latin-1')
assert s._module_node.get_code() == name

View File

@@ -5,22 +5,14 @@ from jedi._compatibility import highest_pickle_protocol
def test_highest_pickle_protocol():
v = namedtuple('version', 'major, minor')
assert highest_pickle_protocol([v(2, 7), v(2, 7)]) == 2
assert highest_pickle_protocol([v(2, 7), v(3, 3)]) == 2
assert highest_pickle_protocol([v(2, 7), v(3, 4)]) == 2
assert highest_pickle_protocol([v(2, 7), v(3, 8)]) == 2
assert highest_pickle_protocol([v(2, 7), v(3, 5)]) == 2
assert highest_pickle_protocol([v(2, 7), v(3, 6)]) == 2
assert highest_pickle_protocol([v(3, 3), v(2, 7)]) == 2
assert highest_pickle_protocol([v(3, 3), v(3, 3)]) == 3
assert highest_pickle_protocol([v(3, 3), v(3, 4)]) == 3
assert highest_pickle_protocol([v(3, 3), v(3, 5)]) == 3
assert highest_pickle_protocol([v(3, 3), v(3, 6)]) == 3
assert highest_pickle_protocol([v(3, 4), v(2, 7)]) == 2
assert highest_pickle_protocol([v(3, 4), v(3, 3)]) == 3
assert highest_pickle_protocol([v(3, 4), v(3, 4)]) == 4
assert highest_pickle_protocol([v(3, 4), v(3, 5)]) == 4
assert highest_pickle_protocol([v(3, 4), v(3, 6)]) == 4
assert highest_pickle_protocol([v(3, 8), v(2, 7)]) == 2
assert highest_pickle_protocol([v(3, 8), v(3, 8)]) == 4
assert highest_pickle_protocol([v(3, 8), v(3, 5)]) == 4
assert highest_pickle_protocol([v(3, 8), v(3, 6)]) == 4
assert highest_pickle_protocol([v(3, 6), v(2, 7)]) == 2
assert highest_pickle_protocol([v(3, 6), v(3, 3)]) == 3
assert highest_pickle_protocol([v(3, 6), v(3, 4)]) == 4
assert highest_pickle_protocol([v(3, 6), v(3, 8)]) == 4
assert highest_pickle_protocol([v(3, 6), v(3, 5)]) == 4
assert highest_pickle_protocol([v(3, 6), v(3, 6)]) == 4

View File

@@ -1,3 +1,18 @@
# -*- coding: utf-8 -*-
import warnings
import pytest
from jedi._compatibility import u
@pytest.fixture(autouse=True)
def check_for_warning(recwarn):
warnings.simplefilter("always")
with pytest.warns(DeprecationWarning):
yield
def test_goto_definitions(Script):
int_, = Script('x = 1\nx, y\ny', line=2, column=0).goto_definitions()
assert int_.name == 'int'
@@ -25,3 +40,9 @@ def test_usages(Script):
def test_call_signatures(Script):
d1, = Script('abs(float(\nstr(', line=1, column=4).call_signatures()
assert d1.name == 'abs'
def test_encoding_parameter(Script):
name = u('')
s = Script(name.encode('latin-1'), encoding='latin-1')
assert s._module_node.get_code() == name

View File

@@ -67,7 +67,7 @@ def test_path_from_sys_path_assignment(Script):
import sys
sys.path[0:0] = [
'/usr/lib/python3.4/site-packages',
'/usr/lib/python3.8/site-packages',
'/home/test/.buildout/eggs/important_package.egg'
]

View File

@@ -33,9 +33,9 @@ def test_get_signatures_stdlib(Script):
assert len(sigs[0].params) == 1
# Check only on linux 64 bit platform and Python3.4.
# Check only on linux 64 bit platform and Python3.8.
@pytest.mark.parametrize('load_unsafe_extensions', [False, True])
@pytest.mark.skipif('sys.platform != "linux" or sys.maxsize <= 2**32 or sys.version_info[:2] != (3, 4)')
@pytest.mark.skipif('sys.platform != "linux" or sys.maxsize <= 2**32 or sys.version_info[:2] != (3, 8)')
def test_init_extension_module(Script, load_unsafe_extensions):
"""
``__init__`` extension modules are also packages and Jedi should understand
@@ -45,10 +45,10 @@ def test_init_extension_module(Script, load_unsafe_extensions):
This test was built by the module.c and setup.py combination you can find
in the init_extension_module folder. You can easily build the
`__init__.cpython-34m.so` by compiling it (create a virtualenv and run
`__init__.cpython-38m.so` by compiling it (create a virtualenv and run
`setup.py install`.
This is also why this test only runs on certain systems (and Python 3.4).
This is also why this test only runs on certain systems and Python 3.8.
"""
project = jedi.Project(get_example_dir(), load_unsafe_extensions=load_unsafe_extensions)

View File

@@ -45,7 +45,7 @@ def test_infer_and_goto(Script, code, full_name, has_stub, has_python, way,
kwargs, type_, options, environment):
if environment.version_info < (3, 5):
# We just don't care about much of the detailed Python 2 failures
# anymore, because its end-of-life soon. (same for 3.4)
# anymore, because its end-of-life soon.
pytest.skip()
if type_ == 'infer' and full_name == 'typing.Sequence' and environment.version_info >= (3, 7):

View File

@@ -24,9 +24,6 @@ def test_get_typeshed_directories():
dirs = get_dirs(PythonVersionInfo(2, 7))
assert dirs == transform({'stdlib/2and3', 'stdlib/2', 'third_party/2and3', 'third_party/2'})
dirs = get_dirs(PythonVersionInfo(3, 4))
assert dirs == transform({'stdlib/2and3', 'stdlib/3', 'third_party/2and3', 'third_party/3'})
dirs = get_dirs(PythonVersionInfo(3, 5))
assert dirs == transform({'stdlib/2and3', 'stdlib/3',
'third_party/2and3', 'third_party/3'})
@@ -139,10 +136,13 @@ def test_math(Script):
assert value
def test_type_var(Script):
def test_type_var(Script, environment):
def_, = Script('import typing; T = typing.TypeVar("T1")').infer()
assert def_.name == 'TypeVar'
assert def_.description == 'TypeVar = object()'
if environment.version_info.major == 2:
assert def_.description == 'TypeVar = object()'
else:
assert def_.description == 'class TypeVar'
@pytest.mark.parametrize(

View File

@@ -8,7 +8,7 @@ from jedi import Project
@pytest.fixture(autouse=True)
def skip_not_supported_versions(environment):
if environment.version_info < (3, 4):
if environment.version_info < (3, 5):
pytest.skip()
@@ -58,9 +58,9 @@ def test_implicit_nested_namespace_package(Script):
code = 'from implicit_nested_namespaces.namespace.pkg.module import CONST'
project = Project('.', sys_path=[example_dir])
script = Script(project=project, source=code, line=1, column=61)
script = Script(code, project=project)
result = script.infer()
result = script.infer(line=1, column=61)
assert len(result) == 1
@@ -70,41 +70,41 @@ def test_implicit_nested_namespace_package(Script):
def test_implicit_namespace_package_import_autocomplete(Script):
CODE = 'from implicit_name'
code = 'from implicit_name'
project = Project('.', sys_path=[example_dir])
script = Script(project=project, source=CODE)
script = Script(code, project=project)
compl = script.complete()
assert [c.name for c in compl] == ['implicit_namespace_package']
def test_namespace_package_in_multiple_directories_autocompletion(Script):
CODE = 'from pkg.'
code = 'from pkg.'
sys_path = [get_example_dir('implicit_namespace_package', 'ns1'),
get_example_dir('implicit_namespace_package', 'ns2')]
project = Project('.', sys_path=sys_path)
script = Script(project=project, source=CODE)
script = Script(code, project=project)
compl = script.complete()
assert set(c.name for c in compl) == set(['ns1_file', 'ns2_file'])
def test_namespace_package_in_multiple_directories_goto_definition(Script):
CODE = 'from pkg import ns1_file'
code = 'from pkg import ns1_file'
sys_path = [get_example_dir('implicit_namespace_package', 'ns1'),
get_example_dir('implicit_namespace_package', 'ns2')]
project = Project('.', sys_path=sys_path)
script = Script(project=project, source=CODE)
script = Script(code, project=project)
result = script.infer()
assert len(result) == 1
def test_namespace_name_autocompletion_full_name(Script):
CODE = 'from pk'
code = 'from pk'
sys_path = [get_example_dir('implicit_namespace_package', 'ns1'),
get_example_dir('implicit_namespace_package', 'ns2')]
project = Project('.', sys_path=sys_path)
script = Script(project=project, source=CODE)
script = Script(code, project=project)
compl = script.complete()
assert set(c.full_name for c in compl) == set(['pkg'])

View File

@@ -7,7 +7,7 @@ import os
import pytest
from jedi.file_io import FileIO, KnownContentFileIO
from jedi.file_io import FileIO
from jedi._compatibility import find_module_py33, find_module
from jedi.inference import compiled
from jedi.inference import imports
@@ -259,7 +259,7 @@ def test_goto_following_on_imports(Script):
def test_goto(Script):
sys, = Script("import sys", 1, 10).goto(follow_imports=True)
sys, = Script("import sys").goto(follow_imports=True)
assert sys.type == 'module'
@@ -344,23 +344,6 @@ def test_get_modules_containing_name(inference_state, path, goal, is_package):
assert found_module.string_names == goal
@pytest.mark.parametrize(
('path', 'base_names', 'is_package', 'names'), [
('/foo/bar.py', ('foo',), False, ('foo', 'bar')),
('/foo/bar.py', ('foo', 'baz'), False, ('foo', 'baz', 'bar')),
('/foo/__init__.py', ('foo',), True, ('foo',)),
('/__init__.py', ('foo',), True, ('foo',)),
('/foo/bar/__init__.py', ('foo',), True, ('foo',)),
('/foo/bar/__init__.py', ('foo', 'bar'), True, ('foo', 'bar')),
]
)
def test_load_module_from_path(inference_state, path, base_names, is_package, names):
file_io = KnownContentFileIO(path, '')
m = imports.load_module_from_path(inference_state, file_io, base_names)
assert m.is_package() == is_package
assert m.string_names == names
@pytest.mark.parametrize(
'path', ('api/whatever/test_this.py', 'api/whatever/file'))
@pytest.mark.parametrize('empty_sys_path', (False, True))
@@ -489,6 +472,6 @@ def test_relative_import_star(Script):
from . import *
furl.c
"""
script = Script(source, 'export.py')
script = Script(source, path='export.py')
assert script.complete(3, len("furl.c"))

View File

@@ -71,9 +71,7 @@ def test_nested_namespace_package(Script):
sys_path = [example_dir]
project = Project('.', sys_path=sys_path)
script = Script(project=project, source=code)
result = script.infer(line=1, column=45)
result = Script(code, project=project).infer(line=1, column=45)
assert len(result) == 1
@@ -82,7 +80,7 @@ def test_relative_import(Script, environment, tmpdir):
"""
Attempt a relative import in a very simple namespace package.
"""
if environment.version_info < (3, 4):
if environment.version_info < (3, 5):
pytest.skip()
directory = get_example_dir('namespace_package_relative_import')

View File

@@ -29,11 +29,11 @@ def pyc_project_path(tmpdir):
path = tmpdir.strpath
dummy_package_path = os.path.join(path, "dummy_package")
os.mkdir(dummy_package_path)
with open(os.path.join(dummy_package_path, "__init__.py"), 'w'):
with open(os.path.join(dummy_package_path, "__init__.py"), 'w', newline=''):
pass
dummy_path = os.path.join(dummy_package_path, 'dummy.py')
with open(dummy_path, 'w') as f:
with open(dummy_path, 'w', newline='') as f:
f.write(SRC)
import compileall
compileall.compile_file(dummy_path)
@@ -56,6 +56,7 @@ def pyc_project_path(tmpdir):
@pytest.mark.parametrize('load_unsafe_extensions', [False, True])
@pytest.mark.skipif(sys.version_info[0] == 2, reason="Ignore Python 2, because EOL")
def test_pyc(pyc_project_path, environment, load_unsafe_extensions):
"""
The list of completion must be greater than 2.

View File

@@ -4,6 +4,8 @@ import sys
import pytest
from . import helpers
from jedi.common.utils import indent_block
from jedi import RefactoringError
def assert_case_equal(case, actual, desired):
@@ -16,9 +18,11 @@ def assert_case_equal(case, actual, desired):
"""
assert actual == desired, """
Test %r failed.
actual = %s
desired = %s
""" % (case, actual, desired)
actual =
%s
desired =
%s
""" % (case, indent_block(str(actual)), indent_block(str(desired)))
def assert_static_analysis(case, actual, desired):
@@ -56,15 +60,25 @@ def test_static_analysis(static_analysis_case, environment):
static_analysis_case.run(assert_static_analysis, environment)
def test_refactor(refactor_case):
def test_refactor(refactor_case, skip_pre_python36, environment):
"""
Run refactoring test case.
:type refactor_case: :class:`.refactor.RefactoringCase`
"""
if 0:
# TODO Refactoring is not relevant at the moment, it will be changed
# significantly in the future, but maybe we can use these tests:
refactor_case.run()
assert_case_equal(refactor_case,
refactor_case.result, refactor_case.desired)
if sys.version_info < (3, 6):
pytest.skip()
desired_result = refactor_case.get_desired_result()
if refactor_case.type == 'error':
with pytest.raises(RefactoringError) as e:
refactor_case.refactor(environment)
assert e.value.args[0] == desired_result.strip()
elif refactor_case.type == 'text':
refactoring = refactor_case.refactor(environment)
assert not refactoring.get_renames()
text = ''.join(f.get_new_code() for f in refactoring.get_changed_files().values())
assert_case_equal(refactor_case, text, desired_result)
else:
diff = refactor_case.refactor(environment).get_diff()
assert_case_equal(refactor_case, diff, desired_result)

View File

@@ -70,7 +70,7 @@ def test_add_to_end(Script):
" self."
def complete(code, line=None, column=None):
script = Script(code, 'example.py')
script = Script(code, path='example.py')
assert script.complete(line, column)
complete(a, 7, 12)