forked from VimPlug/jedi
test_evaluate -> test_inference
This commit is contained in:
0
test/test_inference/__init__.py
Normal file
0
test/test_inference/__init__.py
Normal file
14
test/test_inference/absolute_import/local_module.py
Normal file
14
test/test_inference/absolute_import/local_module.py
Normal file
@@ -0,0 +1,14 @@
|
||||
"""
|
||||
This is a module that imports the *standard library* unittest,
|
||||
despite there being a local "unittest" module. It specifies that it
|
||||
wants the stdlib one with the ``absolute_import`` __future__ import.
|
||||
|
||||
The twisted equivalent of this module is ``twisted.trial._synctest``.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
import unittest
|
||||
|
||||
|
||||
class Assertions(unittest.TestCase):
|
||||
pass
|
||||
14
test/test_inference/absolute_import/unittest.py
Normal file
14
test/test_inference/absolute_import/unittest.py
Normal file
@@ -0,0 +1,14 @@
|
||||
"""
|
||||
This is a module that shadows a builtin (intentionally).
|
||||
|
||||
It imports a local module, which in turn imports stdlib unittest (the
|
||||
name shadowed by this module). If that is properly resolved, there's
|
||||
no problem. However, if jedi doesn't understand absolute_imports, it
|
||||
will get this module again, causing infinite recursion.
|
||||
"""
|
||||
from local_module import Assertions
|
||||
|
||||
|
||||
class TestCase(Assertions):
|
||||
def test(self):
|
||||
self.assertT
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Baz = 1
|
||||
2
test/test_inference/flask-site-packages/flask_foo.py
Normal file
2
test/test_inference/flask-site-packages/flask_foo.py
Normal file
@@ -0,0 +1,2 @@
|
||||
class Foo(object):
|
||||
pass
|
||||
2
test/test_inference/flask-site-packages/flaskext/bar.py
Normal file
2
test/test_inference/flask-site-packages/flaskext/bar.py
Normal file
@@ -0,0 +1,2 @@
|
||||
class Bar(object):
|
||||
pass
|
||||
@@ -0,0 +1 @@
|
||||
Moo = 1
|
||||
@@ -0,0 +1 @@
|
||||
foo = 'ns1_file!'
|
||||
@@ -0,0 +1 @@
|
||||
foo = 'ns2_file!'
|
||||
@@ -0,0 +1 @@
|
||||
CONST = 1
|
||||
BIN
test/test_inference/init_extension_module/__init__.cpython-34m.so
Executable file
BIN
test/test_inference/init_extension_module/__init__.cpython-34m.so
Executable file
Binary file not shown.
15
test/test_inference/init_extension_module/module.c
Normal file
15
test/test_inference/init_extension_module/module.c
Normal file
@@ -0,0 +1,15 @@
|
||||
#include "Python.h"
|
||||
|
||||
static struct PyModuleDef module = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"init_extension_module",
|
||||
NULL,
|
||||
-1,
|
||||
NULL
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC PyInit_init_extension_module(void){
|
||||
PyObject *m = PyModule_Create(&module);
|
||||
PyModule_AddObject(m, "foo", Py_None);
|
||||
return m;
|
||||
}
|
||||
10
test/test_inference/init_extension_module/setup.py
Normal file
10
test/test_inference/init_extension_module/setup.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from distutils.core import setup, Extension
|
||||
|
||||
setup(name='init_extension_module',
|
||||
version='0.0',
|
||||
description='',
|
||||
ext_modules=[
|
||||
Extension('init_extension_module.__init__',
|
||||
sources=['module.c'])
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,9 @@
|
||||
foo = 'ns1!'
|
||||
|
||||
# this is a namespace package
|
||||
try:
|
||||
import pkg_resources
|
||||
pkg_resources.declare_namespace(__name__)
|
||||
except ImportError:
|
||||
import pkgutil
|
||||
__path__ = pkgutil.extend_path(__path__, __name__)
|
||||
@@ -0,0 +1 @@
|
||||
foo = 'ns1_file!'
|
||||
@@ -0,0 +1 @@
|
||||
foo = 'ns1_folder!'
|
||||
@@ -0,0 +1 @@
|
||||
foo = 'ns2_file!'
|
||||
@@ -0,0 +1 @@
|
||||
foo = 'ns2_folder!'
|
||||
@@ -0,0 +1 @@
|
||||
foo = 'nested!'
|
||||
0
test/test_inference/nested_namespaces/__init__.py
Normal file
0
test/test_inference/nested_namespaces/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
try:
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
except ImportError:
|
||||
pass
|
||||
@@ -0,0 +1 @@
|
||||
CONST = 1
|
||||
0
test/test_inference/not_in_sys_path/__init__.py
Normal file
0
test/test_inference/not_in_sys_path/__init__.py
Normal file
1
test/test_inference/not_in_sys_path/not_in_sys_path.py
Normal file
1
test/test_inference/not_in_sys_path/not_in_sys_path.py
Normal file
@@ -0,0 +1 @@
|
||||
value = 3
|
||||
@@ -0,0 +1 @@
|
||||
value = 'package'
|
||||
@@ -0,0 +1 @@
|
||||
value = 'package.module'
|
||||
0
test/test_inference/not_in_sys_path/pkg/__init__.py
Normal file
0
test/test_inference/not_in_sys_path/pkg/__init__.py
Normal file
7
test/test_inference/not_in_sys_path/pkg/module.py
Normal file
7
test/test_inference/not_in_sys_path/pkg/module.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from not_in_sys_path import not_in_sys_path
|
||||
from not_in_sys_path import not_in_sys_path_package
|
||||
from not_in_sys_path.not_in_sys_path_package import module
|
||||
|
||||
not_in_sys_path.value
|
||||
not_in_sys_path_package.value
|
||||
module.value
|
||||
@@ -0,0 +1,2 @@
|
||||
# This file is here to force git to create the directory, as *.pth files only
|
||||
# add existing directories.
|
||||
@@ -0,0 +1 @@
|
||||
/path/from/egg-link
|
||||
1
test/test_inference/sample_venvs/pth_directory/foo.pth
Normal file
1
test/test_inference/sample_venvs/pth_directory/foo.pth
Normal file
@@ -0,0 +1 @@
|
||||
./dir-from-foo-pth
|
||||
@@ -0,0 +1 @@
|
||||
import smth; smth.extend_path_foo()
|
||||
@@ -0,0 +1 @@
|
||||
./relative/egg-link/path
|
||||
6
test/test_inference/sample_venvs/pth_directory/smth.py
Normal file
6
test/test_inference/sample_venvs/pth_directory/smth.py
Normal file
@@ -0,0 +1,6 @@
|
||||
import sys
|
||||
sys.path.append('/foo/smth.py:module')
|
||||
|
||||
|
||||
def extend_path_foo():
|
||||
sys.path.append('/foo/smth.py:from_func')
|
||||
11
test/test_inference/test_absolute_import.py
Normal file
11
test/test_inference/test_absolute_import.py
Normal file
@@ -0,0 +1,11 @@
|
||||
"""
|
||||
Tests ``from __future__ import absolute_import`` (only important for
|
||||
Python 2.X)
|
||||
"""
|
||||
from .. import helpers
|
||||
|
||||
|
||||
@helpers.cwd_at("test/test_inference/absolute_import")
|
||||
def test_can_complete_when_shadowing(Script):
|
||||
script = Script(path="unittest.py")
|
||||
assert script.completions()
|
||||
64
test/test_inference/test_annotations.py
Normal file
64
test/test_inference/test_annotations.py
Normal file
@@ -0,0 +1,64 @@
|
||||
from textwrap import dedent
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
def test_simple_annotations(Script, environment):
|
||||
"""
|
||||
Annotations only exist in Python 3.
|
||||
If annotations adhere to PEP-0484, we use them (they override inference),
|
||||
else they are parsed but ignored
|
||||
"""
|
||||
if environment.version_info.major == 2:
|
||||
pytest.skip()
|
||||
|
||||
source = dedent("""\
|
||||
def annot(a:3):
|
||||
return a
|
||||
|
||||
annot('')""")
|
||||
|
||||
assert [d.name for d in Script(source).goto_definitions()] == ['str']
|
||||
|
||||
source = dedent("""\
|
||||
|
||||
def annot_ret(a:3) -> 3:
|
||||
return a
|
||||
|
||||
annot_ret('')""")
|
||||
assert [d.name for d in Script(source).goto_definitions()] == ['str']
|
||||
|
||||
source = dedent("""\
|
||||
def annot(a:int):
|
||||
return a
|
||||
|
||||
annot('')""")
|
||||
|
||||
assert [d.name for d in Script(source).goto_definitions()] == ['int']
|
||||
|
||||
|
||||
@pytest.mark.parametrize('reference', [
|
||||
'assert 1',
|
||||
'1',
|
||||
'def x(): pass',
|
||||
'1, 2',
|
||||
r'1\n'
|
||||
])
|
||||
def test_illegal_forward_references(Script, environment, reference):
|
||||
if environment.version_info.major == 2:
|
||||
pytest.skip()
|
||||
|
||||
source = 'def foo(bar: "%s"): bar' % reference
|
||||
|
||||
assert not Script(source).goto_definitions()
|
||||
|
||||
|
||||
def test_lambda_forward_references(Script, environment):
|
||||
if environment.version_info.major == 2:
|
||||
pytest.skip()
|
||||
|
||||
source = 'def foo(bar: "lambda: 3"): bar'
|
||||
|
||||
# For now just receiving the 3 is ok. I'm doubting that this is what we
|
||||
# want. We also execute functions. Should we only execute classes?
|
||||
assert Script(source).goto_definitions()
|
||||
91
test/test_inference/test_buildout_detection.py
Normal file
91
test/test_inference/test_buildout_detection.py
Normal file
@@ -0,0 +1,91 @@
|
||||
import os
|
||||
from textwrap import dedent
|
||||
|
||||
from jedi._compatibility import force_unicode
|
||||
from jedi.evaluate.sys_path import (_get_parent_dir_with_file,
|
||||
_get_buildout_script_paths,
|
||||
check_sys_path_modifications)
|
||||
|
||||
from ..helpers import cwd_at
|
||||
|
||||
|
||||
def check_module_test(Script, code):
|
||||
module_context = Script(code)._get_module()
|
||||
return check_sys_path_modifications(module_context)
|
||||
|
||||
|
||||
@cwd_at('test/examples/buildout_project/src/proj_name')
|
||||
def test_parent_dir_with_file(Script):
|
||||
parent = _get_parent_dir_with_file(
|
||||
os.path.abspath(os.curdir), 'buildout.cfg')
|
||||
assert parent is not None
|
||||
assert parent.endswith(os.path.join('test', 'examples', 'buildout_project'))
|
||||
|
||||
|
||||
@cwd_at('test/examples/buildout_project/src/proj_name')
|
||||
def test_buildout_detection(Script):
|
||||
scripts = list(_get_buildout_script_paths(os.path.abspath('./module_name.py')))
|
||||
assert len(scripts) == 1
|
||||
curdir = os.path.abspath(os.curdir)
|
||||
appdir_path = os.path.normpath(os.path.join(curdir, '../../bin/app'))
|
||||
assert scripts[0] == appdir_path
|
||||
|
||||
|
||||
def test_append_on_non_sys_path(Script):
|
||||
code = dedent("""
|
||||
class Dummy(object):
|
||||
path = []
|
||||
|
||||
d = Dummy()
|
||||
d.path.append('foo')"""
|
||||
)
|
||||
|
||||
paths = check_module_test(Script, code)
|
||||
assert not paths
|
||||
assert 'foo' not in paths
|
||||
|
||||
|
||||
def test_path_from_invalid_sys_path_assignment(Script):
|
||||
code = dedent("""
|
||||
import sys
|
||||
sys.path = 'invalid'"""
|
||||
)
|
||||
|
||||
paths = check_module_test(Script, code)
|
||||
assert not paths
|
||||
assert 'invalid' not in paths
|
||||
|
||||
|
||||
@cwd_at('test/examples/buildout_project/src/proj_name/')
|
||||
def test_sys_path_with_modifications(Script):
|
||||
code = dedent("""
|
||||
import os
|
||||
""")
|
||||
|
||||
path = os.path.abspath(os.path.join(os.curdir, 'module_name.py'))
|
||||
paths = Script(code, path=path)._evaluator.get_sys_path()
|
||||
assert '/tmp/.buildout/eggs/important_package.egg' in paths
|
||||
|
||||
|
||||
def test_path_from_sys_path_assignment(Script):
|
||||
code = dedent("""
|
||||
#!/usr/bin/python
|
||||
|
||||
import sys
|
||||
sys.path[0:0] = [
|
||||
'/usr/lib/python3.4/site-packages',
|
||||
'/home/test/.buildout/eggs/important_package.egg'
|
||||
]
|
||||
|
||||
path[0:0] = [1]
|
||||
|
||||
import important_package
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(important_package.main())"""
|
||||
)
|
||||
|
||||
paths = check_module_test(Script, code)
|
||||
paths = list(map(force_unicode, paths))
|
||||
assert 1 not in paths
|
||||
assert '/home/test/.buildout/eggs/important_package.egg' in paths
|
||||
171
test/test_inference/test_compiled.py
Normal file
171
test/test_inference/test_compiled.py
Normal file
@@ -0,0 +1,171 @@
|
||||
from textwrap import dedent
|
||||
import math
|
||||
import sys
|
||||
from collections import Counter
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from jedi.evaluate import compiled
|
||||
from jedi.evaluate.compiled.access import DirectObjectAccess
|
||||
from jedi.evaluate.gradual.conversion import _stub_to_python_context_set
|
||||
|
||||
|
||||
def test_simple(evaluator, environment):
|
||||
obj = compiled.create_simple_object(evaluator, u'_str_')
|
||||
upper, = obj.py__getattribute__(u'upper')
|
||||
objs = list(upper.execute_with_values())
|
||||
assert len(objs) == 1
|
||||
if environment.version_info.major == 2:
|
||||
expected = 'unicode'
|
||||
else:
|
||||
expected = 'str'
|
||||
assert objs[0].name.string_name == expected
|
||||
|
||||
|
||||
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_next_docstr(evaluator):
|
||||
next_ = compiled.builtin_from_name(evaluator, u'next')
|
||||
assert next_.tree_node is not None
|
||||
assert next_.py__doc__() == '' # It's a stub
|
||||
for non_stub in _stub_to_python_context_set(next_):
|
||||
assert non_stub.py__doc__() == next.__doc__
|
||||
|
||||
|
||||
def test_parse_function_doc_illegal_docstr():
|
||||
docstr = """
|
||||
test_func(o
|
||||
|
||||
doesn't have a closing bracket.
|
||||
"""
|
||||
assert ('', '') == compiled.context._parse_function_doc(docstr)
|
||||
|
||||
|
||||
def test_doc(evaluator):
|
||||
"""
|
||||
Even CompiledObject docs always return empty docstrings - not None, that's
|
||||
just a Jedi API definition.
|
||||
"""
|
||||
str_ = compiled.create_simple_object(evaluator, u'')
|
||||
# Equals `''.__getnewargs__`
|
||||
obj, = str_.py__getattribute__(u'__getnewargs__')
|
||||
assert obj.py__doc__() == ''
|
||||
|
||||
|
||||
def test_string_literals(Script, environment):
|
||||
def typ(string):
|
||||
d = Script("a = %s; a" % string).goto_definitions()[0]
|
||||
return d.name
|
||||
|
||||
assert typ('""') == 'str'
|
||||
assert typ('r""') == 'str'
|
||||
if environment.version_info.major > 2:
|
||||
assert typ('br""') == 'bytes'
|
||||
assert typ('b""') == 'bytes'
|
||||
assert typ('u""') == 'str'
|
||||
else:
|
||||
assert typ('b""') == 'str'
|
||||
assert typ('u""') == 'unicode'
|
||||
|
||||
|
||||
def test_method_completion(Script, environment):
|
||||
code = dedent('''
|
||||
class Foo:
|
||||
def bar(self):
|
||||
pass
|
||||
|
||||
foo = Foo()
|
||||
foo.bar.__func__''')
|
||||
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(raw=True) == time.sleep.__doc__
|
||||
expected = 'sleep(secs: float) -> None\n\n' + time.sleep.__doc__
|
||||
assert comp.docstring() == expected
|
||||
|
||||
|
||||
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'
|
||||
|
||||
|
||||
def _return_int():
|
||||
return 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'attribute, expected_name, expected_parent', [
|
||||
('x', 'int', 'builtins'),
|
||||
('y', 'int', 'builtins'),
|
||||
('z', 'bool', 'builtins'),
|
||||
('cos', 'cos', 'math'),
|
||||
('dec', 'Decimal', 'decimal'),
|
||||
('dt', 'datetime', 'datetime'),
|
||||
('ret_int', '_return_int', 'test.test_inference.test_compiled'),
|
||||
]
|
||||
)
|
||||
def test_parent_context(same_process_evaluator, attribute, expected_name, expected_parent):
|
||||
import decimal
|
||||
|
||||
class C:
|
||||
x = 1
|
||||
y = int
|
||||
z = True
|
||||
cos = math.cos
|
||||
dec = decimal.Decimal(1)
|
||||
dt = datetime(2000, 1, 1)
|
||||
ret_int = _return_int
|
||||
|
||||
o = compiled.CompiledObject(
|
||||
same_process_evaluator,
|
||||
DirectObjectAccess(same_process_evaluator, C)
|
||||
)
|
||||
x, = o.py__getattribute__(attribute)
|
||||
assert x.py__name__() == expected_name
|
||||
module_name = x.parent_context.py__name__()
|
||||
if module_name == '__builtin__':
|
||||
module_name = 'builtins' # Python 2
|
||||
assert module_name == expected_parent
|
||||
assert x.parent_context.parent_context is None
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info[0] == 2, reason="Ignore Python 2, because EOL")
|
||||
@pytest.mark.parametrize(
|
||||
'obj, expected_names', [
|
||||
('', ['str']),
|
||||
(str, ['str']),
|
||||
(''.upper, ['str', 'upper']),
|
||||
(str.upper, ['str', 'upper']),
|
||||
|
||||
(math.cos, ['cos']),
|
||||
|
||||
(Counter, ['Counter']),
|
||||
(Counter(""), ['Counter']),
|
||||
(Counter.most_common, ['Counter', 'most_common']),
|
||||
(Counter("").most_common, ['Counter', 'most_common']),
|
||||
]
|
||||
)
|
||||
def test_qualified_names(same_process_evaluator, obj, expected_names):
|
||||
o = compiled.CompiledObject(
|
||||
same_process_evaluator,
|
||||
DirectObjectAccess(same_process_evaluator, obj)
|
||||
)
|
||||
assert o.get_qualified_names() == tuple(expected_names)
|
||||
21
test/test_inference/test_context.py
Normal file
21
test/test_inference/test_context.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from jedi._compatibility import force_unicode
|
||||
|
||||
|
||||
def test_module_attributes(Script):
|
||||
def_, = Script('__name__').completions()
|
||||
assert def_.name == '__name__'
|
||||
assert def_.line is None
|
||||
assert def_.column is None
|
||||
str_, = def_.infer()
|
||||
assert str_.name == 'str'
|
||||
|
||||
|
||||
def test_module__file__(Script, environment):
|
||||
assert not Script('__file__').goto_definitions()
|
||||
def_, = Script('__file__', path='example.py').goto_definitions()
|
||||
value = force_unicode(def_._name._context.get_safe_value())
|
||||
assert value.endswith('example.py')
|
||||
|
||||
def_, = Script('import antigravity; antigravity.__file__').goto_definitions()
|
||||
value = force_unicode(def_._name._context.get_safe_value())
|
||||
assert value.endswith('.py')
|
||||
416
test/test_inference/test_docstring.py
Normal file
416
test/test_inference/test_docstring.py
Normal file
@@ -0,0 +1,416 @@
|
||||
"""
|
||||
Testing of docstring related issues and especially ``jedi.docstrings``.
|
||||
"""
|
||||
|
||||
from textwrap import dedent
|
||||
import jedi
|
||||
import pytest
|
||||
from ..helpers import unittest
|
||||
import sys
|
||||
|
||||
try:
|
||||
import numpydoc # NOQA
|
||||
except ImportError:
|
||||
numpydoc_unavailable = True
|
||||
else:
|
||||
numpydoc_unavailable = False
|
||||
|
||||
try:
|
||||
import numpy # NOQA
|
||||
except ImportError:
|
||||
numpy_unavailable = True
|
||||
else:
|
||||
numpy_unavailable = False
|
||||
|
||||
if sys.version_info.major == 2:
|
||||
# In Python 2 there's an issue with tox/docutils that makes the tests fail,
|
||||
# Python 2 is soon end-of-life, so just don't support numpydoc for it anymore.
|
||||
numpydoc_unavailable = True
|
||||
|
||||
|
||||
def test_function_doc(Script):
|
||||
defs = Script("""
|
||||
def func():
|
||||
'''Docstring of `func`.'''
|
||||
func""").goto_definitions()
|
||||
assert defs[0].docstring() == 'func()\n\nDocstring of `func`.'
|
||||
|
||||
|
||||
def test_class_doc(Script):
|
||||
defs = Script("""
|
||||
class TestClass():
|
||||
'''Docstring of `TestClass`.'''
|
||||
TestClass""").goto_definitions()
|
||||
|
||||
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):
|
||||
defs = Script("""
|
||||
class TestClass():
|
||||
'''Docstring of `TestClass`.'''
|
||||
tc = TestClass()
|
||||
tc""").goto_definitions()
|
||||
assert defs[0].docstring() == 'Docstring of `TestClass`.'
|
||||
|
||||
|
||||
@unittest.skip('need evaluator class for that')
|
||||
def test_attribute_docstring(Script):
|
||||
defs = Script("""
|
||||
x = None
|
||||
'''Docstring of `x`.'''
|
||||
x""").goto_definitions()
|
||||
assert defs[0].docstring() == 'Docstring of `x`.'
|
||||
|
||||
|
||||
@unittest.skip('need evaluator class for that')
|
||||
def test_multiple_docstrings(Script):
|
||||
defs = Script("""
|
||||
def func():
|
||||
'''Original docstring.'''
|
||||
x = func
|
||||
'''Docstring of `x`.'''
|
||||
x""").goto_definitions()
|
||||
docs = [d.docstring() for d in defs]
|
||||
assert docs == ['Original docstring.', 'Docstring of `x`.']
|
||||
|
||||
|
||||
def test_completion(Script):
|
||||
assert Script('''
|
||||
class DocstringCompletion():
|
||||
#? []
|
||||
""" asdfas """''').completions()
|
||||
|
||||
|
||||
def test_docstrings_type_dotted_import(Script):
|
||||
s = """
|
||||
def func(arg):
|
||||
'''
|
||||
:type arg: random.Random
|
||||
'''
|
||||
arg."""
|
||||
names = [c.name for c in Script(s).completions()]
|
||||
assert 'seed' in names
|
||||
|
||||
|
||||
def test_docstrings_param_type(Script):
|
||||
s = """
|
||||
def func(arg):
|
||||
'''
|
||||
:param str arg: some description
|
||||
'''
|
||||
arg."""
|
||||
names = [c.name for c in Script(s).completions()]
|
||||
assert 'join' in names
|
||||
|
||||
|
||||
def test_docstrings_type_str(Script):
|
||||
s = """
|
||||
def func(arg):
|
||||
'''
|
||||
:type arg: str
|
||||
'''
|
||||
arg."""
|
||||
|
||||
names = [c.name for c in Script(s).completions()]
|
||||
assert 'join' in names
|
||||
|
||||
|
||||
def test_docstring_instance(Script):
|
||||
# The types hint that it's a certain kind
|
||||
s = dedent("""
|
||||
class A:
|
||||
def __init__(self,a):
|
||||
'''
|
||||
:type a: threading.Thread
|
||||
'''
|
||||
|
||||
if a is not None:
|
||||
a.start()
|
||||
|
||||
self.a = a
|
||||
|
||||
|
||||
def method_b(c):
|
||||
'''
|
||||
:type c: A
|
||||
'''
|
||||
|
||||
c.""")
|
||||
|
||||
names = [c.name for c in Script(s).completions()]
|
||||
assert 'a' in names
|
||||
assert '__init__' in names
|
||||
assert 'mro' not in names # Exists only for types.
|
||||
|
||||
|
||||
def test_docstring_keyword(Script):
|
||||
completions = Script('assert').completions()
|
||||
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,
|
||||
reason='numpydoc module is unavailable')
|
||||
def test_numpydoc_parameters():
|
||||
s = dedent('''
|
||||
def foobar(x, y):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
x : int
|
||||
y : str
|
||||
"""
|
||||
y.''')
|
||||
names = [c.name for c in jedi.Script(s).completions()]
|
||||
assert 'isupper' in names
|
||||
assert 'capitalize' in names
|
||||
|
||||
|
||||
@pytest.mark.skipif(numpydoc_unavailable,
|
||||
reason='numpydoc module is unavailable')
|
||||
def test_numpydoc_parameters_set_of_values():
|
||||
s = dedent('''
|
||||
def foobar(x, y):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
x : {'foo', 'bar', 100500}, optional
|
||||
"""
|
||||
x.''')
|
||||
names = [c.name for c in jedi.Script(s).completions()]
|
||||
assert 'isupper' in names
|
||||
assert 'capitalize' in names
|
||||
assert 'numerator' in names
|
||||
|
||||
|
||||
@pytest.mark.skipif(numpydoc_unavailable,
|
||||
reason='numpydoc module is unavailable')
|
||||
def test_numpydoc_parameters_alternative_types():
|
||||
s = dedent('''
|
||||
def foobar(x, y):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
x : int or str or list
|
||||
"""
|
||||
x.''')
|
||||
names = [c.name for c in jedi.Script(s).completions()]
|
||||
assert 'isupper' in names
|
||||
assert 'capitalize' in names
|
||||
assert 'numerator' in names
|
||||
assert 'append' in names
|
||||
|
||||
|
||||
@pytest.mark.skipif(numpydoc_unavailable,
|
||||
reason='numpydoc module is unavailable')
|
||||
def test_numpydoc_invalid():
|
||||
s = dedent('''
|
||||
def foobar(x, y):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
x : int (str, py.path.local
|
||||
"""
|
||||
x.''')
|
||||
|
||||
assert not jedi.Script(s).completions()
|
||||
|
||||
|
||||
@pytest.mark.skipif(numpydoc_unavailable,
|
||||
reason='numpydoc module is unavailable')
|
||||
def test_numpydoc_returns():
|
||||
s = dedent('''
|
||||
def foobar():
|
||||
"""
|
||||
Returns
|
||||
----------
|
||||
x : int
|
||||
y : str
|
||||
"""
|
||||
return x
|
||||
|
||||
def bazbiz():
|
||||
z = foobar()
|
||||
z.''')
|
||||
names = [c.name for c in jedi.Script(s).completions()]
|
||||
assert 'isupper' in names
|
||||
assert 'capitalize' in names
|
||||
assert 'numerator' in names
|
||||
|
||||
|
||||
@pytest.mark.skipif(numpydoc_unavailable,
|
||||
reason='numpydoc module is unavailable')
|
||||
def test_numpydoc_returns_set_of_values():
|
||||
s = dedent('''
|
||||
def foobar():
|
||||
"""
|
||||
Returns
|
||||
----------
|
||||
x : {'foo', 'bar', 100500}
|
||||
"""
|
||||
return x
|
||||
|
||||
def bazbiz():
|
||||
z = foobar()
|
||||
z.''')
|
||||
names = [c.name for c in jedi.Script(s).completions()]
|
||||
assert 'isupper' in names
|
||||
assert 'capitalize' in names
|
||||
assert 'numerator' in names
|
||||
|
||||
|
||||
@pytest.mark.skipif(numpydoc_unavailable,
|
||||
reason='numpydoc module is unavailable')
|
||||
def test_numpydoc_returns_alternative_types():
|
||||
s = dedent('''
|
||||
def foobar():
|
||||
"""
|
||||
Returns
|
||||
----------
|
||||
int or list of str
|
||||
"""
|
||||
return x
|
||||
|
||||
def bazbiz():
|
||||
z = foobar()
|
||||
z.''')
|
||||
names = [c.name for c in jedi.Script(s).completions()]
|
||||
assert 'isupper' not in names
|
||||
assert 'capitalize' not in names
|
||||
assert 'numerator' in names
|
||||
assert 'append' in names
|
||||
|
||||
|
||||
@pytest.mark.skipif(numpydoc_unavailable,
|
||||
reason='numpydoc module is unavailable')
|
||||
def test_numpydoc_returns_list_of():
|
||||
s = dedent('''
|
||||
def foobar():
|
||||
"""
|
||||
Returns
|
||||
----------
|
||||
list of str
|
||||
"""
|
||||
return x
|
||||
|
||||
def bazbiz():
|
||||
z = foobar()
|
||||
z.''')
|
||||
names = [c.name for c in jedi.Script(s).completions()]
|
||||
assert 'append' in names
|
||||
assert 'isupper' not in names
|
||||
assert 'capitalize' not in names
|
||||
|
||||
|
||||
@pytest.mark.skipif(numpydoc_unavailable,
|
||||
reason='numpydoc module is unavailable')
|
||||
def test_numpydoc_returns_obj():
|
||||
s = dedent('''
|
||||
def foobar(x, y):
|
||||
"""
|
||||
Returns
|
||||
----------
|
||||
int or random.Random
|
||||
"""
|
||||
return x + y
|
||||
|
||||
def bazbiz():
|
||||
z = foobar(x, y)
|
||||
z.''')
|
||||
script = jedi.Script(s)
|
||||
names = [c.name for c in script.completions()]
|
||||
assert 'numerator' in names
|
||||
assert 'seed' in names
|
||||
|
||||
|
||||
@pytest.mark.skipif(numpydoc_unavailable,
|
||||
reason='numpydoc module is unavailable')
|
||||
def test_numpydoc_yields():
|
||||
s = dedent('''
|
||||
def foobar():
|
||||
"""
|
||||
Yields
|
||||
----------
|
||||
x : int
|
||||
y : str
|
||||
"""
|
||||
return x
|
||||
|
||||
def bazbiz():
|
||||
z = foobar():
|
||||
z.''')
|
||||
names = [c.name for c in jedi.Script(s).completions()]
|
||||
assert 'isupper' in names
|
||||
assert 'capitalize' in names
|
||||
assert 'numerator' in names
|
||||
|
||||
|
||||
@pytest.mark.skipif(numpydoc_unavailable or numpy_unavailable,
|
||||
reason='numpydoc or numpy module is unavailable')
|
||||
def test_numpy_returns():
|
||||
s = dedent('''
|
||||
import numpy
|
||||
x = numpy.asarray([])
|
||||
x.d'''
|
||||
)
|
||||
names = [c.name for c in jedi.Script(s).completions()]
|
||||
assert 'diagonal' in names
|
||||
|
||||
|
||||
@pytest.mark.skipif(numpydoc_unavailable or numpy_unavailable,
|
||||
reason='numpydoc or numpy module is unavailable')
|
||||
def test_numpy_comp_returns():
|
||||
s = dedent('''
|
||||
import numpy
|
||||
x = numpy.array([])
|
||||
x.d'''
|
||||
)
|
||||
names = [c.name for c in jedi.Script(s).completions()]
|
||||
assert 'diagonal' in names
|
||||
|
||||
|
||||
def test_decorator(Script):
|
||||
code = dedent('''
|
||||
def decorator(name=None):
|
||||
def _decorate(func):
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
"""wrapper docstring"""
|
||||
return func(*args, **kwargs)
|
||||
return wrapper
|
||||
return _decorate
|
||||
|
||||
|
||||
@decorator('testing')
|
||||
def check_user(f):
|
||||
"""Nice docstring"""
|
||||
pass
|
||||
|
||||
check_user''')
|
||||
|
||||
d, = Script(code).goto_definitions()
|
||||
assert d.docstring(raw=True) == 'Nice docstring'
|
||||
57
test/test_inference/test_extension.py
Normal file
57
test/test_inference/test_extension.py
Normal file
@@ -0,0 +1,57 @@
|
||||
"""
|
||||
Test compiled module
|
||||
"""
|
||||
import os
|
||||
|
||||
import jedi
|
||||
from ..helpers import cwd_at
|
||||
import pytest
|
||||
|
||||
|
||||
def test_completions(Script):
|
||||
s = Script('import _ctypes; _ctypes.')
|
||||
assert len(s.completions()) >= 15
|
||||
|
||||
|
||||
def test_call_signatures_extension(Script):
|
||||
if os.name == 'nt':
|
||||
func = 'LoadLibrary'
|
||||
params = 1
|
||||
else:
|
||||
func = 'dlopen'
|
||||
params = 2
|
||||
s = Script('import _ctypes; _ctypes.%s(' % (func,))
|
||||
sigs = s.call_signatures()
|
||||
assert len(sigs) == 1
|
||||
assert len(sigs[0].params) == params
|
||||
|
||||
|
||||
def test_call_signatures_stdlib(Script):
|
||||
s = Script('import math; math.cos(')
|
||||
sigs = s.call_signatures()
|
||||
assert len(sigs) == 1
|
||||
assert len(sigs[0].params) == 1
|
||||
|
||||
|
||||
# Check only on linux 64 bit platform and Python3.4.
|
||||
@pytest.mark.skipif('sys.platform != "linux" or sys.maxsize <= 2**32 or sys.version_info[:2] != (3, 4)')
|
||||
@cwd_at('test/test_inference')
|
||||
def test_init_extension_module(Script):
|
||||
"""
|
||||
``__init__`` extension modules are also packages and Jedi should understand
|
||||
that.
|
||||
|
||||
Originally coming from #472.
|
||||
|
||||
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
|
||||
`setup.py install`.
|
||||
|
||||
This is also why this test only runs on certain systems (and Python 3.4).
|
||||
"""
|
||||
s = jedi.Script('import init_extension_module as i\ni.', path='not_existing.py')
|
||||
assert 'foo' in [c.name for c in s.completions()]
|
||||
|
||||
s = jedi.Script('from init_extension_module import foo\nfoo', path='not_existing.py')
|
||||
assert ['foo'] == [c.name for c in s.completions()]
|
||||
19
test/test_inference/test_fstring.py
Normal file
19
test/test_inference/test_fstring.py
Normal file
@@ -0,0 +1,19 @@
|
||||
import pytest
|
||||
from textwrap import dedent
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def skip_not_supported(environment):
|
||||
if environment.version_info < (3, 6):
|
||||
pytest.skip()
|
||||
|
||||
|
||||
def test_fstring_multiline(Script):
|
||||
code = dedent("""\
|
||||
'' f'''s{
|
||||
str.uppe
|
||||
'''
|
||||
"""
|
||||
)
|
||||
c, = Script(code, line=2, column=9).completions()
|
||||
assert c.name == 'upper'
|
||||
27
test/test_inference/test_gradual/test_stub_loading.py
Normal file
27
test/test_inference/test_gradual/test_stub_loading.py
Normal 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
|
||||
94
test/test_inference/test_gradual/test_stubs.py
Normal file
94
test/test_inference/test_gradual/test_stubs.py
Normal file
@@ -0,0 +1,94 @@
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
from jedi.api.project import Project
|
||||
from test.helpers import root_dir
|
||||
|
||||
|
||||
@pytest.mark.parametrize('type_', ['goto', 'infer'])
|
||||
@pytest.mark.parametrize('way', ['direct', 'indirect'])
|
||||
@pytest.mark.parametrize(
|
||||
'kwargs', [
|
||||
dict(only_stubs=False, prefer_stubs=False),
|
||||
dict(only_stubs=False, prefer_stubs=True),
|
||||
dict(only_stubs=True, prefer_stubs=False),
|
||||
]
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
('code', 'full_name', 'has_stub', 'has_python', 'goto_changes'), [
|
||||
['import os; os.walk', 'os.walk', True, True, {}],
|
||||
['from collections import Counter', 'collections.Counter', True, True, {}],
|
||||
['from collections', 'collections', True, True, {}],
|
||||
['from collections import Counter; Counter', 'collections.Counter', True, True, {}],
|
||||
['from collections import Counter; Counter()', 'collections.Counter', True, True, {}],
|
||||
['from collections import Counter; Counter.most_common',
|
||||
'collections.Counter.most_common', True, True, {}],
|
||||
['from collections import deque', 'collections.deque', True, False, {'has_python': True}],
|
||||
|
||||
['from keyword import kwlist; kwlist', 'typing.Sequence', True, True,
|
||||
{'full_name': 'keyword.kwlist'}],
|
||||
['from keyword import kwlist', 'typing.Sequence', True, True,
|
||||
{'full_name': 'keyword.kwlist'}],
|
||||
|
||||
['from socket import AF_INET', 'socket.AddressFamily', True, False,
|
||||
{'full_name': 'socket.AF_INET'}],
|
||||
['from socket import socket', 'socket.socket', True, True, {}],
|
||||
|
||||
['import with_stub', 'with_stub', True, True, {}],
|
||||
['import with_stub', 'with_stub', True, True, {}],
|
||||
['import with_stub_folder.python_only', 'with_stub_folder.python_only', False, True, {}],
|
||||
['import stub_only', 'stub_only', True, False, {}],
|
||||
])
|
||||
def test_infer_and_goto(Script, code, full_name, has_stub, has_python, way,
|
||||
kwargs, type_, goto_changes, environment):
|
||||
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)
|
||||
pytest.skip()
|
||||
|
||||
if type_ == 'infer' and full_name == 'typing.Sequence' and environment.version_info >= (3, 7):
|
||||
# In Python 3.7+ there's not really a sequence definition, there's just
|
||||
# a name that leads nowhere.
|
||||
has_python = False
|
||||
|
||||
project = Project(os.path.join(root_dir, 'test', 'completion', 'stub_folder'))
|
||||
s = Script(code, _project=project)
|
||||
prefer_stubs = kwargs['prefer_stubs']
|
||||
only_stubs = kwargs['only_stubs']
|
||||
|
||||
if type_ == 'goto':
|
||||
full_name = goto_changes.get('full_name', full_name)
|
||||
has_python = goto_changes.get('has_python', has_python)
|
||||
|
||||
if way == 'direct':
|
||||
if type_ == 'goto':
|
||||
defs = s.goto_assignments(follow_imports=True, **kwargs)
|
||||
else:
|
||||
defs = s.goto_definitions(**kwargs)
|
||||
else:
|
||||
goto_defs = s.goto_assignments(
|
||||
# Prefering stubs when we want to go to python and vice versa
|
||||
prefer_stubs=not (prefer_stubs or only_stubs),
|
||||
follow_imports=True,
|
||||
)
|
||||
if type_ == 'goto':
|
||||
defs = [d for goto_def in goto_defs for d in goto_def.goto_assignments(**kwargs)]
|
||||
else:
|
||||
defs = [d for goto_def in goto_defs for d in goto_def.infer(**kwargs)]
|
||||
|
||||
if not has_stub and only_stubs:
|
||||
assert not defs
|
||||
else:
|
||||
assert defs
|
||||
|
||||
for d in defs:
|
||||
if prefer_stubs and has_stub:
|
||||
assert d.is_stub()
|
||||
elif only_stubs:
|
||||
assert d.is_stub()
|
||||
else:
|
||||
assert has_python == (not d.is_stub())
|
||||
assert d.full_name == full_name
|
||||
|
||||
assert d.is_stub() == d.module_path.endswith('.pyi')
|
||||
236
test/test_inference/test_gradual/test_typeshed.py
Normal file
236
test/test_inference/test_gradual/test_typeshed.py
Normal 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_assignments(only_stubs=True)
|
||||
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_assignments(only_stubs=True) == [cos]
|
||||
assert cos.full_name == full_name
|
||||
|
||||
cos, = s.goto_assignments()
|
||||
assert cos.module_path.endswith(wanted)
|
||||
assert cos.goto_assignments(only_stubs=True) == [cos]
|
||||
assert cos.is_stub() is True
|
||||
assert cos.full_name == full_name
|
||||
|
||||
|
||||
def test_goto_stubs(Script):
|
||||
s = Script('import os; os')
|
||||
os_module, = s.goto_definitions()
|
||||
assert os_module.full_name == 'os'
|
||||
assert os_module.is_stub() is False
|
||||
stub, = os_module.goto_assignments(only_stubs=True)
|
||||
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_assignments(only_stubs=True)
|
||||
|
||||
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_assignments(only_stubs=True)
|
||||
_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)
|
||||
16
test/test_inference/test_helpers.py
Normal file
16
test/test_inference/test_helpers.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from textwrap import dedent
|
||||
|
||||
from jedi import names
|
||||
from jedi.evaluate import helpers
|
||||
|
||||
|
||||
def test_call_of_leaf_in_brackets(environment):
|
||||
s = dedent("""
|
||||
x = 1
|
||||
type(x)
|
||||
""")
|
||||
last_x = names(s, references=True, definitions=False, environment=environment)[-1]
|
||||
name = last_x._name.tree_name
|
||||
|
||||
call = helpers.call_of_leaf(name)
|
||||
assert call == name
|
||||
105
test/test_inference/test_implicit_namespace_package.py
Normal file
105
test/test_inference/test_implicit_namespace_package.py
Normal file
@@ -0,0 +1,105 @@
|
||||
from os.path import dirname, join
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def skip_not_supported_versions(environment):
|
||||
if environment.version_info < (3, 4):
|
||||
pytest.skip()
|
||||
|
||||
|
||||
def test_implicit_namespace_package(Script):
|
||||
sys_path = [join(dirname(__file__), d)
|
||||
for d in ['implicit_namespace_package/ns1', 'implicit_namespace_package/ns2']]
|
||||
|
||||
def script_with_path(*args, **kwargs):
|
||||
return Script(sys_path=sys_path, *args, **kwargs)
|
||||
|
||||
# goto definition
|
||||
assert script_with_path('from pkg import ns1_file').goto_definitions()
|
||||
assert script_with_path('from pkg import ns2_file').goto_definitions()
|
||||
assert not script_with_path('from pkg import ns3_file').goto_definitions()
|
||||
|
||||
# goto assignment
|
||||
tests = {
|
||||
'from pkg.ns2_file import foo': 'ns2_file!',
|
||||
'from pkg.ns1_file import foo': 'ns1_file!',
|
||||
}
|
||||
for source, solution in tests.items():
|
||||
ass = script_with_path(source).goto_assignments()
|
||||
assert len(ass) == 1
|
||||
assert ass[0].description == "foo = '%s'" % solution
|
||||
|
||||
# completion
|
||||
completions = script_with_path('from pkg import ').completions()
|
||||
names = [c.name for c in completions]
|
||||
compare = ['ns1_file', 'ns2_file']
|
||||
# must at least contain these items, other items are not important
|
||||
assert set(compare) == set(names)
|
||||
|
||||
tests = {
|
||||
'from pkg import ns2_file as x': 'ns2_file!',
|
||||
'from pkg import ns1_file as x': 'ns1_file!'
|
||||
}
|
||||
for source, solution in tests.items():
|
||||
for c in script_with_path(source + '; x.').completions():
|
||||
if c.name == 'foo':
|
||||
completion = c
|
||||
solution = "foo = '%s'" % solution
|
||||
assert completion.description == solution
|
||||
|
||||
|
||||
def test_implicit_nested_namespace_package(Script):
|
||||
code = 'from implicit_nested_namespaces.namespace.pkg.module import CONST'
|
||||
|
||||
sys_path = [dirname(__file__)]
|
||||
|
||||
script = Script(sys_path=sys_path, source=code, line=1, column=61)
|
||||
|
||||
result = script.goto_definitions()
|
||||
|
||||
assert len(result) == 1
|
||||
|
||||
implicit_pkg, = Script(code, column=10, sys_path=sys_path).goto_definitions()
|
||||
assert implicit_pkg.type == 'module'
|
||||
assert implicit_pkg.module_path is None
|
||||
|
||||
|
||||
def test_implicit_namespace_package_import_autocomplete(Script):
|
||||
CODE = 'from implicit_name'
|
||||
|
||||
sys_path = [dirname(__file__)]
|
||||
|
||||
script = Script(sys_path=sys_path, source=CODE)
|
||||
compl = script.completions()
|
||||
assert [c.name for c in compl] == ['implicit_namespace_package']
|
||||
|
||||
|
||||
def test_namespace_package_in_multiple_directories_autocompletion(Script):
|
||||
CODE = 'from pkg.'
|
||||
sys_path = [join(dirname(__file__), d)
|
||||
for d in ['implicit_namespace_package/ns1', 'implicit_namespace_package/ns2']]
|
||||
|
||||
script = Script(sys_path=sys_path, source=CODE)
|
||||
compl = script.completions()
|
||||
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'
|
||||
sys_path = [join(dirname(__file__), d)
|
||||
for d in ['implicit_namespace_package/ns1', 'implicit_namespace_package/ns2']]
|
||||
script = Script(sys_path=sys_path, source=CODE)
|
||||
result = script.goto_definitions()
|
||||
assert len(result) == 1
|
||||
|
||||
|
||||
def test_namespace_name_autocompletion_full_name(Script):
|
||||
CODE = 'from pk'
|
||||
sys_path = [join(dirname(__file__), d)
|
||||
for d in ['implicit_namespace_package/ns1', 'implicit_namespace_package/ns2']]
|
||||
|
||||
script = Script(sys_path=sys_path, source=CODE)
|
||||
compl = script.completions()
|
||||
assert set(c.full_name for c in compl) == set(['pkg'])
|
||||
477
test/test_inference/test_imports.py
Normal file
477
test/test_inference/test_imports.py
Normal file
@@ -0,0 +1,477 @@
|
||||
"""
|
||||
Tests of various import related things that could not be tested with "Black Box
|
||||
Tests".
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
import pytest
|
||||
from jedi.file_io import FileIO, KnownContentFileIO
|
||||
|
||||
from jedi._compatibility import find_module_py33, find_module
|
||||
from jedi.evaluate import compiled
|
||||
from jedi.evaluate import imports
|
||||
from jedi.api.project import Project
|
||||
from jedi.evaluate.gradual.conversion import _stub_to_python_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, False)
|
||||
with pytest.raises(ImportError):
|
||||
assert find_module_py33('_DOESNTEXIST_') == (None, None)
|
||||
|
||||
|
||||
def test_find_module_package():
|
||||
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_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):
|
||||
sys_path = environment.get_sys_path() + [pkg_zip_path]
|
||||
script = Script('import pkg; pkg.mod', sys_path=sys_path)
|
||||
assert len(script.completions()) == 1
|
||||
|
||||
file_io, is_package = evaluator.compiled_subprocess.get_module_info(
|
||||
sys_path=sys_path,
|
||||
string=u'pkg',
|
||||
full_name=u'pkg'
|
||||
)
|
||||
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
|
||||
|
||||
file_io, is_package = evaluator.compiled_subprocess.get_module_info(
|
||||
sys_path=sys_path,
|
||||
string=u'not_pkg',
|
||||
full_name=u'not_pkg'
|
||||
)
|
||||
assert file_io.path.endswith(os.path.join('not_pkg.zip', 'not_pkg.py'))
|
||||
assert is_package is False
|
||||
|
||||
|
||||
@cwd_at('test/test_inference/not_in_sys_path/pkg')
|
||||
def test_import_not_in_sys_path(Script):
|
||||
"""
|
||||
non-direct imports (not in sys.path)
|
||||
"""
|
||||
a = Script(path='module.py', line=5).goto_definitions()
|
||||
assert a[0].name == 'int'
|
||||
|
||||
a = Script(path='module.py', line=6).goto_definitions()
|
||||
assert a[0].name == 'str'
|
||||
a = Script(path='module.py', line=7).goto_definitions()
|
||||
assert a[0].name == 'str'
|
||||
|
||||
|
||||
@pytest.mark.parametrize("code,name", [
|
||||
("from flask.ext import foo; foo.", "Foo"), # flask_foo.py
|
||||
("from flask.ext import bar; bar.", "Bar"), # flaskext/bar.py
|
||||
("from flask.ext import baz; baz.", "Baz"), # flask_baz/__init__.py
|
||||
("from flask.ext import moo; moo.", "Moo"), # flaskext/moo/__init__.py
|
||||
("from flask.ext.", "foo"),
|
||||
("from flask.ext.", "bar"),
|
||||
("from flask.ext.", "baz"),
|
||||
("from flask.ext.", "moo"),
|
||||
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.
|
||||
"""
|
||||
path = os.path.join(os.path.dirname(__file__), 'flask-site-packages')
|
||||
completions = Script(code, sys_path=[path]).completions()
|
||||
assert name in [c.name for c in completions]
|
||||
|
||||
|
||||
@cwd_at('test/test_inference/')
|
||||
def test_not_importable_file(Script):
|
||||
src = 'import not_importable_file as x; x.'
|
||||
assert not Script(src, path='example.py').completions()
|
||||
|
||||
|
||||
def test_import_unique(Script):
|
||||
src = "import os; os.path"
|
||||
defs = Script(src, path='example.py').goto_definitions()
|
||||
parent_contexts = [d._name._context for d in defs]
|
||||
assert len(parent_contexts) == len(set(parent_contexts))
|
||||
|
||||
|
||||
def test_cache_works_with_sys_path_param(Script, tmpdir):
|
||||
foo_path = tmpdir.join('foo')
|
||||
bar_path = tmpdir.join('bar')
|
||||
foo_path.join('module.py').write('foo = 123', ensure=True)
|
||||
bar_path.join('module.py').write('bar = 123', ensure=True)
|
||||
foo_completions = Script('import module; module.',
|
||||
sys_path=[foo_path.strpath]).completions()
|
||||
bar_completions = Script('import module; module.',
|
||||
sys_path=[bar_path.strpath]).completions()
|
||||
assert 'foo' in [c.name for c in foo_completions]
|
||||
assert 'bar' not in [c.name for c in foo_completions]
|
||||
|
||||
assert 'bar' in [c.name for c in bar_completions]
|
||||
assert 'foo' not in [c.name for c in bar_completions]
|
||||
|
||||
|
||||
def test_import_completion_docstring(Script):
|
||||
import abc
|
||||
s = Script('"""test"""\nimport ab')
|
||||
abc_completions = [c for c in s.completions() if c.name == 'abc']
|
||||
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 abc_completions[0].docstring() == ''
|
||||
|
||||
|
||||
def test_goto_definition_on_import(Script):
|
||||
assert Script("import sys_blabla", 1, 8).goto_definitions() == []
|
||||
assert len(Script("import sys", 1, 8).goto_definitions()) == 1
|
||||
|
||||
|
||||
@cwd_at('jedi')
|
||||
def test_complete_on_empty_import(Script):
|
||||
assert Script("from datetime import").completions()[0].name == 'import'
|
||||
# should just list the files in the directory
|
||||
assert 10 < len(Script("from .", path='whatever.py').completions()) < 30
|
||||
|
||||
# Global import
|
||||
assert len(Script("from . import", 1, 5, 'whatever.py').completions()) > 30
|
||||
# relative import
|
||||
assert 10 < len(Script("from . import", 1, 6, 'whatever.py').completions()) < 30
|
||||
|
||||
# Global import
|
||||
assert len(Script("from . import classes", 1, 5, 'whatever.py').completions()) > 30
|
||||
# relative import
|
||||
assert 10 < len(Script("from . import classes", 1, 6, 'whatever.py').completions()) < 30
|
||||
|
||||
wanted = {'ImportError', 'import', 'ImportWarning'}
|
||||
assert {c.name for c in Script("import").completions()} == wanted
|
||||
assert len(Script("import import", path='').completions()) > 0
|
||||
|
||||
# 111
|
||||
assert Script("from datetime import").completions()[0].name == 'import'
|
||||
assert Script("from datetime import ").completions()
|
||||
|
||||
|
||||
def test_imports_on_global_namespace_without_path(Script):
|
||||
"""If the path is None, there shouldn't be any import problem"""
|
||||
completions = Script("import operator").completions()
|
||||
assert [c.name for c in completions] == ['operator']
|
||||
completions = Script("import operator", path='example.py').completions()
|
||||
assert [c.name for c in completions] == ['operator']
|
||||
|
||||
# the first one has a path the second doesn't
|
||||
completions = Script("import keyword", path='example.py').completions()
|
||||
assert [c.name for c in completions] == ['keyword']
|
||||
completions = Script("import keyword").completions()
|
||||
assert [c.name for c in completions] == ['keyword']
|
||||
|
||||
|
||||
def test_named_import(Script):
|
||||
"""named import - jedi-vim issue #8"""
|
||||
s = "import time as dt"
|
||||
assert len(Script(s, 1, 15, '/').goto_definitions()) == 1
|
||||
assert len(Script(s, 1, 10, '/').goto_definitions()) == 1
|
||||
|
||||
|
||||
@pytest.mark.skipif('True', reason='The nested import stuff is still very messy.')
|
||||
def test_goto_following_on_imports(Script):
|
||||
s = "import multiprocessing.dummy; multiprocessing.dummy"
|
||||
g = Script(s).goto_assignments()
|
||||
assert len(g) == 1
|
||||
assert (g[0].line, g[0].column) != (0, 0)
|
||||
|
||||
|
||||
def test_goto_assignments(Script):
|
||||
sys, = Script("import sys", 1, 10).goto_assignments(follow_imports=True)
|
||||
assert sys.type == 'module'
|
||||
|
||||
|
||||
def test_os_after_from(Script):
|
||||
def check(source, result, column=None):
|
||||
completions = Script(source, column=column).completions()
|
||||
assert [c.name for c in completions] == result
|
||||
|
||||
check('\nfrom os. ', ['path'])
|
||||
check('\nfrom os ', ['import'])
|
||||
check('from os ', ['import'])
|
||||
check('\nfrom os import whatever', ['import'], len('from os im'))
|
||||
|
||||
check('from os\\\n', ['import'])
|
||||
check('from os \\\n', ['import'])
|
||||
|
||||
|
||||
def test_os_issues(Script):
|
||||
def import_names(*args, **kwargs):
|
||||
return [d.name for d in Script(*args, **kwargs).completions()]
|
||||
|
||||
# Github issue #759
|
||||
s = 'import os, s'
|
||||
assert 'sys' in import_names(s)
|
||||
assert 'path' not in import_names(s, column=len(s) - 1)
|
||||
assert 'os' in import_names(s, column=len(s) - 3)
|
||||
|
||||
# Some more checks
|
||||
s = 'from os import path, e'
|
||||
assert 'environ' in import_names(s)
|
||||
assert 'json' not in import_names(s, column=len(s) - 1)
|
||||
assert 'environ' in import_names(s, column=len(s) - 1)
|
||||
assert 'path' in import_names(s, column=len(s) - 3)
|
||||
|
||||
|
||||
def test_path_issues(Script):
|
||||
"""
|
||||
See pull request #684 for details.
|
||||
"""
|
||||
source = '''from datetime import '''
|
||||
assert Script(source).completions()
|
||||
|
||||
|
||||
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)
|
||||
def_, = script.goto_definitions()
|
||||
assert def_.type == 'module'
|
||||
context, = def_._name.infer()
|
||||
assert not _stub_to_python_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', '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(evaluator, path, base_names, is_package, names):
|
||||
file_io = KnownContentFileIO(path, '')
|
||||
m = imports._load_module_from_path(evaluator, 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))
|
||||
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
|
||||
|
||||
|
||||
def test_import_with_semicolon(Script):
|
||||
names = [c.name for c in Script('xzy; from abc import ').completions()]
|
||||
assert 'ABCMeta' in names
|
||||
assert 'abc' not in names
|
||||
|
||||
|
||||
def test_relative_import_star(Script):
|
||||
# Coming from github #1235
|
||||
import jedi
|
||||
|
||||
source = """
|
||||
from . import *
|
||||
furl.c
|
||||
"""
|
||||
script = jedi.Script(source, 3, len("furl.c"), 'export.py')
|
||||
|
||||
assert script.completions()
|
||||
46
test/test_inference/test_literals.py
Normal file
46
test/test_inference/test_literals.py
Normal file
@@ -0,0 +1,46 @@
|
||||
import pytest
|
||||
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, TreeInstance)
|
||||
return ''
|
||||
else:
|
||||
return def_._name._context.get_safe_value()
|
||||
|
||||
|
||||
def test_f_strings(Script, environment):
|
||||
"""
|
||||
f literals are not really supported in Jedi. They just get ignored and an
|
||||
empty string is returned.
|
||||
"""
|
||||
if environment.version_info < (3, 6):
|
||||
pytest.skip()
|
||||
|
||||
assert _eval_literal(Script, 'f"asdf"', is_fstring=True) == ''
|
||||
assert _eval_literal(Script, 'f"{asdf} "', is_fstring=True) == ''
|
||||
assert _eval_literal(Script, 'F"{asdf} "', is_fstring=True) == ''
|
||||
assert _eval_literal(Script, 'rF"{asdf} "', is_fstring=True) == ''
|
||||
|
||||
|
||||
def test_rb_strings(Script, environment):
|
||||
assert _eval_literal(Script, 'br"asdf"') == b'asdf'
|
||||
obj = _eval_literal(Script, 'rb"asdf"')
|
||||
|
||||
# rb is not valid in Python 2. Due to error recovery we just get a
|
||||
# string.
|
||||
assert obj == b'asdf'
|
||||
|
||||
|
||||
def test_thousand_separators(Script, environment):
|
||||
if environment.version_info < (3, 6):
|
||||
pytest.skip()
|
||||
|
||||
assert _eval_literal(Script, '1_2_3') == 123
|
||||
assert _eval_literal(Script, '123_456_789') == 123456789
|
||||
assert _eval_literal(Script, '0x3_4') == 52
|
||||
assert _eval_literal(Script, '0b1_0') == 2
|
||||
assert _eval_literal(Script, '0o1_0') == 8
|
||||
7
test/test_inference/test_mixed.py
Normal file
7
test/test_inference/test_mixed.py
Normal file
@@ -0,0 +1,7 @@
|
||||
import jedi
|
||||
|
||||
|
||||
def test_on_code():
|
||||
from functools import wraps
|
||||
i = jedi.Interpreter("wraps.__code__", [{'wraps':wraps}])
|
||||
assert i.goto_definitions()
|
||||
96
test/test_inference/test_namespace_package.py
Normal file
96
test/test_inference/test_namespace_package.py
Normal file
@@ -0,0 +1,96 @@
|
||||
from os.path import dirname, join
|
||||
|
||||
import pytest
|
||||
import py
|
||||
|
||||
from ..helpers import get_example_dir
|
||||
|
||||
|
||||
SYS_PATH = [join(dirname(__file__), d)
|
||||
for d in ['namespace_package/ns1', 'namespace_package/ns2']]
|
||||
|
||||
|
||||
def script_with_path(Script, *args, **kwargs):
|
||||
return Script(sys_path=SYS_PATH, *args, **kwargs)
|
||||
|
||||
|
||||
def test_goto_definition(Script):
|
||||
assert script_with_path(Script, 'from pkg import ns1_file').goto_definitions()
|
||||
assert script_with_path(Script, 'from pkg import ns2_file').goto_definitions()
|
||||
assert not script_with_path(Script, 'from pkg import ns3_file').goto_definitions()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
('source', 'solution'), [
|
||||
('from pkg.ns2_folder.nested import foo', 'nested!'),
|
||||
('from pkg.ns2_folder import foo', 'ns2_folder!'),
|
||||
('from pkg.ns2_file import foo', 'ns2_file!'),
|
||||
('from pkg.ns1_folder import foo', 'ns1_folder!'),
|
||||
('from pkg.ns1_file import foo', 'ns1_file!'),
|
||||
('from pkg import foo', 'ns1!'),
|
||||
]
|
||||
)
|
||||
def test_goto_assignment(Script, source, solution):
|
||||
ass = script_with_path(Script, source).goto_assignments()
|
||||
assert len(ass) == 1
|
||||
assert ass[0].description == "foo = '%s'" % solution
|
||||
|
||||
|
||||
def test_simple_completions(Script):
|
||||
# completion
|
||||
completions = script_with_path(Script, 'from pkg import ').completions()
|
||||
names = [str(c.name) for c in completions] # str because of unicode
|
||||
compare = ['foo', 'ns1_file', 'ns1_folder', 'ns2_folder', 'ns2_file',
|
||||
'pkg_resources', 'pkgutil', '__name__', '__path__',
|
||||
'__package__', '__file__', '__doc__']
|
||||
# must at least contain these items, other items are not important
|
||||
assert set(compare) == set(names)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
('source', 'solution'), [
|
||||
('from pkg import ns2_folder as x', 'ns2_folder!'),
|
||||
('from pkg import ns2_file as x', 'ns2_file!'),
|
||||
('from pkg.ns2_folder import nested as x', 'nested!'),
|
||||
('from pkg import ns1_folder as x', 'ns1_folder!'),
|
||||
('from pkg import ns1_file as x', 'ns1_file!'),
|
||||
('import pkg as x', 'ns1!'),
|
||||
]
|
||||
)
|
||||
def test_completions(Script, source, solution):
|
||||
for c in script_with_path(Script, source + '; x.').completions():
|
||||
if c.name == 'foo':
|
||||
completion = c
|
||||
solution = "foo = '%s'" % solution
|
||||
assert completion.description == solution
|
||||
|
||||
|
||||
def test_nested_namespace_package(Script):
|
||||
code = 'from nested_namespaces.namespace.pkg import CONST'
|
||||
|
||||
sys_path = [dirname(__file__)]
|
||||
|
||||
script = Script(sys_path=sys_path, source=code, line=1, column=45)
|
||||
|
||||
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'
|
||||
18
test/test_inference/test_precedence.py
Normal file
18
test/test_inference/test_precedence.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from jedi.evaluate.compiled import CompiledObject
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.parametrize('source', [
|
||||
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:
|
||||
pytest.skip("Ellipsis does not exists in 2")
|
||||
script = Script(source)
|
||||
node = script._module_node.children[0]
|
||||
first, = script._get_module().eval_node(node)
|
||||
assert isinstance(first, CompiledObject) and first.get_safe_value() is True
|
||||
73
test/test_inference/test_pyc.py
Normal file
73
test/test_inference/test_pyc.py
Normal file
@@ -0,0 +1,73 @@
|
||||
"""
|
||||
Test completions from *.pyc files:
|
||||
|
||||
- generate a dummy python module
|
||||
- compile the dummy module to generate a *.pyc
|
||||
- delete the pure python dummy module
|
||||
- try jedi on the generated *.pyc
|
||||
"""
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
import jedi
|
||||
from jedi.api.environment import SameEnvironment, InterpreterEnvironment
|
||||
|
||||
|
||||
SRC = """class Foo:
|
||||
pass
|
||||
|
||||
class Bar:
|
||||
pass
|
||||
"""
|
||||
|
||||
|
||||
@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
|
||||
|
||||
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_path)
|
||||
os.remove(dummy_path)
|
||||
|
||||
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
|
||||
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_path, dst)
|
||||
shutil.copy(os.path.join(pycache, f), dst)
|
||||
try:
|
||||
yield path
|
||||
finally:
|
||||
shutil.rmtree(path)
|
||||
|
||||
|
||||
def test_pyc(pyc_project_path, environment):
|
||||
"""
|
||||
The list of completion must be greater than 2.
|
||||
"""
|
||||
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
|
||||
34
test/test_inference/test_representation.py
Normal file
34
test/test_inference/test_representation.py
Normal file
@@ -0,0 +1,34 @@
|
||||
from textwrap import dedent
|
||||
|
||||
|
||||
def get_definition_and_evaluator(Script, source):
|
||||
first, = Script(dedent(source)).goto_definitions()
|
||||
return first._name._context, first._evaluator
|
||||
|
||||
|
||||
def test_function_execution(Script):
|
||||
"""
|
||||
We've been having an issue of a mutable list that was changed inside the
|
||||
function execution. Test if an execution always returns the same result.
|
||||
"""
|
||||
|
||||
s = """
|
||||
def x():
|
||||
return str()
|
||||
x"""
|
||||
func, evaluator = get_definition_and_evaluator(Script, s)
|
||||
# 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_with_values()) == 1
|
||||
assert len(func.execute_with_values()) == 1
|
||||
|
||||
|
||||
def test_class_mro(Script):
|
||||
s = """
|
||||
class X(object):
|
||||
pass
|
||||
X"""
|
||||
cls, evaluator = get_definition_and_evaluator(Script, s)
|
||||
mro = cls.py__mro__()
|
||||
assert [c.name.string_name for c in mro] == ['X', 'object']
|
||||
268
test/test_inference/test_signature.py
Normal file
268
test/test_inference/test_signature.py
Normal file
@@ -0,0 +1,268 @@
|
||||
from textwrap import dedent
|
||||
from operator import ge, lt
|
||||
import re
|
||||
|
||||
import pytest
|
||||
|
||||
from jedi.evaluate.gradual.conversion import _stub_to_python_context_set
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'code, sig, names, op, version', [
|
||||
('import math; math.cos', 'cos(x, /)', ['x'], ge, (2, 7)),
|
||||
|
||||
('next', 'next(iterator, default=None, /)', ['iterator', 'default'], ge, (2, 7)),
|
||||
|
||||
('str', "str(object='', /) -> str", ['object'], ge, (2, 7)),
|
||||
|
||||
('pow', 'pow(x, y, z=None, /) -> number', ['x', 'y', 'z'], lt, (3, 5)),
|
||||
('pow', 'pow(x, y, z=None, /)', ['x', 'y', 'z'], ge, (3, 5)),
|
||||
|
||||
('bytes.partition', 'partition(self, sep, /) -> (head, sep, tail)', ['self', 'sep'], lt, (3, 5)),
|
||||
('bytes.partition', 'partition(self, sep, /)', ['self', 'sep'], ge, (3, 5)),
|
||||
|
||||
('bytes().partition', 'partition(sep, /) -> (head, sep, tail)', ['sep'], lt, (3, 5)),
|
||||
('bytes().partition', 'partition(sep, /)', ['sep'], ge, (3, 5)),
|
||||
]
|
||||
)
|
||||
def test_compiled_signature(Script, environment, code, sig, names, op, version):
|
||||
if not op(environment.version_info, version):
|
||||
return # The test right next to it should take over.
|
||||
|
||||
d, = Script(code).goto_definitions()
|
||||
context, = d._name.infer()
|
||||
compiled, = _stub_to_python_context_set(context)
|
||||
signature, = compiled.get_signatures()
|
||||
assert signature.to_string() == sig
|
||||
assert [n.string_name for n in signature.get_param_names()] == names
|
||||
|
||||
|
||||
classmethod_code = '''
|
||||
class X:
|
||||
@classmethod
|
||||
def x(cls, a, b):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def static(a, b):
|
||||
pass
|
||||
'''
|
||||
|
||||
|
||||
partial_code = '''
|
||||
import functools
|
||||
|
||||
def func(a, b, c):
|
||||
pass
|
||||
|
||||
a = functools.partial(func)
|
||||
b = functools.partial(func, 1)
|
||||
c = functools.partial(func, 1, c=2)
|
||||
d = functools.partial()
|
||||
'''
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'code, expected', [
|
||||
('def f(a, * args, x): pass\n f(', 'f(a, *args, x)'),
|
||||
('def f(a, *, x): pass\n f(', 'f(a, *, x)'),
|
||||
('def f(*, x= 3,**kwargs): pass\n f(', 'f(*, x=3, **kwargs)'),
|
||||
('def f(x,/,y,* ,z): pass\n f(', 'f(x, /, y, *, z)'),
|
||||
('def f(a, /, *, x=3, **kwargs): pass\n f(', 'f(a, /, *, x=3, **kwargs)'),
|
||||
|
||||
(classmethod_code + 'X.x(', 'x(cls, a, b)'),
|
||||
(classmethod_code + 'X().x(', 'x(cls, a, b)'),
|
||||
(classmethod_code + 'X.static(', 'static(a, b)'),
|
||||
(classmethod_code + 'X().static(', 'static(a, b)'),
|
||||
|
||||
(partial_code + 'a(', 'func(a, b, c)'),
|
||||
(partial_code + 'b(', 'func(b, c)'),
|
||||
(partial_code + 'c(', 'func(b)'),
|
||||
(partial_code + 'd(', None),
|
||||
]
|
||||
)
|
||||
def test_tree_signature(Script, environment, code, expected):
|
||||
# Only test this in the latest version, because of /
|
||||
if environment.version_info < (3, 8):
|
||||
pytest.skip()
|
||||
|
||||
if expected is None:
|
||||
assert not Script(code).call_signatures()
|
||||
else:
|
||||
sig, = Script(code).call_signatures()
|
||||
assert expected == sig.to_string()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'combination, expected', [
|
||||
# Functions
|
||||
('full_redirect(simple)', 'b, *, c'),
|
||||
('full_redirect(simple4)', 'b, x: int'),
|
||||
('full_redirect(a)', 'b, *args'),
|
||||
('full_redirect(kw)', 'b, *, c, **kwargs'),
|
||||
('full_redirect(akw)', 'c, *args, **kwargs'),
|
||||
|
||||
# Non functions
|
||||
('full_redirect(lambda x, y: ...)', 'y'),
|
||||
('full_redirect()', '*args, **kwargs'),
|
||||
('full_redirect(1)', '*args, **kwargs'),
|
||||
|
||||
# Classes / inheritance
|
||||
('full_redirect(C)', 'z, *, c'),
|
||||
('full_redirect(C())', 'y'),
|
||||
('D', 'D(a, z, /)'),
|
||||
('D()', 'D(x, y)'),
|
||||
('D().foo', 'foo(a, *, bar, z, **kwargs)'),
|
||||
|
||||
# Merging
|
||||
('two_redirects(simple, simple)', 'a, b, *, c'),
|
||||
('two_redirects(simple2, simple2)', 'x'),
|
||||
('two_redirects(akw, kw)', 'a, c, *args, **kwargs'),
|
||||
('two_redirects(kw, akw)', 'a, b, *args, c, **kwargs'),
|
||||
|
||||
('combined_redirect(simple, simple2)', 'a, b, /, *, x'),
|
||||
('combined_redirect(simple, simple3)', 'a, b, /, *, a, x: int'),
|
||||
('combined_redirect(simple2, simple)', 'x, /, *, a, b, c'),
|
||||
('combined_redirect(simple3, simple)', 'a, x: int, /, *, a, b, c'),
|
||||
|
||||
('combined_redirect(simple, kw)', 'a, b, /, *, a, b, c, **kwargs'),
|
||||
('combined_redirect(kw, simple)', 'a, b, /, *, a, b, c'),
|
||||
|
||||
('combined_lot_of_args(kw, simple4)', '*, b'),
|
||||
('combined_lot_of_args(simple4, kw)', '*, b, c, **kwargs'),
|
||||
|
||||
('combined_redirect(combined_redirect(simple2, simple4), combined_redirect(kw, simple5))',
|
||||
'x, /, *, y'),
|
||||
('combined_redirect(combined_redirect(simple4, simple2), combined_redirect(simple5, kw))',
|
||||
'a, b, x: int, /, *, a, b, c, **kwargs'),
|
||||
('combined_redirect(combined_redirect(a, kw), combined_redirect(kw, simple5))',
|
||||
'a, b, /, *args, y'),
|
||||
|
||||
('no_redirect(kw)', '*args, **kwargs'),
|
||||
('no_redirect(akw)', '*args, **kwargs'),
|
||||
('no_redirect(simple)', '*args, **kwargs'),
|
||||
]
|
||||
)
|
||||
def test_nested_signatures(Script, environment, combination, expected, skip_pre_python35):
|
||||
code = dedent('''
|
||||
def simple(a, b, *, c): ...
|
||||
def simple2(x): ...
|
||||
def simple3(a, x: int): ...
|
||||
def simple4(a, b, x: int): ...
|
||||
def simple5(y): ...
|
||||
def a(a, b, *args): ...
|
||||
def kw(a, b, *, c, **kwargs): ...
|
||||
def akw(a, c, *args, **kwargs): ...
|
||||
|
||||
def no_redirect(func):
|
||||
return lambda *args, **kwargs: func(1)
|
||||
def full_redirect(func):
|
||||
return lambda *args, **kwargs: func(1, *args, **kwargs)
|
||||
def two_redirects(func1, func2):
|
||||
return lambda *args, **kwargs: func1(*args, **kwargs) + func2(1, *args, **kwargs)
|
||||
def combined_redirect(func1, func2):
|
||||
return lambda *args, **kwargs: func1(*args) + func2(**kwargs)
|
||||
def combined_lot_of_args(func1, func2):
|
||||
return lambda *args, **kwargs: func1(1, 2, 3, 4, *args) + func2(a=3, x=1, y=1, **kwargs)
|
||||
|
||||
class C:
|
||||
def __init__(self, a, z, *, c): ...
|
||||
def __call__(self, x, y): ...
|
||||
|
||||
def foo(self, bar, z, **kwargs): ...
|
||||
|
||||
class D(C):
|
||||
def __init__(self, *args):
|
||||
super().__init__(*args)
|
||||
|
||||
def foo(self, a, **kwargs):
|
||||
super().foo(**kwargs)
|
||||
''')
|
||||
code += 'z = ' + combination + '\nz('
|
||||
sig, = Script(code).call_signatures()
|
||||
computed = sig.to_string()
|
||||
if not re.match(r'\w+\(', expected):
|
||||
expected = '<lambda>(' + expected + ')'
|
||||
assert expected == computed
|
||||
|
||||
|
||||
def test_pow_signature(Script):
|
||||
# See github #1357
|
||||
sigs = Script('pow(').call_signatures()
|
||||
strings = {sig.to_string() for sig in sigs}
|
||||
assert strings == {'pow(x: float, y: float, z: float, /) -> float',
|
||||
'pow(x: float, y: float, /) -> float',
|
||||
'pow(x: int, y: int, z: int, /) -> Any',
|
||||
'pow(x: int, y: int, /) -> Any'}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'code, signature', [
|
||||
[dedent('''
|
||||
import functools
|
||||
def f(x):
|
||||
pass
|
||||
def x(f):
|
||||
@functools.wraps(f)
|
||||
def wrapper(*args):
|
||||
# Have no arguments here, but because of wraps, the signature
|
||||
# should still be f's.
|
||||
return f(*args)
|
||||
return wrapper
|
||||
|
||||
x(f)('''), 'f(x, /)'],
|
||||
[dedent('''
|
||||
import functools
|
||||
def f(x):
|
||||
pass
|
||||
def x(f):
|
||||
@functools.wraps(f)
|
||||
def wrapper():
|
||||
# Have no arguments here, but because of wraps, the signature
|
||||
# should still be f's.
|
||||
return 1
|
||||
return wrapper
|
||||
|
||||
x(f)('''), 'f()'],
|
||||
]
|
||||
)
|
||||
def test_wraps_signature(Script, code, signature, skip_pre_python35):
|
||||
sigs = Script(code).call_signatures()
|
||||
assert {sig.to_string() for sig in sigs} == {signature}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'start, start_params', [
|
||||
['@dataclass\nclass X:', []],
|
||||
['@dataclass(eq=True)\nclass X:', []],
|
||||
[dedent('''
|
||||
class Y():
|
||||
y: int
|
||||
@dataclass
|
||||
class X(Y):'''), []],
|
||||
[dedent('''
|
||||
@dataclass
|
||||
class Y():
|
||||
y: int
|
||||
z = 5
|
||||
@dataclass
|
||||
class X(Y):'''), ['y']],
|
||||
]
|
||||
)
|
||||
def test_dataclass_signature(Script, skip_pre_python37, start, start_params):
|
||||
code = dedent('''
|
||||
name: str
|
||||
foo = 3
|
||||
price: float
|
||||
quantity: int = 0.0
|
||||
|
||||
X(''')
|
||||
|
||||
code = 'from dataclasses import dataclass\n' + start + code
|
||||
|
||||
sig, = Script(code).call_signatures()
|
||||
assert [p.name for p in sig.params] == start_params + ['name', 'price', 'quantity']
|
||||
quantity, = sig.params[-1].infer()
|
||||
assert quantity.name == 'int'
|
||||
price, = sig.params[-2].infer()
|
||||
assert price.name == 'float'
|
||||
103
test/test_inference/test_stdlib.py
Normal file
103
test/test_inference/test_stdlib.py
Normal file
@@ -0,0 +1,103 @@
|
||||
"""
|
||||
Tests of various stdlib related things that could not be tested
|
||||
with "Black Box Tests".
|
||||
"""
|
||||
from textwrap import dedent
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.parametrize(['letter', 'expected'], [
|
||||
('n', ['name']),
|
||||
('s', ['smart']),
|
||||
])
|
||||
def test_namedtuple_str(letter, expected, Script):
|
||||
source = dedent("""\
|
||||
import collections
|
||||
Person = collections.namedtuple('Person', 'name smart')
|
||||
dave = Person('Dave', False)
|
||||
dave.%s""") % letter
|
||||
result = Script(source).completions()
|
||||
completions = set(r.name for r in result)
|
||||
assert completions == set(expected)
|
||||
|
||||
|
||||
def test_namedtuple_list(Script):
|
||||
source = dedent("""\
|
||||
import collections
|
||||
Cat = collections.namedtuple('Person', ['legs', u'length', 'large'])
|
||||
garfield = Cat(4, '85cm', True)
|
||||
garfield.l""")
|
||||
result = Script(source).completions()
|
||||
completions = set(r.name for r in result)
|
||||
assert completions == {'legs', 'length', 'large'}
|
||||
|
||||
|
||||
def test_namedtuple_content(Script):
|
||||
source = dedent("""\
|
||||
import collections
|
||||
Foo = collections.namedtuple('Foo', ['bar', 'baz'])
|
||||
named = Foo(baz=4, bar=3.0)
|
||||
unnamed = Foo(4, '')
|
||||
""")
|
||||
|
||||
def d(source):
|
||||
x, = Script(source).goto_definitions()
|
||||
return x.name
|
||||
|
||||
assert d(source + 'unnamed.bar') == 'int'
|
||||
assert d(source + 'unnamed.baz') == 'str'
|
||||
assert d(source + 'named.bar') == 'float'
|
||||
assert d(source + 'named.baz') == 'int'
|
||||
|
||||
|
||||
def test_nested_namedtuples(Script):
|
||||
"""
|
||||
From issue #730.
|
||||
"""
|
||||
s = Script(dedent('''
|
||||
import collections
|
||||
Dataset = collections.namedtuple('Dataset', ['data'])
|
||||
Datasets = collections.namedtuple('Datasets', ['train'])
|
||||
train_x = Datasets(train=Dataset('data_value'))
|
||||
train_x.train.'''
|
||||
))
|
||||
assert 'data' in [c.name for c in s.completions()]
|
||||
|
||||
|
||||
def test_namedtuple_goto_definitions(Script):
|
||||
source = dedent("""
|
||||
from collections import namedtuple
|
||||
|
||||
Foo = namedtuple('Foo', 'id timestamp gps_timestamp attributes')
|
||||
Foo""")
|
||||
|
||||
from jedi.api import Script
|
||||
|
||||
d1, = Script(source).goto_definitions()
|
||||
|
||||
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'}
|
||||
else:
|
||||
assert names == {'str'}
|
||||
|
||||
# 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'}
|
||||
110
test/test_inference/test_sys_path.py
Normal file
110
test/test_inference/test_sys_path.py
Normal file
@@ -0,0 +1,110 @@
|
||||
import os
|
||||
from glob import glob
|
||||
import sys
|
||||
import shutil
|
||||
|
||||
import pytest
|
||||
from ..helpers import skip_if_windows, skip_if_not_windows
|
||||
|
||||
from jedi.evaluate import sys_path
|
||||
from jedi.api.environment import create_environment
|
||||
|
||||
|
||||
def test_paths_from_assignment(Script):
|
||||
def paths(src):
|
||||
script = Script(src, path='/foo/bar.py')
|
||||
expr_stmt = script._module_node.children[0]
|
||||
return set(sys_path._paths_from_assignment(script._get_module(), expr_stmt))
|
||||
|
||||
# Normalize paths for Windows.
|
||||
path_a = os.path.abspath('/foo/a')
|
||||
path_b = os.path.abspath('/foo/b')
|
||||
path_c = os.path.abspath('/foo/c')
|
||||
|
||||
assert paths('sys.path[0:0] = ["a"]') == {path_a}
|
||||
assert paths('sys.path = ["b", 1, x + 3, y, "c"]') == {path_b, path_c}
|
||||
assert paths('sys.path = a = ["a"]') == {path_a}
|
||||
|
||||
# Fail for complicated examples.
|
||||
assert paths('sys.path, other = ["a"], 2') == set()
|
||||
|
||||
|
||||
def test_venv_and_pths(venv_path):
|
||||
pjoin = os.path.join
|
||||
|
||||
CUR_DIR = os.path.dirname(__file__)
|
||||
site_pkg_path = pjoin(venv_path, 'lib')
|
||||
if os.name == 'nt':
|
||||
site_pkg_path = pjoin(site_pkg_path, 'site-packages')
|
||||
else:
|
||||
site_pkg_path = glob(pjoin(site_pkg_path, 'python*', 'site-packages'))[0]
|
||||
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 = [
|
||||
# For now disable egg-links. I have no idea how they work... ~ dave
|
||||
#pjoin('/path', 'from', 'egg-link'),
|
||||
#pjoin(site_pkg_path, '.', 'relative', 'egg-link', 'path'),
|
||||
site_pkg_path,
|
||||
pjoin(site_pkg_path, 'dir-from-foo-pth'),
|
||||
'/foo/smth.py:module',
|
||||
# Not sure why it's added twice. It has to do with site.py which is not
|
||||
# something we can change. However this obviously also doesn't matter.
|
||||
'/foo/smth.py:from_func',
|
||||
'/foo/smth.py:from_func',
|
||||
]
|
||||
|
||||
# Ensure that pth and egg-link paths were added.
|
||||
assert venv_paths[-len(ETALON):] == ETALON
|
||||
|
||||
# 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),
|
||||
|
||||
skip_if_windows(['/foo'], '/foo/bar.so', ('bar',), False),
|
||||
skip_if_windows(['/foo'], '/foo/bar/__init__.so', ('bar',), True),
|
||||
skip_if_not_windows(['/foo'], '/foo/bar.pyd', ('bar',), False),
|
||||
skip_if_not_windows(['/foo'], '/foo/bar/__init__.pyd', ('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)
|
||||
BIN
test/test_inference/zipped_imports/not_pkg.zip
Normal file
BIN
test/test_inference/zipped_imports/not_pkg.zip
Normal file
Binary file not shown.
BIN
test/test_inference/zipped_imports/pkg.zip
Normal file
BIN
test/test_inference/zipped_imports/pkg.zip
Normal file
Binary file not shown.
Reference in New Issue
Block a user