1
0
forked from VimPlug/jedi

Merge branch 'master' into pytest

This commit is contained in:
Dave Halter
2019-05-20 00:21:57 +02:00
committed by GitHub
178 changed files with 7689 additions and 4031 deletions

View File

@@ -30,7 +30,7 @@ b = [6,7]
#? int()
b[8-7]
# Something unreasonable:
#?
#? int()
b['']
# -----------------
@@ -45,7 +45,7 @@ b[int():]
#? list()
b[:]
#?
#? int()
b[:, 1]
class _StrangeSlice():
@@ -161,7 +161,7 @@ def a(): return ''
#? str()
(a)()
#? str()
(a)().replace()
(a)().title()
#? int()
(tuple).index()
#? int()
@@ -209,8 +209,7 @@ g
dic2 = {'asdf': 3, 'b': 'str'}
#? int()
dic2['asdf']
# TODO for now get doesn't work properly when used with a literal.
#? None
#? None int() str()
dic2.get('asdf')
# string literal
@@ -268,11 +267,12 @@ for x in {1: 3.0, '': 1j}:
dict().values().__iter__
d = dict(a=3, b='')
x, = d.values()
#? int() str()
x
#? int() str()
d.values()[0]
#? int()
d['a']
#? int() None
#? int() str() None
d.get('a')
# -----------------
@@ -437,7 +437,7 @@ def test_func():
#? int()
tuple({1})[0]
# python >= 3.3
# python >= 3.4
# -----------------
# PEP 3132 Extended Iterable Unpacking (star unpacking)
# -----------------
@@ -445,7 +445,7 @@ tuple({1})[0]
a, *b, c = [1, 'b', list, dict]
#? int()
a
#? str()
#?
b
#? list
c
@@ -454,12 +454,14 @@ c
a, *b, *c = [1, 'd', list]
#? int()
a
#? str()
#?
b
#? list
#?
c
lc = [x for a, *x in [(1, '', 1.0)]]
#?
lc[0][0]
#?
lc[0][1]

View File

@@ -154,6 +154,9 @@ def global_define():
#? int()
global_var_in_func
#? ['global_var_in_func']
global_var_in_f
def funct1():
# From issue #610
@@ -175,6 +178,7 @@ def init_global_var_predefined():
#? int() None
global_var_predefined
# -----------------
# within docstrs
# -----------------
@@ -300,7 +304,7 @@ with open('') as f:
#? ['closed']
f.closed
for line in f:
#? str()
#? str() bytes()
line
with open('') as f1, open('') as f2:

View File

@@ -36,6 +36,7 @@ class TestClass(object):
self2.var_inst = first_param
self2.second = second_param
self2.first = first_param
self2.first.var_on_argument = 5
a = 3
def var_func(self):
@@ -57,6 +58,8 @@ class TestClass(object):
# should not know any class functions!
#? []
values
#?
values
#? ['return']
ret
return a1
@@ -417,6 +420,9 @@ class PrivateVar():
def __private_func(self):
return 1
#? int()
__private_func()
def wrap_private(self):
return self.__private_func()
#? []
@@ -425,6 +431,8 @@ PrivateVar().__var
PrivateVar().__var
#? []
PrivateVar().__private_func
#? []
PrivateVar.__private_func
#? int()
PrivateVar().wrap_private()
@@ -571,3 +579,26 @@ class Foo(object):
#? int()
Foo().b
# -----------------
# default arguments
# -----------------
default = ''
class DefaultArg():
default = 3
def x(self, arg=default):
#? str()
default
return arg
def y(self):
return default
#? int()
DefaultArg().x()
#? str()
DefaultArg().y()
#? int()
DefaultArg.x()
#? str()
DefaultArg.y()

View File

@@ -52,12 +52,12 @@ left
[a for a in {1:'x'}][0]
# list comprehensions should also work in combination with functions
def listen(arg):
def _listen(arg):
for x in arg:
#? str()
x
listen(['' for x in [1]])
_listen(['' for x in [1]])
#?
([str for x in []])[0]
@@ -212,3 +212,14 @@ next(iter({a for a in range(10)}))
#? int()
[a for a in {1, 2, 3}][0]
# -----------------
# syntax errors
# -----------------
# Issue #1146
#? ['list']
[int(str(x.value) for x in list
def reset_missing_bracket(): pass

View File

@@ -16,8 +16,18 @@ class Y(X):
#? ['func']
def f
#? ['__doc__']
__doc__
#? []
def __doc__
# This might or might not be what we wanted, currently properties are also
# used like this. IMO this is not wanted ~dave.
#? ['__class__']
def __class__
#? []
__class__
#? ['__repr__']
def __repr__

View File

@@ -55,9 +55,10 @@ list(arr)[10]
arr = [1.0]
arr.extend([1,2,3])
arr.extend([])
arr.extend("") # should ignore
arr.extend("")
arr.extend(list) # should ignore
#? float() int()
#? float() int() str()
arr[100]
a = set(arr)
@@ -94,7 +95,7 @@ arr2[0]
lst = [1]
lst.append(1.0)
s = set(lst)
s.add("")
s.add("ahh")
lst = list(s)
lst.append({})

View File

@@ -25,3 +25,14 @@ Fr'sasdf'
#? 7 str()
Fr'''sasdf''' + ''
#? ['upper']
f'xyz'.uppe
#? 3 []
f'f'
# Github #1248
#? int()
{"foo": 1}[f"foo"]

View File

@@ -319,6 +319,7 @@ exe['c']
a = 'a'
exe2 = kwargs_func(**{a:3,
'b':4.0})
#? int()
exe2['a']
#? float()
@@ -326,6 +327,19 @@ exe2['b']
#? int() float()
exe2['c']
exe3 = kwargs_func(**{k: v for k, v in [(a, 3), ('b', 4.0)]})
# Should resolve to the same as 2 but jedi is not smart enough yet
# Here to make sure it doesn't result in crash though
#?
exe3['a']
#?
exe3['b']
#?
exe3['c']
# -----------------
# *args / ** kwargs
# -----------------

View File

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

View File

@@ -120,6 +120,8 @@ import_tree.a
#! ['module mod1']
import import_tree.mod1
#! ['module mod1']
from import_tree.mod1
#! ['a = 1']
import_tree.mod1.a

View File

@@ -114,6 +114,31 @@ def as_imports():
bar.a
def broken_import():
import import_tree.mod1
#? import_tree.mod1
from import_tree.mod1
#? 25 import_tree.mod1
import import_tree.mod1.
#? 25 import_tree.mod1
impo5t import_tree.mod1.foo
#? 25 import_tree.mod1
import import_tree.mod1.foo.
#? 31 import_tree.mod1
import json, import_tree.mod1.foo.
# Cases with ;
mod1 = 3
#? 25 int()
import import_tree; mod1.
#? 38 import_tree.mod1
import_tree; import import_tree.mod1.
#! ['module json']
from json
def test_import_priorities():
"""
It's possible to overwrite import paths in an ``__init__.py`` file, by

View File

@@ -143,12 +143,12 @@ a3[0]
a = [for a in
def break(): pass
#?
#? str()
a[0]
a = [a for a in [1,2]
def break(): pass
#?
#? str()
a[0]
#? []

View File

@@ -18,13 +18,13 @@ b; continue
b; continu
#? []
c + brea
c + pass
#? []
a + break
a + pass
#? ['break']
b; break
#? ['pass']
b; pass
# -----------------
# Keywords should not appear everywhere.

View File

@@ -1,6 +1,6 @@
""" Pep-0484 type hinting """
# python >= 3.2
# python >= 3.4
class A():
@@ -68,7 +68,7 @@ def return_annotation_and_docstring() -> str:
"""
pass
#? str() int()
#? str()
return_annotation_and_docstring()
@@ -138,7 +138,7 @@ function_with_non_pep_0484_annotation(1, 2, 3, "force string")
def function_forward_reference_dynamic(
x: return_str_type(),
y: "return_str_type()") -> None:
#?
#? str()
x
#? str()
y

View File

@@ -40,6 +40,8 @@ def we_can_has_sequence(p, q, r, s, t, u):
t[1]
#? ["append"]
u.a
#? float() list()
u[1.0]
#? float()
u[1]
@@ -114,13 +116,9 @@ def tuple(p, q, r):
i, s, f = q
#? int()
i
##? str() --- TODO fix support for tuple assignment
# https://github.com/davidhalter/jedi/pull/663#issuecomment-172317854
#?
#? str()
s
##? float() --- TODO fix support for tuple assignment
# https://github.com/davidhalter/jedi/pull/663#issuecomment-172317854
#?
#? float()
f
class Key:
@@ -173,6 +171,21 @@ def mapping(p, q, d, dd, r, s, t):
key
#? Value()
value
for key, value in q.items():
#? Key()
key
#? Value()
value
for key, value in d.items():
#? Key()
key
#? Value()
value
for key, value in dd.items():
#? Key()
key
#? Value()
value
for key in r:
#? Key()
key
@@ -211,7 +224,7 @@ def optional(p):
as being of that type. Jedi doesn't do anything with the extra into that
it can be None as well
"""
#? int()
#? int() None
p
class ForwardReference:
@@ -243,7 +256,7 @@ for key in x.keys():
for value in x.values():
#? int()
value
# python >= 3.2
# python >= 3.4
class TestDefaultDict(typing.DefaultDict[str, int]):
def setdud(self):
@@ -271,7 +284,7 @@ for key in x.keys():
for value in x.values():
#? int()
value
# python >= 3.2
# python >= 3.4
"""
@@ -292,3 +305,49 @@ from typing import Union as U
def union4(x: U[int, str]):
#? int() str()
x
TYPE_VAR = typing.TypeVar('TYPE_VAR')
# TODO there should at least be some results.
#? []
TYPE_VAR.
#! ["TYPE_VAR = typing.TypeVar('TYPE_VAR')"]
TYPE_VAR
class WithTypeVar(typing.Generic[TYPE_VAR]):
def lala(self) -> TYPE_VAR:
...
def maaan(p: WithTypeVar[int]):
#? int()
p.lala()
if typing.TYPE_CHECKING:
with_type_checking = 1
else:
without_type_checking = 1.0
#? int()
with_type_checking
#?
without_type_checking
def foo(a: typing.List, b: typing.Dict, c: typing.MutableMapping) -> typing.Type[int]:
#? ['append']
a.appen
#? list()
a
#?
a[0]
#? ['setdefault']
b.setd
#? ['setdefault']
c.setd
#? typing.MutableMapping()
c
#?
c['asdf']
#? int
foo()

View File

@@ -36,3 +36,18 @@ char: str
for char in NOT_DEFINED:
#? str()
char
class Foo():
bar: int
baz: typing.ClassVar[str]
#? int()
Foo.bar
#? int()
Foo().bar
#? str()
Foo.baz
#? str()
Foo().baz

View File

@@ -57,6 +57,11 @@ a
#? int() str()
(3 ** 'a')
class X():
foo = 2
#? int()
(X.foo ** 3)
# -----------------
# assignments
# -----------------

View File

@@ -76,3 +76,18 @@ class InstanceAttributeIfs:
InstanceAttributeIfs().a1
#? int() str()
InstanceAttributeIfs().a2
class A:
def a(self, b):
for x in [self.a(i) for i in b]:
#?
x
class B:
def a(self, b):
for i in b:
for i in self.a(i):
#?
yield i

View File

@@ -25,7 +25,7 @@ next(reversed(yielder()))
#?
next(reversed())
#? str()
#? str() bytes()
next(open(''))
#? int()
@@ -34,6 +34,8 @@ next(open(''))
# Compiled classes should have the meta class attributes.
#? ['__itemsize__']
tuple.__itemsize__
#? []
tuple().__itemsize__
# -----------------
# type() calls with one parameter
@@ -69,10 +71,15 @@ if os.path.isfile():
#? ['abspath']
fails = os.path.abspath
# The type vars and other underscored things from typeshed should not be
# findable.
#?
os._T
with open('foo') as f:
for line in f.readlines():
#? str()
#? str() bytes()
line
# -----------------
# enumerate
@@ -101,9 +108,6 @@ for a in re.finditer('a', 'a'):
#? int()
a.start()
#? str()
re.sub('a', 'a')
# -----------------
# ref
# -----------------
@@ -114,7 +118,7 @@ weakref.proxy(1)
#? weakref.ref()
weakref.ref(1)
#? int()
#? int() None
weakref.ref(1)()
# -----------------
@@ -165,10 +169,6 @@ import sqlite3
con = sqlite3.connect()
#? sqlite3.Cursor()
c = con.cursor()
#? sqlite3.Row()
row = c.fetchall()[0]
#? str()
row.keys()[0]
def huhu(db):
"""
@@ -241,6 +241,31 @@ with contextlib.closing('asd') as string:
#? str()
string
# -----------------
# operator
# -----------------
import operator
f = operator.itemgetter(1)
#? float()
f([1.0])
#? str()
f([1, ''])
g = operator.itemgetter(1, 2)
x1, x2 = g([1, 1.0, ''])
#? float()
x1
#? str()
x2
x1, x2 = g([1, ''])
#? str()
x1
#? int() str()
x2
# -----------------
# shlex
# -----------------
@@ -249,5 +274,5 @@ with contextlib.closing('asd') as string:
import shlex
qsplit = shlex.split("foo, ferwerwerw werw werw e")
for part in qsplit:
#? str() None
#? str()
part

View File

@@ -0,0 +1 @@
in_stub_only: int

View File

@@ -0,0 +1 @@
in_stub_only_folder: int

View File

@@ -0,0 +1 @@
in_stub_only: int

View File

@@ -0,0 +1,2 @@
in_python = ''
in_both = ''

View File

@@ -0,0 +1,2 @@
in_stub: int
in_both: float

View File

@@ -0,0 +1 @@
in_python = ''

View File

@@ -0,0 +1,2 @@
in_with_stub_both = 5
in_with_stub_python = 8

View File

@@ -0,0 +1,2 @@
in_with_stub_both: str
in_with_stub_stub: float

View File

@@ -0,0 +1,2 @@
in_with_stub_both_folder = 5
in_with_stub_python_folder = 8

View File

@@ -0,0 +1,2 @@
in_with_stub_both_folder: str
in_with_stub_stub_folder: float

View File

@@ -0,0 +1 @@
in_stub_only: int

View File

@@ -0,0 +1,2 @@
in_python = ''
in_both = ''

View File

@@ -0,0 +1,2 @@
in_stub: int
in_both: float

View File

@@ -0,0 +1 @@
in_python = ''

104
test/completion/stubs.py Normal file
View File

@@ -0,0 +1,104 @@
# python >= 3.4
from stub_folder import with_stub, stub_only, with_stub_folder, stub_only_folder
# -------------------------
# Just files
# -------------------------
#? int()
stub_only.in_stub_only
#? str()
with_stub.in_with_stub_both
#? int()
with_stub.in_with_stub_python
#? float()
with_stub.in_with_stub_stub
#! ['in_stub_only: int']
stub_only.in_stub_only
#! ['in_with_stub_both = 5']
with_stub.in_with_stub_both
#! ['in_with_stub_python = 8']
with_stub.in_with_stub_python
#! ['in_with_stub_stub: float']
with_stub.in_with_stub_stub
#? ['in_stub_only']
stub_only.in_
#? ['in_stub_only']
from stub_folder.stub_only import in_
#? ['in_with_stub_both', 'in_with_stub_python', 'in_with_stub_stub']
with_stub.in_
#? ['in_with_stub_both', 'in_with_stub_python', 'in_with_stub_stub']
from stub_folder.with_stub import in_
#? ['with_stub', 'stub_only', 'with_stub_folder', 'stub_only_folder']
from stub_folder.
# -------------------------
# Folders
# -------------------------
#? int()
stub_only_folder.in_stub_only_folder
#? str()
with_stub_folder.in_with_stub_both_folder
#? int()
with_stub_folder.in_with_stub_python_folder
#? float()
with_stub_folder.in_with_stub_stub_folder
#? ['in_stub_only_folder']
stub_only_folder.in_
#? ['in_with_stub_both_folder', 'in_with_stub_python_folder', 'in_with_stub_stub_folder']
with_stub_folder.in_
# -------------------------
# Folders nested with stubs
# -------------------------
from stub_folder.with_stub_folder import nested_stub_only, nested_with_stub, \
python_only
#? int()
nested_stub_only.in_stub_only
#? float()
nested_with_stub.in_both
#? str()
nested_with_stub.in_python
#? int()
nested_with_stub.in_stub
#? str()
python_only.in_python
#? ['in_stub_only_folder']
stub_only_folder.in_
#? ['in_with_stub_both_folder', 'in_with_stub_python_folder', 'in_with_stub_stub_folder']
with_stub_folder.in_
#? ['in_python']
python_only.in_
# -------------------------
# Folders nested with stubs
# -------------------------
from stub_folder.stub_only_folder import nested_stub_only, nested_with_stub, \
python_only
#? int()
nested_stub_only.in_stub_only
#? float()
nested_with_stub.in_both
#? str()
nested_with_stub.in_python
#? int()
nested_with_stub.in_stub
#? str()
python_only.in_python
#? ['in_stub_only']
nested_stub_only.in_
#? ['in_both', 'in_python', 'in_stub']
nested_with_stub.in_
#? ['in_python']
python_only.in_

View File

@@ -131,3 +131,58 @@ set_t2 = set()
#? ['clear', 'copy']
set_t2.c
# -----------------
# pep 448 unpacking generalizations
# -----------------
# python >= 3.5
d = {'a': 3}
dc = {v: 3 for v in ['a']}
#? dict()
{**d}
#? dict()
{**dc}
#? str()
{**d, "b": "b"}["b"]
#? str()
{**dc, "b": "b"}["b"]
# Should resolve to int() but jedi is not smart enough yet
# Here to make sure it doesn't result in crash though
#?
{**d}["a"]
# Should resolve to int() but jedi is not smart enough yet
# Here to make sure it doesn't result in crash though
#?
{**dc}["a"]
s = {1, 2, 3}
#? set()
{*s}
#? set()
{*s, 4, *s}
s = {1, 2, 3}
# Should resolve to int() but jedi is not smart enough yet
# Here to make sure it doesn't result in crash though
#?
{*s}.pop()
#? int()
{*s, 4}.pop()
# Should resolve to int() but jedi is not smart enough yet
# Here to make sure it doesn't result in crash though
#?
[*s][0]
#? int()
[*s, 4][0]

View File

@@ -265,7 +265,10 @@ check(DynamicParam())
import _sre
#< 0 (-3,7), (0,0), ('_sre', None, None)
# TODO reenable this, it's currently not working, because of 2/3
# inconsistencies in typeshed (_sre exists in typeshed/2, but not in
# typeshed/3).
##< 0 (-3,7), (0,0), ('_sre', None, None)
_sre
# -----------------

View File

@@ -126,11 +126,12 @@ class StaticAnalysisCase(object):
return "<%s: %s>" % (self.__class__.__name__, os.path.basename(self._path))
@pytest.fixture()
def venv_path(tmpdir, environment):
@pytest.fixture(scope='session')
def venv_path(tmpdir_factory, environment):
if environment.version_info.major < 3:
pytest.skip("python -m venv does not exist in Python 2")
tmpdir = tmpdir_factory.mktemp('venv_path')
dirname = os.path.join(tmpdir.dirname, 'venv')
# We cannot use the Python from tox because tox creates virtualenvs and

View File

View File

View File

View File

@@ -0,0 +1 @@
from .rel2 import name

View File

@@ -0,0 +1 @@
name = 1

View File

@@ -0,0 +1 @@
foo: int

View File

@@ -0,0 +1,2 @@
both: int
stub_only: str

View File

@@ -0,0 +1 @@
in_sub_module: int

View File

@@ -0,0 +1,2 @@
python_only = 1
both = ''

View File

@@ -0,0 +1 @@
in_sub_module = ''

View File

@@ -126,6 +126,7 @@ from jedi.api.classes import Definition
from jedi.api.completion import get_user_scope
from jedi import parser_utils
from jedi.api.environment import get_default_environment, get_system_environment
from jedi.evaluate.gradual.conversion import try_stubs_to_actual_context_set
TEST_COMPLETIONS = 0
@@ -230,7 +231,10 @@ class IntegrationTestCase(object):
if user_context.api_type == 'function':
user_context = user_context.get_function_execution()
element.parent = user_context.tree_node
results = evaluator.eval_element(user_context, element)
results = try_stubs_to_actual_context_set(
evaluator.eval_element(user_context, element),
prefer_stub_to_compiled=True
)
if not results:
raise Exception('Could not resolve %s on line %s'
% (match.string, self.line_nr - 1))
@@ -412,7 +416,6 @@ if __name__ == '__main__':
dir_ = os.path.dirname(os.path.realpath(__file__))
completion_test_dir = os.path.join(dir_, '../test/completion')
completion_test_dir = os.path.abspath(completion_test_dir)
summary = []
tests_fail = 0
# execute tests
@@ -422,9 +425,11 @@ if __name__ == '__main__':
cases += collect_dir_tests(completion_test_dir, test_files, True)
def file_change(current, tests, fails):
if current is not None:
if current is None:
current = ''
else:
current = os.path.basename(current)
print('%s \t\t %s tests and %s fails.' % (current, tests, fails))
print('{:25} {} tests and {} fails.'.format(current, tests, fails))
def report(case, actual, desired):
if actual == desired:
@@ -470,8 +475,6 @@ if __name__ == '__main__':
print('\nSummary: (%s fails of %s tests) in %.3fs'
% (tests_fail, len(cases), time.time() - t_start))
for s in summary:
print(s)
exit_code = 1 if tests_fail else 0
sys.exit(exit_code)

View File

@@ -111,9 +111,3 @@ import import_tree
import_tree.a
import_tree.b
# This is something that raised an error, because it was using a complex
# mixture of Jedi fakes and compiled objects.
import _sre
#! 15 attribute-error
_sre.compile().not_existing

View File

@@ -6,8 +6,9 @@
1 - '1'
-1 - - 1
-1 - int()
int() - float()
# TODO uncomment
#-1 - int()
#int() - float()
float() - 3.0
a = 3

View File

@@ -87,3 +87,21 @@ else:
str.upper
#! 4 attribute-error
str.undefined
# -----------------
# arguments
# -----------------
def i_see(r):
return r
def lala():
# This weird structure checks if the error is actually resolved in the
# right place.
a = TypeError
try:
i_see()
except a:
pass
#! 5 type-error-too-few-arguments
i_see()

View File

@@ -5,17 +5,25 @@ Test all things related to the ``jedi.api`` module.
import os
from textwrap import dedent
from jedi import preload_module
from jedi._compatibility import is_py3
from pytest import raises
from parso import cache
from jedi import preload_module
from jedi.evaluate.gradual import typeshed
def test_preload_modules():
def check_loaded(*modules):
for grammar_cache in cache.parser_cache.values():
if None in grammar_cache:
break
# Filter the typeshed parser cache.
typeshed_cache_count = sum(
1 for path in grammar_cache
if path is not None and path.startswith(typeshed.TYPESHED_PATH)
)
# +1 for None module (currently used)
grammar_cache = next(iter(cache.parser_cache.values()))
assert len(grammar_cache) == len(modules) + 1
assert len(grammar_cache) - typeshed_cache_count == len(modules) + 1
for i in modules:
assert [i in k for k in grammar_cache.keys() if k is not None]
@@ -111,11 +119,7 @@ def test_goto_assignments_on_non_name(Script, environment):
assert Script('for').goto_assignments() == []
assert Script('assert').goto_assignments() == []
if environment.version_info.major == 2:
# In Python 2.7 True is still a name.
assert Script('True').goto_assignments()[0].description == 'instance True'
else:
assert Script('True').goto_assignments() == []
assert Script('True').goto_assignments() == []
def test_goto_definitions_on_non_name(Script):
@@ -199,9 +203,9 @@ def test_goto_assignments_follow_imports(Script):
assert definition.name == 'p'
result, = definition.goto_assignments()
assert result.name == 'p'
result, = definition._goto_definitions()
result, = definition.infer()
assert result.name == 'int'
result, = result._goto_definitions()
result, = result.infer()
assert result.name == 'int'
definition, = script.goto_assignments()
@@ -285,3 +289,11 @@ def test_backslash_continuation_and_bracket(Script):
column = lines[-1].index('(')
def_, = Script(code, line=len(lines), column=column).goto_definitions()
assert def_.name == 'int'
def test_goto_follow_builtin_imports(Script):
s = Script('import sys; sys')
d, = s.goto_assignments(follow_imports=True)
assert d.in_builtin_module() is True
d, = s.goto_assignments(follow_imports=True, follow_builtin_imports=True)
assert d.in_builtin_module() is True

View File

@@ -18,7 +18,7 @@ def check_follow_definition_types(Script, source):
return [d.type for d in defs]
def test_follow_import_incomplete(Script):
def test_follow_import_incomplete(Script, environment):
"""
Completion on incomplete imports should always take the full completion
to do any evaluation.
@@ -34,8 +34,10 @@ def test_follow_import_incomplete(Script):
# incomplete `from * import` part
datetime = check_follow_definition_types(Script, "from datetime import datetim")
assert set(datetime) == {'class', 'instance'} # py33: builtin and pure py version
if environment.version_info.major == 2:
assert datetime == ['class']
else:
assert set(datetime) == {'class', 'instance'} # py3: builtin and pure py version
# os.path check
ospath = check_follow_definition_types(Script, "from os.path import abspat")
assert ospath == ['function']

View File

@@ -6,7 +6,7 @@ import pytest
from ..helpers import TestCase
from jedi import cache
from jedi._compatibility import is_py33
from jedi.parser_utils import get_call_signature
def assert_signature(Script, source, expected_name, expected_index=0, line=None, column=None):
@@ -24,7 +24,7 @@ def assert_signature(Script, source, expected_name, expected_index=0, line=None,
def test_valid_call(Script):
assert_signature(Script, 'str()', 'str', column=4)
assert_signature(Script, 'bool()', 'bool', column=5)
class TestCallSignatures(TestCase):
@@ -39,12 +39,12 @@ class TestCallSignatures(TestCase):
run = self._run_simple
# simple
s1 = "sorted(a, str("
s1 = "sorted(a, bool("
run(s1, 'sorted', 0, 7)
run(s1, 'sorted', 1, 9)
run(s1, 'sorted', 1, 10)
run(s1, 'sorted', 1, 11)
run(s1, 'str', 0, 14)
run(s1, 'bool', 0, 15)
s2 = "abs(), "
run(s2, 'abs', 0, 4)
@@ -58,26 +58,26 @@ class TestCallSignatures(TestCase):
def test_more_complicated(self):
run = self._run_simple
s4 = 'abs(zip(), , set,'
s4 = 'abs(bool(), , set,'
run(s4, None, column=3)
run(s4, 'abs', 0, 4)
run(s4, 'zip', 0, 8)
run(s4, 'abs', 0, 9)
run(s4, 'abs', None, 10)
run(s4, 'bool', 0, 9)
run(s4, 'abs', 0, 10)
run(s4, 'abs', None, 11)
s5 = "sorted(1,\nif 2:\n def a():"
run(s5, 'sorted', 0, 7)
run(s5, 'sorted', 1, 9)
s6 = "str().center("
run(s6, 'center', 0)
run(s6, 'str', 0, 4)
s6 = "bool().__eq__("
run(s6, '__eq__', 0)
run(s6, 'bool', 0, 5)
s7 = "str().upper().center("
s8 = "str(int[zip("
s8 = "bool(int[abs("
run(s7, 'center', 0)
run(s8, 'zip', 0)
run(s8, 'str', 0, 8)
run(s8, 'abs', 0)
run(s8, 'bool', 0, 10)
run("import time; abc = time; abc.sleep(", 'sleep', 0)
@@ -87,15 +87,19 @@ class TestCallSignatures(TestCase):
"func(alpha='101',"
self._run_simple(s, 'func', 0, column=13, line=2)
def test_flows(self):
# jedi-vim #9
self._run_simple("with open(", 'open', 0)
def test_for(self):
# jedi-vim #11
self._run_simple("for sorted(", 'sorted', 0)
self._run_simple("for s in sorted(", 'sorted', 0)
def test_with(Script):
# jedi-vim #9
sigs = Script("with open(").call_signatures()
assert sigs
assert all(sig.name == 'open' for sig in sigs)
def test_call_signatures_empty_parentheses_pre_space(Script):
s = dedent("""\
def f(a, b):
@@ -150,22 +154,22 @@ def test_decorator_in_class(Script):
def test_additional_brackets(Script):
assert_signature(Script, 'str((', 'str', 0)
assert_signature(Script, 'abs((', 'abs', 0)
def test_unterminated_strings(Script):
assert_signature(Script, 'str(";', 'str', 0)
assert_signature(Script, 'abs(";', 'abs', 0)
def test_whitespace_before_bracket(Script):
assert_signature(Script, 'str (', 'str', 0)
assert_signature(Script, 'str (";', 'str', 0)
assert_signature(Script, 'str\n(', None)
assert_signature(Script, 'abs (', 'abs', 0)
assert_signature(Script, 'abs (";', 'abs', 0)
assert_signature(Script, 'abs\n(', None)
def test_brackets_in_string_literals(Script):
assert_signature(Script, 'str (" (', 'str', 0)
assert_signature(Script, 'str (" )', 'str', 0)
assert_signature(Script, 'abs (" (', 'abs', 0)
assert_signature(Script, 'abs (" )', 'abs', 0)
def test_function_definitions_should_break(Script):
@@ -173,8 +177,8 @@ def test_function_definitions_should_break(Script):
Function definitions (and other tokens that cannot exist within call
signatures) should break and not be able to return a call signature.
"""
assert_signature(Script, 'str(\ndef x', 'str', 0)
assert not Script('str(\ndef x(): pass').call_signatures()
assert_signature(Script, 'abs(\ndef x', 'abs', 0)
assert not Script('abs(\ndef x(): pass').call_signatures()
def test_flow_call(Script):
@@ -211,7 +215,7 @@ def test_call_signature_on_module(Script):
assert Script(s).call_signatures() == []
def test_complex(Script):
def test_complex(Script, environment):
s = """
def abc(a,b):
pass
@@ -229,7 +233,19 @@ def test_complex(Script):
re.compile(
return it * 2
"""
assert_signature(Script, s, 'compile', 0, line=4, column=27)
sig1, sig2 = sorted(Script(s, line=4, column=27).call_signatures(), key=lambda s: s.line)
assert sig1.name == sig2.name == 'compile'
assert sig1.index == sig2.index == 0
func1, = sig1._name.infer()
func2, = sig2._name.infer()
if environment.version_info.major == 3:
# Do these checks just for Python 3, I'm too lazy to deal with this
# legacy stuff. ~ dave.
assert get_call_signature(func1.tree_node) \
== 'compile(pattern: AnyStr, flags: _FlagsType = ...) -> Pattern[AnyStr]'
assert get_call_signature(func2.tree_node) \
== 'compile(pattern: Pattern[AnyStr], flags: _FlagsType = ...) ->\nPattern[AnyStr]'
# jedi-vim #70
s = """def foo("""
@@ -246,19 +262,24 @@ def _params(Script, source, line=None, column=None):
return signatures[0].params
def test_param_name(Script):
if not is_py33:
p = _params(Script, '''int(''')
# int is defined as: `int(x[, base])`
assert p[0].name == 'x'
# `int` docstring has been redefined:
# http://bugs.python.org/issue14783
# TODO have multiple call signatures for int (like in the docstr)
#assert p[1].name == 'base'
def test_int_params(Script):
sig1, sig2 = Script('int(').call_signatures()
# int is defined as: `int(x[, base])`
assert len(sig1.params) == 2
assert sig1.params[0].name == 'x'
assert sig1.params[1].name == 'base'
assert len(sig2.params) == 1
assert sig2.params[0].name == 'x'
p = _params(Script, '''open(something,''')
assert p[0].name in ['file', 'name']
assert p[1].name == 'mode'
def test_param_name(Script):
sigs = Script('open(something,').call_signatures()
for sig in sigs:
# All of the signatures (in Python the function is overloaded),
# contain the same param names.
assert sig.params[0].name in ['file', 'name']
assert sig.params[1].name == 'mode'
assert sig.params[2].name == 'buffering'
def test_builtins(Script):
@@ -286,18 +307,16 @@ def test_signature_is_definition(Script):
# Now compare all the attributes that a CallSignature must also have.
for attr_name in dir(definition):
dont_scan = ['defined_names', 'parent', 'goto_assignments', 'params']
dont_scan = ['defined_names', 'parent', 'goto_assignments', 'infer', 'params']
if attr_name.startswith('_') or attr_name in dont_scan:
continue
# Might trigger some deprecation warnings.
with warnings.catch_warnings(record=True):
attribute = getattr(definition, attr_name)
signature_attribute = getattr(signature, attr_name)
if inspect.ismethod(attribute):
assert attribute() == signature_attribute()
else:
assert attribute == signature_attribute
attribute = getattr(definition, attr_name)
signature_attribute = getattr(signature, attr_name)
if inspect.ismethod(attribute):
assert attribute() == signature_attribute()
else:
assert attribute == signature_attribute
def test_no_signature(Script):
@@ -381,7 +400,7 @@ def test_bracket_start(Script):
assert len(signatures) == 1
return signatures[0].bracket_start
assert bracket_start('str(') == (1, 3)
assert bracket_start('abs(') == (1, 3)
def test_different_caller(Script):
@@ -390,11 +409,11 @@ def test_different_caller(Script):
index and then get the call signature of it.
"""
assert_signature(Script, '[str][0](', 'str', 0)
assert_signature(Script, '[str][0]()', 'str', 0, column=len('[str][0]('))
assert_signature(Script, '[abs][0](', 'abs', 0)
assert_signature(Script, '[abs][0]()', 'abs', 0, column=len('[abs][0]('))
assert_signature(Script, '(str)(', 'str', 0)
assert_signature(Script, '(str)()', 'str', 0, column=len('(str)('))
assert_signature(Script, '(abs)(', 'abs', 0)
assert_signature(Script, '(abs)()', 'abs', 0, column=len('(abs)('))
def test_in_function(Script):
@@ -415,20 +434,28 @@ def test_lambda_params(Script):
assert [p.name for p in sig.params] == ['x']
CLASS_CODE = dedent('''\
class X():
def __init__(self, foo, bar):
self.foo = foo
''')
def test_class_creation(Script):
code = dedent('''\
class X():
def __init__(self, foo, bar):
self.foo = foo
''')
sig, = Script(code + 'X(').call_signatures()
sig, = Script(CLASS_CODE + 'X(').call_signatures()
assert sig.index == 0
assert sig.name == 'X'
assert [p.name for p in sig.params] == ['foo', 'bar']
sig, = Script(code + 'X.__init__(').call_signatures()
def test_call_init_on_class(Script):
sig, = Script(CLASS_CODE + 'X.__init__(').call_signatures()
assert [p.name for p in sig.params] == ['self', 'foo', 'bar']
sig, = Script(code + 'X().__init__(').call_signatures()
def test_call_init_on_instance(Script):
sig, = Script(CLASS_CODE + 'X().__init__(').call_signatures()
assert [p.name for p in sig.params] == ['foo', 'bar']

View File

@@ -8,7 +8,6 @@ import pytest
import jedi
from jedi import __doc__ as jedi_doc, names
from ..helpers import cwd_at
from ..helpers import TestCase
@@ -66,27 +65,31 @@ def test_basedefinition_type(Script, environment):
'generator', 'statement', 'import', 'param')
def test_basedefinition_type_import(Script):
def get_types(source, **kwargs):
return {t.type for t in Script(source, **kwargs).completions()}
@pytest.mark.parametrize(
('src', 'expected_result', 'column'), [
# import one level
('import t', 'module', None),
('import ', 'module', None),
('import datetime; datetime', 'module', None),
# import one level
assert get_types('import t') == {'module'}
assert get_types('import ') == {'module'}
assert get_types('import datetime; datetime') == {'module'}
# from
('from datetime import timedelta', 'class', None),
('from datetime import timedelta; timedelta', 'class', None),
('from json import tool', 'module', None),
('from json import tool; tool', 'module', None),
# from
assert get_types('from datetime import timedelta') == {'class'}
assert get_types('from datetime import timedelta; timedelta') == {'class'}
assert get_types('from json import tool') == {'module'}
assert get_types('from json import tool; tool') == {'module'}
# import two levels
('import json.tool; json', 'module', None),
('import json.tool; json.tool', 'module', None),
('import json.tool; json.tool.main', 'function', None),
('import json.tool', 'module', None),
('import json.tool', 'module', 9),
]
# import two levels
assert get_types('import json.tool; json') == {'module'}
assert get_types('import json.tool; json.tool') == {'module'}
assert get_types('import json.tool; json.tool.main') == {'function'}
assert get_types('import json.tool') == {'module'}
assert get_types('import json.tool', column=9) == {'module'}
)
def test_basedefinition_type_import(Script, src, expected_result, column):
types = {t.type for t in Script(src, column=column).completions()}
assert types == {expected_result}
def test_function_call_signature_in_doc(Script):
@@ -99,7 +102,7 @@ def test_function_call_signature_in_doc(Script):
def test_param_docstring():
param = jedi.names("def test(parameter): pass")[1]
param = jedi.names("def test(parameter): pass", all_scopes=True)[1]
assert param.name == 'parameter'
assert param.docstring() == ''
@@ -111,13 +114,14 @@ def test_class_call_signature(Script):
pass
Foo""").goto_definitions()
doc = defs[0].docstring()
assert "Foo(self, x, y=1, z='a')" in str(doc)
assert doc == "Foo(x, y=1, z='a')"
def test_position_none_if_builtin(Script):
gotos = Script('import sys; sys.path').goto_assignments()
assert gotos[0].line is None
assert gotos[0].column is None
assert gotos[0].in_builtin_module()
assert gotos[0].line is not None
assert gotos[0].column is not None
def test_completion_docstring(Script, jedi_path):
@@ -174,9 +178,9 @@ def test_hashlib_params(Script, environment):
if environment.version_info < (3,):
pytest.skip()
script = Script(source='from hashlib import ', line=1, column=20)
c = script.completions()
assert c[2].params
script = Script(source='from hashlib import sha256')
c, = script.completions()
assert [p.name for p in c.params] == ['arg']
def test_signature_params(Script):
@@ -291,10 +295,10 @@ def test_parent_on_completion(Script):
def test_type(Script):
for c in Script('a = [str()]; a[0].').completions():
if c.name == '__class__':
if c.name == '__class__' and False: # TODO fix.
assert c.type == 'class'
else:
assert c.type in ('function', 'instance')
assert c.type in ('function', 'statement')
for c in Script('list.').completions():
assert c.type

View File

@@ -29,7 +29,7 @@ def test_in_empty_space(Script):
comps = Script(code, 3, 7).completions()
self, = [c for c in comps if c.name == 'self']
assert self.name == 'self'
def_, = self._goto_definitions()
def_, = self.infer()
assert def_.name == 'X'
@@ -132,7 +132,6 @@ def test_async(Script, environment):
hey = 3
ho'''
)
print(code)
comps = Script(code, column=4).completions()
names = [c.name for c in comps]
assert 'foo' in names

View File

@@ -79,6 +79,59 @@ class TestDefinedNames(TestCase):
self.assert_definition_names(subsubdefs, ['L3', 'f'])
self.assert_definition_names(subsubdefs[0].defined_names(), ['f'])
def test_class_fields_with_all_scopes_false(self):
definitions = self.check_defined_names("""
from module import f
g = f(f)
class C:
h = g
def foo(x=a):
bar = x
return bar
""", ['f', 'g', 'C', 'foo'])
C_subdefs = definitions[-2].defined_names()
foo_subdefs = definitions[-1].defined_names()
self.assert_definition_names(C_subdefs, ['h'])
self.assert_definition_names(foo_subdefs, ['x', 'bar'])
def test_async_stmt_with_all_scopes_false(self):
definitions = self.check_defined_names("""
from module import f
import asyncio
g = f(f)
class C:
h = g
def __init__(self):
pass
async def __aenter__(self):
pass
def foo(x=a):
bar = x
return bar
async def async_foo(duration):
async def wait():
await asyncio.sleep(100)
for i in range(duration//100):
await wait()
return duration//100*100
async with C() as cinst:
d = cinst
""", ['f', 'asyncio', 'g', 'C', 'foo', 'async_foo', 'cinst', 'd'])
C_subdefs = definitions[3].defined_names()
foo_subdefs = definitions[4].defined_names()
async_foo_subdefs = definitions[5].defined_names()
cinst_subdefs = definitions[6].defined_names()
self.assert_definition_names(C_subdefs, ['h', '__init__', '__aenter__'])
self.assert_definition_names(foo_subdefs, ['x', 'bar'])
self.assert_definition_names(async_foo_subdefs, ['duration', 'wait', 'i'])
# We treat d as a name outside `async with` block
self.assert_definition_names(cinst_subdefs, [])
def test_follow_imports(environment):
# github issue #344
@@ -96,3 +149,24 @@ def test_names_twice(environment):
defs = names(source=source, environment=environment)
assert defs[0].defined_names() == []
def test_simple_name(environment):
defs = names('foo', references=True, environment=environment)
assert not defs[0]._name.infer()
def test_no_error(environment):
code = dedent("""
def foo(a, b):
if a == 10:
if b is None:
print("foo")
a = 20
""")
func_name, = names(code)
a, b, a20 = func_name.defined_names()
assert a.name == 'a'
assert b.name == 'b'
assert a20.name == 'a'
assert a20.goto_assignments() == [a20]

View File

@@ -1,6 +1,5 @@
import os
import sys
from contextlib import contextmanager
import pytest
@@ -8,7 +7,8 @@ import jedi
from jedi._compatibility import py_version
from jedi.api.environment import get_default_environment, find_virtualenvs, \
InvalidPythonEnvironment, find_system_environments, \
get_system_environment, create_environment
get_system_environment, create_environment, InterpreterEnvironment, \
get_cached_default_environment
def test_sys_path():
@@ -44,7 +44,7 @@ def test_versions(version):
def test_load_module(evaluator):
access_path = evaluator.compiled_subprocess.load_module(
name=u'math',
dotted_name=u'math',
sys_path=evaluator.get_sys_path()
)
name, access_handle = access_path.accesses[0]
@@ -55,7 +55,10 @@ def test_load_module(evaluator):
access_handle.py__mro__()
def test_error_in_environment(evaluator, Script):
def test_error_in_environment(evaluator, Script, environment):
if isinstance(environment, InterpreterEnvironment):
pytest.skip("We don't catch these errors at the moment.")
# Provoke an error to show how Jedi can recover from it.
with pytest.raises(jedi.InternalError):
evaluator.compiled_subprocess._test_raise_error(KeyboardInterrupt)
@@ -72,9 +75,11 @@ def test_stdout_in_subprocess(evaluator, Script):
Script('1').goto_definitions()
def test_killed_subprocess(evaluator, Script):
def test_killed_subprocess(evaluator, Script, environment):
if isinstance(environment, InterpreterEnvironment):
pytest.skip("We cannot kill our own process")
# Just kill the subprocess.
evaluator.compiled_subprocess._compiled_subprocess._process.kill()
evaluator.compiled_subprocess._compiled_subprocess._get_process().kill()
# Since the process was terminated (and nobody knows about it) the first
# Jedi call fails.
with pytest.raises(jedi.InternalError):
@@ -85,34 +90,22 @@ def test_killed_subprocess(evaluator, Script):
assert def_.name == 'str'
@contextmanager
def set_environment_variable(name, value):
tmp = os.environ.get(name)
try:
os.environ[name] = value
yield
finally:
if tmp is None:
del os.environ[name]
else:
os.environ[name] = tmp
def test_not_existing_virtualenv():
def test_not_existing_virtualenv(monkeypatch):
"""Should not match the path that was given"""
path = '/foo/bar/jedi_baz'
with set_environment_variable('VIRTUAL_ENV', path):
assert get_default_environment().executable != path
monkeypatch.setenv('VIRTUAL_ENV', path)
assert get_default_environment().executable != path
def test_working_venv(venv_path):
with set_environment_variable('VIRTUAL_ENV', venv_path):
assert get_default_environment().path == venv_path
def test_working_venv(venv_path, monkeypatch):
monkeypatch.setenv('VIRTUAL_ENV', venv_path)
assert get_default_environment().path == venv_path
def test_scanning_venvs(venv_path):
parent_dir = os.path.dirname(venv_path)
assert any(venv.path == venv_path for venv in find_virtualenvs([parent_dir]))
assert any(venv.path == venv_path
for venv in find_virtualenvs([parent_dir]))
def test_create_environment_venv_path(venv_path):
@@ -123,3 +116,40 @@ def test_create_environment_venv_path(venv_path):
def test_create_environment_executable():
environment = create_environment(sys.executable)
assert environment.executable == sys.executable
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:
f.write('')
def _get_subprocess(self):
if self._start_executable != fake_python:
raise RuntimeError('Should not get called!')
self.executable = fake_python
self.path = 'fake'
monkeypatch.setattr('jedi.api.environment.Environment._get_subprocess',
_get_subprocess)
monkeypatch.setenv('VIRTUAL_ENV', fake_python)
env = get_default_environment()
assert env.path == 'fake'
@pytest.mark.parametrize('virtualenv', ['', 'fufuuuuu', sys.prefix])
def test_get_default_environment_when_embedded(monkeypatch, virtualenv):
# When using Python embedded, sometimes the executable is not a Python
# executable.
executable_name = 'RANDOM_EXE'
monkeypatch.setattr(sys, 'executable', executable_name)
monkeypatch.setenv('VIRTUAL_ENV', virtualenv)
env = get_default_environment()
assert env.executable != executable_name
def test_changing_venv(venv_path, monkeypatch):
monkeypatch.setitem(os.environ, 'VIRTUAL_ENV', venv_path)
get_cached_default_environment()
monkeypatch.setitem(os.environ, 'VIRTUAL_ENV', sys.executable)
assert get_cached_default_environment().executable == sys.executable

View File

@@ -18,7 +18,7 @@ import textwrap
import pytest
import jedi
from ..helpers import TestCase, cwd_at
from ..helpers import TestCase
class MixinTestFullName(object):
@@ -52,7 +52,7 @@ class TestFullNameWithGotoDefinitions(MixinTestFullName, TestCase):
self.check("""
import re
any_re = re.compile('.*')
any_re""", '_sre.SRE_Pattern')
any_re""", 'typing.Pattern')
def test_from_import(self):
self.check('from os import path', 'os.path')
@@ -111,5 +111,4 @@ def test_os_path(Script):
def test_os_issues(Script):
"""Issue #873"""
c, = Script('import os\nos.nt''').completions()
assert c.full_name == 'nt'
assert [c.name for c in Script('import os\nos.nt''').completions()] == ['nt']

View File

@@ -4,7 +4,7 @@ Tests of ``jedi.api.Interpreter``.
import pytest
import jedi
from jedi._compatibility import is_py3, py_version, is_py35
from jedi._compatibility import is_py3, py_version
from jedi.evaluate.compiled import mixed
@@ -244,8 +244,8 @@ def test_completion_params():
script = jedi.Interpreter('foo', [locals()])
c, = script.completions()
assert [p.name for p in c.params] == ['a', 'b']
assert c.params[0]._goto_definitions() == []
t, = c.params[1]._goto_definitions()
assert c.params[0].infer() == []
t, = c.params[1].infer()
assert t.name == 'int'
@@ -258,9 +258,9 @@ def test_completion_param_annotations():
script = jedi.Interpreter('foo', [locals()])
c, = script.completions()
a, b, c = c.params
assert a._goto_definitions() == []
assert [d.name for d in b._goto_definitions()] == ['str']
assert {d.name for d in c._goto_definitions()} == {'int', 'float'}
assert a.infer() == []
assert [d.name for d in b.infer()] == ['str']
assert {d.name for d in c.infer()} == {'int', 'float'}
def test_keyword_argument():
@@ -340,7 +340,7 @@ def test_dir_magic_method():
assert 'bar' in names
foo = [c for c in completions if c.name == 'foo'][0]
assert foo._goto_definitions() == []
assert foo.infer() == []
def test_name_not_findable():
@@ -356,3 +356,9 @@ def test_name_not_findable():
setattr(X, 'NOT_FINDABLE', X.hidden)
assert jedi.Interpreter("X.NOT_FINDA", [locals()]).completions()
def test_sys_path_docstring(): # Was an issue in #1298
import jedi
s = jedi.Interpreter("from sys import path\npath", line=2, column=4, namespaces=[locals()])
s.completions()[0].docstring()

View File

@@ -12,4 +12,4 @@ def test_django_default_project(Script):
)
c, = script.completions()
assert c.name == "SomeModel"
assert script._project._django is True
assert script._evaluator.project._django is True

View File

@@ -21,3 +21,14 @@ def test_add_dynamic_mods(Script):
result = script.goto_definitions()
assert len(result) == 1
assert result[0].description == 'class int'
def test_add_bracket_after_function(monkeypatch, Script):
settings = api.settings
monkeypatch.setattr(settings, 'add_bracket_after_function', True)
script = Script('''\
def foo():
pass
foo''')
completions = script.completions()
assert completions[0].complete == '('

View File

@@ -72,3 +72,9 @@ def test_wrong_encoding(Script, tmpdir):
c, = Script('import x; x.foo', sys_path=[tmpdir.strpath]).completions()
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

@@ -1,3 +1,14 @@
def test_import_usage(Script):
s = Script("from .. import foo", line=1, column=18, path="foo.py")
assert [usage.line for usage in s.usages()] == [1]
def test_exclude_builtin_modules(Script):
def get(include):
return [(d.line, d.column) for d in Script(source, column=8).usages(include_builtins=include)]
source = '''import sys\nprint(sys.path)'''
places = get(include=True)
assert len(places) > 2 # Includes stubs
places = get(include=False)
assert places == [(1, 7), (2, 6)]

View File

@@ -1,29 +1,37 @@
from textwrap import dedent
import pytest
from jedi.evaluate import compiled
from jedi.evaluate.context import instance
from jedi.evaluate.helpers import execute_evaluated
from jedi.evaluate.gradual.conversion import stub_to_actual_context_set
def test_simple(evaluator):
def test_simple(evaluator, environment):
obj = compiled.create_simple_object(evaluator, u'_str_')
upper, = obj.py__getattribute__(u'upper')
objs = list(upper.execute_evaluated())
objs = list(execute_evaluated(upper))
assert len(objs) == 1
assert isinstance(objs[0], instance.CompiledInstance)
if environment.version_info.major == 2:
expected = 'unicode'
else:
expected = 'str'
assert objs[0].name.string_name == expected
def test_fake_loading(evaluator):
builtin = compiled.get_special_object(evaluator, u'BUILTINS')
string, = builtin.py__getattribute__(u'str')
from_name = compiled.context.create_from_name(evaluator, string, u'__init__')
def test_builtin_loading(evaluator):
string, = evaluator.builtins_module.py__getattribute__(u'str')
from_name, = string.py__getattribute__(u'__init__')
assert from_name.tree_node
assert not from_name.py__doc__() # It's a stub
def test_fake_docstr(evaluator):
def test_next_docstr(evaluator):
next_ = compiled.builtin_from_name(evaluator, u'next')
assert next_.py__doc__()
assert next_.tree_node is not None
assert next_.py__doc__() == next.__doc__
assert next_.py__doc__() == '' # It's a stub
for non_stub in stub_to_actual_context_set(next_):
assert non_stub.py__doc__() == next.__doc__
def test_parse_function_doc_illegal_docstr():
@@ -42,7 +50,7 @@ def test_doc(evaluator):
"""
str_ = compiled.create_simple_object(evaluator, u'')
# Equals `''.__getnewargs__`
obj = compiled.create_from_name(evaluator, str_, u'__getnewargs__')
obj, = str_.py__getattribute__(u'__getnewargs__')
assert obj.py__doc__() == ''
@@ -70,18 +78,26 @@ def test_method_completion(Script, environment):
foo = Foo()
foo.bar.__func__''')
if environment.version_info.major > 2:
result = []
else:
result = ['__func__']
assert [c.name for c in Script(code).completions()] == result
assert [c.name for c in Script(code).completions()] == ['__func__']
def test_time_docstring(Script):
import time
comp, = Script('import time\ntime.sleep').completions()
assert comp.docstring() == time.sleep.__doc__
assert comp.docstring(raw=True) == time.sleep.__doc__
expected = 'sleep(secs: float) -> None\n\n' + time.sleep.__doc__
assert comp.docstring() == expected
def test_dict_values(Script):
def test_dict_values(Script, environment):
if environment.version_info.major == 2:
# It looks like typeshed for Python 2 returns Any.
pytest.skip()
assert Script('import sys\nsys.modules["alshdb;lasdhf"]').goto_definitions()
def test_getitem_on_none(Script):
script = Script('None[1j]')
assert not script.goto_definitions()
issue, = script._evaluator.analysis
assert issue.name == 'type-error-not-subscriptable'

View File

@@ -3,5 +3,5 @@ def test_module_attributes(Script):
assert def_.name == '__name__'
assert def_.line is None
assert def_.column is None
str_, = def_._goto_definitions()
str_, = def_.infer()
assert str_.name == 'str'

View File

@@ -35,7 +35,20 @@ def test_class_doc(Script):
class TestClass():
'''Docstring of `TestClass`.'''
TestClass""").goto_definitions()
assert defs[0].docstring() == 'Docstring of `TestClass`.'
expected = 'Docstring of `TestClass`.'
assert defs[0].docstring(raw=True) == expected
assert defs[0].docstring() == 'TestClass()\n\n' + expected
def test_class_doc_with_init(Script):
d, = Script("""
class TestClass():
'''Docstring'''
def __init__(self, foo, bar=3): pass
TestClass""").goto_definitions()
assert d.docstring() == 'TestClass(foo, bar=3)\n\nDocstring'
def test_instance_doc(Script):
@@ -142,6 +155,16 @@ def test_docstring_keyword(Script):
assert 'assert' in completions[0].docstring()
def test_docstring_params_formatting(Script):
defs = Script("""
def func(param1,
param2,
param3):
pass
func""").goto_definitions()
assert defs[0].docstring() == 'func(param1, param2, param3)'
# ---- Numpy Style Tests ---
@pytest.mark.skipif(numpydoc_unavailable,
@@ -349,7 +372,6 @@ def test_numpy_returns():
x.d'''
)
names = [c.name for c in jedi.Script(s).completions()]
print(names)
assert 'diagonal' in names
@@ -362,5 +384,4 @@ def test_numpy_comp_returns():
x.d'''
)
names = [c.name for c in jedi.Script(s).completions()]
print(names)
assert 'diagonal' in names

View File

@@ -0,0 +1,27 @@
from functools import partial
from test.helpers import get_example_dir
from jedi.api.project import Project
import pytest
@pytest.fixture
def ScriptInStubFolder(Script):
path = get_example_dir('stub_packages')
project = Project(path, sys_path=[path], smart_sys_path=False)
return partial(Script, _project=project)
@pytest.mark.parametrize(
('code', 'expected'), [
('from no_python import foo', ['int']),
('from with_python import stub_only', ['str']),
('from with_python import python_only', ['int']),
('from with_python import both', ['int']),
('from with_python import something_random', []),
('from with_python.module import in_sub_module', ['int']),
]
)
def test_find_stubs_infer(ScriptInStubFolder, code, expected):
defs = ScriptInStubFolder(code).goto_definitions()
assert [d.name for d in defs] == expected

View File

@@ -0,0 +1,236 @@
import os
import pytest
from parso.utils import PythonVersionInfo
from jedi.evaluate.gradual import typeshed, stub_context
from jedi.evaluate.context import TreeInstance, BoundMethod, FunctionContext, \
MethodContext, ClassContext
TYPESHED_PYTHON3 = os.path.join(typeshed.TYPESHED_PATH, 'stdlib', '3')
def test_get_typeshed_directories():
def get_dirs(version_info):
return {
d.replace(typeshed.TYPESHED_PATH, '').lstrip(os.path.sep)
for d in typeshed._get_typeshed_directories(version_info)
}
def transform(set_):
return {x.replace('/', os.path.sep) for x in set_}
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', 'stdlib/3.5',
'third_party/2and3', 'third_party/3', 'third_party/3.5'})
dirs = get_dirs(PythonVersionInfo(3, 6))
assert dirs == transform({'stdlib/2and3', 'stdlib/3', 'stdlib/3.5',
'stdlib/3.6', 'third_party/2and3',
'third_party/3', 'third_party/3.5', 'third_party/3.6'})
def test_get_stub_files():
def get_map(version_info):
return typeshed._create_stub_map(version_info)
map_ = typeshed._create_stub_map(TYPESHED_PYTHON3)
assert map_['functools'] == os.path.join(TYPESHED_PYTHON3, 'functools.pyi')
def test_function(Script, environment):
code = 'import threading; threading.current_thread'
def_, = Script(code).goto_definitions()
context = def_._name._context
assert isinstance(context, FunctionContext), context
def_, = Script(code + '()').goto_definitions()
context = def_._name._context
assert isinstance(context, TreeInstance)
def_, = Script('import threading; threading.Thread').goto_definitions()
assert isinstance(def_._name._context, ClassContext), def_
def test_keywords_variable(Script):
code = 'import keyword; keyword.kwlist'
for seq in Script(code).goto_definitions():
assert seq.name == 'Sequence'
# This points towards the typeshed implementation
stub_seq, = seq.goto_stubs()
assert typeshed.TYPESHED_PATH in stub_seq.module_path
def test_class(Script):
def_, = Script('import threading; threading.Thread').goto_definitions()
context = def_._name._context
assert isinstance(context, ClassContext), context
def test_instance(Script):
def_, = Script('import threading; threading.Thread()').goto_definitions()
context = def_._name._context
assert isinstance(context, TreeInstance)
def test_class_function(Script):
def_, = Script('import threading; threading.Thread.getName').goto_definitions()
context = def_._name._context
assert isinstance(context, MethodContext), context
def test_method(Script):
code = 'import threading; threading.Thread().getName'
def_, = Script(code).goto_definitions()
context = def_._name._context
assert isinstance(context, BoundMethod), context
assert isinstance(context._wrapped_context, MethodContext), context
def_, = Script(code + '()').goto_definitions()
context = def_._name._context
assert isinstance(context, TreeInstance)
assert context.class_context.py__name__() == 'str'
def test_sys_exc_info(Script):
code = 'import sys; sys.exc_info()'
none, def_ = Script(code + '[1]').goto_definitions()
# It's an optional.
assert def_.name == 'BaseException'
assert def_.type == 'instance'
assert none.name == 'NoneType'
none, def_ = Script(code + '[0]').goto_definitions()
assert def_.name == 'BaseException'
assert def_.type == 'class'
def test_sys_getwindowsversion(Script, environment):
# This should only exist on Windows, but type inference should happen
# everywhere.
definitions = Script('import sys; sys.getwindowsversion().major').goto_definitions()
if environment.version_info.major == 2:
assert not definitions
else:
def_, = definitions
assert def_.name == 'int'
def test_sys_hexversion(Script):
script = Script('import sys; sys.hexversion')
def_, = script.completions()
assert isinstance(def_._name, stub_context._StubName), def_._name
assert typeshed.TYPESHED_PATH in def_.module_path
def_, = script.goto_definitions()
assert def_.name == 'int'
def test_math(Script):
def_, = Script('import math; math.acos()').goto_definitions()
assert def_.name == 'float'
context = def_._name._context
assert context
def test_type_var(Script):
def_, = Script('import typing; T = typing.TypeVar("T1")').goto_definitions()
assert def_.name == 'TypeVar'
assert def_.description == 'TypeVar = object()'
@pytest.mark.parametrize(
'code, full_name', (
('import math', 'math'),
('from math import cos', 'math.cos')
)
)
def test_math_is_stub(Script, code, full_name):
s = Script(code)
cos, = s.goto_definitions()
wanted = os.path.join('typeshed', 'stdlib', '2and3', 'math.pyi')
assert cos.module_path.endswith(wanted)
assert cos.is_stub() is True
assert cos.goto_stubs() == [cos]
assert cos.full_name == full_name
cos, = s.goto_assignments()
assert cos.module_path.endswith(wanted)
assert cos.goto_stubs() == [cos]
assert cos.is_stub() is True
assert cos.full_name == full_name
def test_goto_stubs(Script):
s = Script('import os; os')
os_module, = s.goto_definitions()
assert os_module.full_name == 'os'
assert os_module.is_stub() is False
stub, = os_module.goto_stubs()
assert stub.is_stub() is True
os_module, = s.goto_assignments()
def _assert_is_same(d1, d2):
assert d1.name == d2.name
assert d1.module_path == d2.module_path
assert d1.line == d2.line
assert d1.column == d2.column
@pytest.mark.parametrize('type_', ['goto', 'infer'])
@pytest.mark.parametrize(
'code', [
'import os; os.walk',
'from collections import Counter; Counter',
'from collections import Counter; Counter()',
'from collections import Counter; Counter.most_common',
])
def test_goto_stubs_on_itself(Script, code, type_):
"""
If goto_stubs is used on an identifier in e.g. the stdlib, we should goto
the stub of it.
"""
s = Script(code)
if type_ == 'infer':
def_, = s.goto_definitions()
else:
def_, = s.goto_assignments(follow_imports=True)
stub, = def_.goto_stubs()
script_on_source = Script(
path=def_.module_path,
line=def_.line,
column=def_.column
)
if type_ == 'infer':
definition, = script_on_source.goto_definitions()
else:
definition, = script_on_source.goto_assignments()
same_stub, = definition.goto_stubs()
_assert_is_same(same_stub, stub)
_assert_is_same(definition, def_)
assert same_stub.module_path != def_.module_path
# And the reverse.
script_on_stub = Script(
path=same_stub.module_path,
line=same_stub.line,
column=same_stub.column
)
if type_ == 'infer':
same_definition, = script_on_stub.goto_definitions()
same_definition2, = same_stub.infer()
else:
same_definition, = script_on_stub.goto_assignments()
same_definition2, = same_stub.goto_assignments()
_assert_is_same(same_definition, definition)
_assert_is_same(same_definition, same_definition2)

View File

@@ -6,61 +6,106 @@ Tests".
import os
import pytest
from parso.file_io import FileIO
from jedi._compatibility import find_module_py33, find_module
from jedi.evaluate import compiled
from ..helpers import cwd_at
from jedi.evaluate import imports
from jedi.api.project import Project
from jedi.evaluate.gradual.conversion import stub_to_actual_context_set
from ..helpers import cwd_at, get_example_dir, test_dir, root_dir
THIS_DIR = os.path.dirname(__file__)
@pytest.mark.skipif('sys.version_info < (3,3)')
def test_find_module_py33():
"""Needs to work like the old find_module."""
assert find_module_py33('_io') == (None, '_io', False)
assert find_module_py33('_io') == (None, False)
with pytest.raises(ImportError):
assert find_module_py33('_DOESNTEXIST_') == (None, None)
def test_find_module_package():
file, path, is_package = find_module('json')
assert file is None
assert path.endswith('json')
file_io, is_package = find_module('json')
assert file_io.path.endswith(os.path.join('json', '__init__.py'))
assert is_package is True
def test_find_module_not_package():
file, path, is_package = find_module('io')
assert file is not None
assert path.endswith('io.py')
file_io, is_package = find_module('io')
assert file_io.path.endswith('io.py')
assert is_package is False
pkg_zip_path = os.path.join(os.path.dirname(__file__), 'zipped_imports/pkg.zip')
def test_find_module_package_zipped(Script, evaluator, environment):
path = os.path.join(os.path.dirname(__file__), 'zipped_imports/pkg.zip')
sys_path = environment.get_sys_path() + [path]
sys_path = environment.get_sys_path() + [pkg_zip_path]
script = Script('import pkg; pkg.mod', sys_path=sys_path)
assert len(script.completions()) == 1
code, path, is_package = evaluator.compiled_subprocess.get_module_info(
file_io, is_package = evaluator.compiled_subprocess.get_module_info(
sys_path=sys_path,
string=u'pkg',
full_name=u'pkg'
)
assert code is not None
assert path.endswith('pkg.zip')
assert file_io is not None
assert file_io.path.endswith(os.path.join('pkg.zip', 'pkg', '__init__.py'))
assert file_io._zip_path.endswith('pkg.zip')
assert is_package is True
@pytest.mark.parametrize(
'code, file, package, path', [
('import pkg', '__init__.py', 'pkg', 'pkg'),
('import pkg', '__init__.py', 'pkg', 'pkg'),
('from pkg import module', 'module.py', 'pkg', None),
('from pkg.module', 'module.py', 'pkg', None),
('from pkg import nested', os.path.join('nested', '__init__.py'),
'pkg.nested', os.path.join('pkg', 'nested')),
('from pkg.nested', os.path.join('nested', '__init__.py'),
'pkg.nested', os.path.join('pkg', 'nested')),
('from pkg.nested import nested_module',
os.path.join('nested', 'nested_module.py'), 'pkg.nested', None),
('from pkg.nested.nested_module',
os.path.join('nested', 'nested_module.py'), 'pkg.nested', None),
('from pkg.namespace import namespace_module',
os.path.join('namespace', 'namespace_module.py'), 'pkg.namespace', None),
('from pkg.namespace.namespace_module',
os.path.join('namespace', 'namespace_module.py'), 'pkg.namespace', None),
]
)
def test_correct_zip_package_behavior(Script, evaluator, environment, code,
file, package, path, skip_python2):
sys_path = environment.get_sys_path() + [pkg_zip_path]
pkg, = Script(code, sys_path=sys_path).goto_definitions()
context, = pkg._name.infer()
assert context.py__file__() == os.path.join(pkg_zip_path, 'pkg', file)
assert '.'.join(context.py__package__()) == package
assert context.is_package is (path is not None)
if path is not None:
assert context.py__path__() == [os.path.join(pkg_zip_path, path)]
def test_find_module_not_package_zipped(Script, evaluator, environment):
path = os.path.join(os.path.dirname(__file__), 'zipped_imports/not_pkg.zip')
sys_path = environment.get_sys_path() + [path]
script = Script('import not_pkg; not_pkg.val', sys_path=sys_path)
assert len(script.completions()) == 1
code, path, is_package = evaluator.compiled_subprocess.get_module_info(
file_io, is_package = evaluator.compiled_subprocess.get_module_info(
sys_path=sys_path,
string=u'not_pkg',
full_name=u'not_pkg'
)
assert code is not None
assert path.endswith('not_pkg.zip')
assert file_io.path.endswith(os.path.join('not_pkg.zip', 'not_pkg.py'))
assert is_package is False
@@ -87,10 +132,10 @@ def test_import_not_in_sys_path(Script):
("from flask.ext.", "bar"),
("from flask.ext.", "baz"),
("from flask.ext.", "moo"),
pytest.mark.xfail(("import flask.ext.foo; flask.ext.foo.", "Foo")),
pytest.mark.xfail(("import flask.ext.bar; flask.ext.bar.", "Foo")),
pytest.mark.xfail(("import flask.ext.baz; flask.ext.baz.", "Foo")),
pytest.mark.xfail(("import flask.ext.moo; flask.ext.moo.", "Foo")),
pytest.param("import flask.ext.foo; flask.ext.foo.", "Foo", marks=pytest.mark.xfail),
pytest.param("import flask.ext.bar; flask.ext.bar.", "Foo", marks=pytest.mark.xfail),
pytest.param("import flask.ext.baz; flask.ext.baz.", "Foo", marks=pytest.mark.xfail),
pytest.param("import flask.ext.moo; flask.ext.moo.", "Foo", marks=pytest.mark.xfail),
])
def test_flask_ext(Script, code, name):
"""flask.ext.foo is really imported from flaskext.foo or flask_foo.
@@ -132,13 +177,13 @@ def test_cache_works_with_sys_path_param(Script, tmpdir):
def test_import_completion_docstring(Script):
import abc
s = Script('"""test"""\nimport ab')
completions = s.completions()
assert len(completions) == 1
assert completions[0].docstring(fast=False) == abc.__doc__
abc_completions = [c for c in s.completions() if c.name == 'abc']
assert len(abc_completions) == 1
assert abc_completions[0].docstring(fast=False) == abc.__doc__
# However for performance reasons not all modules are loaded and the
# docstring is empty in this case.
assert completions[0].docstring() == ''
assert abc_completions[0].docstring() == ''
def test_goto_definition_on_import(Script):
@@ -249,5 +294,146 @@ def test_compiled_import_none(monkeypatch, Script):
"""
Related to #1079. An import might somehow fail and return None.
"""
script = Script('import sys')
monkeypatch.setattr(compiled, 'load_module', lambda *args, **kwargs: None)
assert not Script('import sys').goto_definitions()
def_, = script.goto_definitions()
assert def_.type == 'module'
context, = def_._name.infer()
assert not stub_to_actual_context_set(context)
@pytest.mark.parametrize(
('path', 'is_package', 'goal'), [
(os.path.join(THIS_DIR, 'test_docstring.py'), False, ('ok', 'lala', 'test_imports')),
(os.path.join(THIS_DIR, '__init__.py'), True, ('ok', 'lala', 'x', 'test_imports')),
]
)
def test_get_modules_containing_name(evaluator, path, goal, is_package):
module = imports._load_python_module(
evaluator,
FileIO(path),
import_names=('ok', 'lala', 'x'),
is_package=is_package,
)
assert module
input_module, found_module = imports.get_modules_containing_name(
evaluator,
[module],
'string_that_only_exists_here'
)
assert input_module is module
assert found_module.string_names == goal
@pytest.mark.parametrize(
'path', ('api/whatever/test_this.py', 'api/whatever/file'))
@pytest.mark.parametrize('empty_sys_path', (False, True))
def test_relative_imports_with_multiple_similar_directories(Script, path, empty_sys_path):
dir = get_example_dir('issue1209')
if empty_sys_path:
project = Project(dir, sys_path=(), smart_sys_path=False)
else:
project = Project(dir)
script = Script(
"from . ",
path=os.path.join(dir, path),
_project=project,
)
name, import_ = script.completions()
assert import_.name == 'import'
assert name.name == 'api_test1'
def test_relative_imports_with_outside_paths(Script):
dir = get_example_dir('issue1209')
project = Project(dir, sys_path=[], smart_sys_path=False)
script = Script(
"from ...",
path=os.path.join(dir, 'api/whatever/test_this.py'),
_project=project,
)
assert [c.name for c in script.completions()] == ['api', 'import', 'whatever']
script = Script(
"from " + '.' * 100,
path=os.path.join(dir, 'api/whatever/test_this.py'),
_project=project,
)
assert [c.name for c in script.completions()] == ['import']
@cwd_at('test/examples/issue1209/api/whatever/')
def test_relative_imports_without_path(Script):
project = Project('.', sys_path=[], smart_sys_path=False)
script = Script("from . ", _project=project)
assert [c.name for c in script.completions()] == ['api_test1', 'import']
script = Script("from .. ", _project=project)
assert [c.name for c in script.completions()] == ['import', 'whatever']
script = Script("from ... ", _project=project)
assert [c.name for c in script.completions()] == ['api', 'import', 'whatever']
def test_relative_import_out_of_file_system(Script):
script = Script("from " + '.' * 100)
import_, = script.completions()
assert import_.name == 'import'
script = Script("from " + '.' * 100 + 'abc import ABCMeta')
assert not script.goto_definitions()
assert not script.completions()
@pytest.mark.parametrize(
'level, directory, project_path, result', [
(1, '/a/b/c', '/a', (['b', 'c'], '/a')),
(2, '/a/b/c', '/a', (['b'], '/a')),
(3, '/a/b/c', '/a', ([], '/a')),
(4, '/a/b/c', '/a', (None, '/')),
(5, '/a/b/c', '/a', (None, None)),
(1, '/', '/', ([], '/')),
(2, '/', '/', (None, None)),
(1, '/a/b', '/a/b/c', (None, '/a/b')),
(2, '/a/b', '/a/b/c', (None, '/a')),
(3, '/a/b', '/a/b/c', (None, '/')),
]
)
def test_level_to_import_path(level, directory, project_path, result):
assert imports._level_to_base_import_path(project_path, directory, level) == result
def test_import_name_calculation(Script):
s = Script(path=os.path.join(test_dir, 'completion', 'isinstance.py'))
m = s._get_module()
assert m.string_names == ('test', 'completion', 'isinstance')
@pytest.mark.parametrize('name', ('builtins', 'typing'))
def test_pre_defined_imports_module(Script, environment, name):
if environment.version_info.major < 3 and name == 'builtins':
name = '__builtin__'
path = os.path.join(root_dir, name + '.py')
module = Script('', path=path)._get_module()
assert module.string_names == (name,)
assert module.evaluator.builtins_module.py__file__() != path
assert module.evaluator.typing_module.py__file__() != path
@pytest.mark.parametrize('name', ('builtins', 'typing'))
def test_import_needed_modules_by_jedi(Script, environment, tmpdir, name):
if environment.version_info.major < 3 and name == 'builtins':
name = '__builtin__'
module_path = tmpdir.join(name + '.py')
module_path.write('int = ...')
script = Script(
'import ' + name,
path=tmpdir.join('something.py').strpath,
sys_path=[tmpdir.strpath] + environment.get_sys_path(),
)
module, = script.goto_definitions()
assert module._evaluator.builtins_module.py__file__() != module_path
assert module._evaluator.typing_module.py__file__() != module_path

View File

@@ -1,12 +1,12 @@
import pytest
from jedi.evaluate.context import CompiledInstance
from jedi.evaluate.context import TreeInstance
def _eval_literal(Script, code, is_fstring=False):
def_, = Script(code).goto_definitions()
if is_fstring:
assert def_.name == 'str'
assert isinstance(def_._name._context, CompiledInstance)
assert isinstance(def_._name._context, TreeInstance)
return ''
else:
return def_._name._context.get_safe_value()

View File

@@ -1,6 +1,9 @@
from os.path import dirname, join
import pytest
import py
from ..helpers import get_example_dir
SYS_PATH = [join(dirname(__file__), d)
@@ -72,3 +75,22 @@ def test_nested_namespace_package(Script):
result = script.goto_definitions()
assert len(result) == 1
def test_relative_import(Script, environment, tmpdir):
"""
Attempt a relative import in a very simple namespace package.
"""
if environment.version_info < (3, 4):
pytest.skip()
directory = get_example_dir('namespace_package_relative_import')
# Need to copy the content in a directory where there's no __init__.py.
py.path.local(directory).copy(tmpdir)
file_path = join(tmpdir.strpath, "rel1.py")
script = Script(path=file_path, line=1)
d, = script.goto_definitions()
assert d.name == 'int'
d, = script.goto_assignments()
assert d.name == 'name'
assert d.module_name == 'rel2'

View File

@@ -4,9 +4,10 @@ import pytest
@pytest.mark.parametrize('source', [
'1 == 1',
'1.0 == 1',
'... == ...'
pytest.param('1 == 1'),
pytest.param('1.0 == 1'),
# Unfortunately for now not possible, because it's a typeshed object.
pytest.param('... == ...', marks=pytest.mark.xfail),
])
def test_equals(Script, environment, source):
if environment.version_info.major < 3:

View File

@@ -10,8 +10,10 @@ import os
import shutil
import sys
import pytest
import jedi
from ..helpers import cwd_at
from jedi.api.environment import SameEnvironment, InterpreterEnvironment
SRC = """class Foo:
@@ -22,35 +24,50 @@ class Bar:
"""
def generate_pyc():
os.mkdir("dummy_package")
with open("dummy_package/__init__.py", 'w'):
@pytest.fixture
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'):
pass
with open("dummy_package/dummy.py", 'w') as f:
dummy_path = os.path.join(dummy_package_path, 'dummy.py')
with open(dummy_path, 'w') as f:
f.write(SRC)
import compileall
compileall.compile_file("dummy_package/dummy.py")
os.remove("dummy_package/dummy.py")
compileall.compile_file(dummy_path)
os.remove(dummy_path)
if sys.version_info[0] == 3:
if sys.version_info.major == 3:
# Python3 specific:
# To import pyc modules, we must move them out of the __pycache__
# directory and rename them to remove ".cpython-%s%d"
# see: http://stackoverflow.com/questions/11648440/python-does-not-detect-pyc-files
for f in os.listdir("dummy_package/__pycache__"):
pycache = os.path.join(dummy_package_path, "__pycache__")
for f in os.listdir(pycache):
dst = f.replace('.cpython-%s%s' % sys.version_info[:2], "")
dst = os.path.join("dummy_package", dst)
shutil.copy(os.path.join("dummy_package/__pycache__", f), dst)
dst = os.path.join(dummy_package_path, dst)
shutil.copy(os.path.join(pycache, f), dst)
try:
yield path
finally:
shutil.rmtree(path)
@cwd_at('test/test_evaluate')
def test_pyc(Script):
def test_pyc(pyc_project_path, environment):
"""
The list of completion must be greater than 2.
"""
try:
generate_pyc()
s = jedi.Script("from dummy_package import dummy; dummy.", path='blub.py')
assert len(s.completions()) >= 2
finally:
shutil.rmtree("dummy_package")
path = os.path.join(pyc_project_path, 'blub.py')
if not isinstance(environment, InterpreterEnvironment):
# We are using the same version for pyc completions here, because it
# was compiled in that version. However with interpreter environments
# we also have the same version and it's easier to debug.
environment = SameEnvironment()
environment = environment
s = jedi.Script(
"from dummy_package import dummy; dummy.",
path=path,
environment=environment)
assert len(s.completions()) >= 2

View File

@@ -1,5 +1,7 @@
from textwrap import dedent
from jedi.evaluate.helpers import execute_evaluated
def get_definition_and_evaluator(Script, source):
first, = Script(dedent(source)).goto_definitions()
@@ -20,8 +22,8 @@ def test_function_execution(Script):
# Now just use the internals of the result (easiest way to get a fully
# usable function).
# Should return the same result both times.
assert len(func.execute_evaluated()) == 1
assert len(func.execute_evaluated()) == 1
assert len(execute_evaluated(func)) == 1
assert len(execute_evaluated(func)) == 1
def test_class_mro(Script):

View File

@@ -7,14 +7,6 @@ from textwrap import dedent
import pytest
# The namedtuple is different for different Python2.7 versions. Some versions
# are missing the attribute `_class_template`.
@pytest.fixture(autouse=True)
def skipping(environment):
if environment.version_info.major < 3:
pytest.skip()
@pytest.mark.parametrize(['letter', 'expected'], [
('n', ['name']),
('s', ['smart']),
@@ -86,3 +78,26 @@ def test_namedtuple_goto_definitions(Script):
assert d1.get_line_code() == "class Foo(tuple):\n"
assert d1.module_path is None
def test_re_sub(Script, environment):
"""
This whole test was taken out of completion/stdlib.py, because of the
version differences.
"""
def run(code):
defs = Script(code).goto_definitions()
return {d.name for d in defs}
names = run("import re; re.sub('a', 'a', 'f')")
if environment.version_info.major == 2:
assert names == {'str', 'unicode'}
else:
assert names == {'str', 'bytes'}
# This param is missing because of overloading.
names = run("import re; re.sub('a', 'a')")
if environment.version_info.major == 2:
assert names == {'str', 'unicode'}
else:
assert names == {'str', 'bytes'}

View File

@@ -3,6 +3,8 @@ from glob import glob
import sys
import shutil
import pytest
from jedi.evaluate import sys_path
from jedi.api.environment import create_environment
@@ -29,10 +31,8 @@ def test_paths_from_assignment(Script):
def test_venv_and_pths(venv_path):
pjoin = os.path.join
virtualenv = create_environment(venv_path)
CUR_DIR = os.path.dirname(__file__)
site_pkg_path = pjoin(virtualenv.path, 'lib')
site_pkg_path = pjoin(venv_path, 'lib')
if os.name == 'nt':
site_pkg_path = pjoin(site_pkg_path, 'site-packages')
else:
@@ -40,6 +40,7 @@ def test_venv_and_pths(venv_path):
shutil.rmtree(site_pkg_path)
shutil.copytree(pjoin(CUR_DIR, 'sample_venvs', 'pth_directory'), site_pkg_path)
virtualenv = create_environment(venv_path)
venv_paths = virtualenv.get_sys_path()
ETALON = [
@@ -60,3 +61,45 @@ def test_venv_and_pths(venv_path):
# Ensure that none of venv dirs leaked to the interpreter.
assert not set(sys.path).intersection(ETALON)
_s = ['/a', '/b', '/c/d/']
@pytest.mark.parametrize(
'sys_path_, module_path, expected, is_package', [
(_s, '/a/b', ('b',), False),
(_s, '/a/b/c', ('b', 'c'), False),
(_s, '/a/b.py', ('b',), False),
(_s, '/a/b/c.py', ('b', 'c'), False),
(_s, '/x/b.py', None, False),
(_s, '/c/d/x.py', ('x',), False),
(_s, '/c/d/x.py', ('x',), False),
(_s, '/c/d/x/y.py', ('x', 'y'), False),
# If dots are in there they also resolve. These are obviously illegal
# in Python, but Jedi can handle them. Give the user a bit more freedom
# that he will have to correct eventually.
(_s, '/a/b.c.py', ('b.c',), False),
(_s, '/a/b.d/foo.bar.py', ('b.d', 'foo.bar'), False),
(_s, '/a/.py', None, False),
(_s, '/a/c/.py', None, False),
(['/foo'], '/foo/bar/__init__.py', ('bar',), True),
(['/foo'], '/foo/bar/baz/__init__.py', ('bar', 'baz'), True),
(['/foo'], '/foo/bar.so', ('bar',), False),
(['/foo'], '/foo/bar/__init__.so', ('bar',), True),
(['/foo'], '/x/bar.py', None, False),
(['/foo'], '/foo/bar.xyz', ('bar.xyz',), False),
(['/foo', '/foo/bar'], '/foo/bar/baz', ('baz',), False),
(['/foo/bar', '/foo'], '/foo/bar/baz', ('baz',), False),
(['/'], '/bar/baz.py', ('bar', 'baz',), False),
])
def test_transform_path_to_dotted(sys_path_, module_path, expected, is_package):
# transform_path_to_dotted expects normalized absolute paths.
sys_path_ = [os.path.abspath(path) for path in sys_path_]
module_path = os.path.abspath(module_path)
assert sys_path.transform_path_to_dotted(sys_path_, module_path) \
== (expected, is_package)

View File

@@ -84,5 +84,3 @@ def test_get_call_signature(code, call_signature):
if node.type == 'simple_stmt':
node = node.children[0]
assert parser_utils.get_call_signature(node) == call_signature
assert parser_utils.get_doc_with_call_signature(node) == (call_signature + '\n\n')

23
test/test_settings.py Normal file
View File

@@ -0,0 +1,23 @@
import pytest
from jedi import settings
from jedi.evaluate.names import ContextName
from jedi.evaluate.compiled import CompiledContextName
from jedi.evaluate.gradual.typeshed import StubModuleContext
@pytest.fixture()
def auto_import_json(monkeypatch):
monkeypatch.setattr(settings, 'auto_import_modules', ['json'])
def test_base_auto_import_modules(auto_import_json, Script):
loads, = Script('import json; json.loads').goto_definitions()
assert isinstance(loads._name, ContextName)
context, = loads._name.infer()
assert isinstance(context.parent_context, StubModuleContext)
def test_auto_import_modules_imports(auto_import_json, Script):
main, = Script('from json import tool; tool.main').goto_definitions()
assert isinstance(main._name, CompiledContextName)

View File

@@ -30,7 +30,7 @@ def _check_speed(time_per_run, number=4, run_warm=True):
return decorated
@_check_speed(0.3)
@_check_speed(0.5)
def test_os_path_join(Script):
s = "from posixpath import join; join('', '')."
assert len(Script(s).completions()) > 10 # is a str completion

View File

@@ -76,7 +76,11 @@ class TestSetupReadline(unittest.TestCase):
goal = {s + el for el in dir(os)}
# There are minor differences, e.g. the dir doesn't include deleted
# items as well as items that are not only available on linux.
assert len(set(self.completions(s)).symmetric_difference(goal)) < 20
difference = set(self.completions(s)).symmetric_difference(goal)
difference = {x for x in difference if not x.startswith('from os import _')}
# There are quite a few differences, because both Windows and Linux
# (posix and nt) libraries are included.
assert len(difference) < 38
@cwd_at('test')
def test_local_import(self):