Use the Script fixture more generally

This commit is contained in:
Dave Halter
2017-12-29 18:40:17 +01:00
parent 38cacba385
commit da211aa63d
10 changed files with 388 additions and 341 deletions

View File

@@ -378,7 +378,7 @@ class Interpreter(Script):
def names(source=None, path=None, encoding='utf-8', all_scopes=False, def names(source=None, path=None, encoding='utf-8', all_scopes=False,
definitions=True, references=False): definitions=True, references=False, environment=None):
""" """
Returns a list of `Definition` objects, containing name parts. Returns a list of `Definition` objects, containing name parts.
This means you can call ``Definition.goto_assignments()`` and get the This means you can call ``Definition.goto_assignments()`` and get the
@@ -398,7 +398,7 @@ def names(source=None, path=None, encoding='utf-8', all_scopes=False,
return definitions and is_def or references and not is_def return definitions and is_def or references and not is_def
# Set line/column to a random position, because they don't matter. # Set line/column to a random position, because they don't matter.
script = Script(source, line=1, column=0, path=path, encoding=encoding) script = Script(source, line=1, column=0, path=path, encoding=encoding, environment=environment)
module_context = script._get_module() module_context = script._get_module()
defs = [ defs = [
classes.Definition( classes.Definition(

View File

@@ -1,10 +1,9 @@
""" """
Test of keywords and ``jedi.keywords`` Test of keywords and ``jedi.keywords``
""" """
from jedi import Script
def test_issue436(): def test_issue436(Script):
code = "bar = 0\nbar += 'foo' + 4" code = "bar = 0\nbar += 'foo' + 4"
errors = set(repr(e) for e in Script(code)._analysis()) errors = set(repr(e) for e in Script(code)._analysis())
assert len(errors) == 2 assert len(errors) == 2

View File

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

View File

@@ -2,13 +2,14 @@ from textwrap import dedent
import inspect import inspect
import warnings import warnings
import pytest
from ..helpers import TestCase from ..helpers import TestCase
from jedi import Script
from jedi import cache from jedi import cache
from jedi._compatibility import is_py33, py_version from jedi._compatibility import is_py33
def assert_signature(source, expected_name, expected_index=0, line=None, column=None): def assert_signature(Script, source, expected_name, expected_index=0, line=None, column=None):
signatures = Script(source, line, column).call_signatures() signatures = Script(source, line, column).call_signatures()
assert len(signatures) <= 1 assert len(signatures) <= 1
@@ -22,12 +23,17 @@ def assert_signature(source, expected_name, expected_index=0, line=None, column=
return signatures[0] return signatures[0]
class TestCallSignatures(TestCase): def test_valid_call(Script):
def _run_simple(self, source, name, index=0, column=None, line=1): assert_signature(Script, 'str()', 'str', column=4)
assert_signature(source, name, index, line, column)
def test_valid_call(self):
assert_signature('str()', 'str', column=4) class TestCallSignatures(TestCase):
@pytest.fixture(autouse=True)
def init(self, Script):
self.Script = Script
def _run_simple(self, source, name, index=0, column=None, line=1):
assert_signature(self.Script, source, name, index, line, column)
def test_simple(self): def test_simple(self):
run = self._run_simple run = self._run_simple
@@ -89,170 +95,185 @@ class TestCallSignatures(TestCase):
self._run_simple("for sorted(", 'sorted', 0) self._run_simple("for sorted(", 'sorted', 0)
self._run_simple("for s in sorted(", 'sorted', 0) self._run_simple("for s in sorted(", 'sorted', 0)
def test_complex(self):
s = """
def abc(a,b):
pass
def a(self): def test_call_signatures_empty_parentheses_pre_space(Script):
abc( s = dedent("""\
def f(a, b):
pass
f( )""")
assert_signature(Script, s, 'f', 0, line=3, column=3)
if 1:
pass
"""
assert_signature(s, 'abc', 0, line=6, column=24)
s = """
import re
def huhu(it):
re.compile(
return it * 2
"""
assert_signature(s, 'compile', 0, line=4, column=31)
# jedi-vim #70 def test_multiple_signatures(Script):
s = """def foo(""" s = dedent("""\
assert Script(s).call_signatures() == [] if x:
# jedi-vim #116
s = """import itertools; test = getattr(itertools, 'chain'); test("""
assert_signature(s, 'chain', 0)
def test_call_signature_on_module(self):
"""github issue #240"""
s = 'import datetime; datetime('
# just don't throw an exception (if numpy doesn't exist, just ignore it)
assert Script(s).call_signatures() == []
def test_call_signatures_empty_parentheses_pre_space(self):
s = dedent("""\
def f(a, b): def f(a, b):
pass pass
f( )""") else:
assert_signature(s, 'f', 0, line=3, column=3) def f(a, b):
def test_multiple_signatures(self):
s = dedent("""\
if x:
def f(a, b):
pass
else:
def f(a, b):
pass
f(""")
assert len(Script(s).call_signatures()) == 2
def test_call_signatures_whitespace(self):
s = dedent("""\
abs(
def x():
pass pass
""") f(""")
assert_signature(s, 'abs', 0, line=1, column=5) assert len(Script(s).call_signatures()) == 2
def test_decorator_in_class(self):
def test_call_signatures_whitespace(Script):
s = dedent("""\
abs(
def x():
pass
""")
assert_signature(Script, s, 'abs', 0, line=1, column=5)
def test_decorator_in_class(Script):
"""
There's still an implicit param, with a decorator.
Github issue #319.
"""
s = dedent("""\
def static(func):
def wrapped(obj, *args):
return f(type(obj), *args)
return wrapped
class C(object):
@static
def test(cls):
return 10
C().test(""")
signatures = Script(s).call_signatures()
assert len(signatures) == 1
x = [p.description for p in signatures[0].params]
assert x == ['param *args']
def test_additional_brackets(Script):
assert_signature(Script, 'str((', 'str', 0)
def test_unterminated_strings(Script):
assert_signature(Script, 'str(";', 'str', 0)
def test_whitespace_before_bracket(Script):
assert_signature(Script, 'str (', 'str', 0)
assert_signature(Script, 'str (";', 'str', 0)
assert_signature(Script, 'str\n(', None)
def test_brackets_in_string_literals(Script):
assert_signature(Script, 'str (" (', 'str', 0)
assert_signature(Script, 'str (" )', 'str', 0)
def test_function_definitions_should_break(Script):
"""
Function definitions (and other tokens that cannot exist within call
signatures) should break and not be able to return a call signature.
"""
assert_signature(Script, 'str(\ndef x', 'str', 0)
assert not Script('str(\ndef x(): pass').call_signatures()
def test_flow_call(Script):
assert not Script('if (1').call_signatures()
def test_chained_calls(Script):
source = dedent('''
class B():
def test2(self, arg):
pass
class A():
def test1(self):
return B()
A().test1().test2(''')
assert_signature(Script, source, 'test2', 0)
def test_return(Script):
source = dedent('''
def foo():
return '.'.join()''')
assert_signature(Script, source, 'join', 0, column=len(" return '.'.join("))
def test_call_signature_on_module(Script):
"""github issue #240"""
s = 'import datetime; datetime('
# just don't throw an exception (if numpy doesn't exist, just ignore it)
assert Script(s).call_signatures() == []
def test_complex(Script):
s = """
def abc(a,b):
pass
def a(self):
abc(
if 1:
pass
""" """
There's still an implicit param, with a decorator. assert_signature(Script, s, 'abc', 0, line=6, column=20)
Github issue #319. s = """
import re
def huhu(it):
re.compile(
return it * 2
""" """
s = dedent("""\ assert_signature(Script, s, 'compile', 0, line=4, column=27)
def static(func):
def wrapped(obj, *args):
return f(type(obj), *args)
return wrapped
class C(object): # jedi-vim #70
@static s = """def foo("""
def test(cls): assert Script(s).call_signatures() == []
return 10
C().test(""") # jedi-vim #116
s = """import itertools; test = getattr(itertools, 'chain'); test("""
signatures = Script(s).call_signatures() assert_signature(Script, s, 'chain', 0)
assert len(signatures) == 1
x = [p.description for p in signatures[0].params]
assert x == ['param *args']
def test_additional_brackets(self):
assert_signature('str((', 'str', 0)
def test_unterminated_strings(self):
assert_signature('str(";', 'str', 0)
def test_whitespace_before_bracket(self):
assert_signature('str (', 'str', 0)
assert_signature('str (";', 'str', 0)
assert_signature('str\n(', None)
def test_brackets_in_string_literals(self):
assert_signature('str (" (', 'str', 0)
assert_signature('str (" )', 'str', 0)
def test_function_definitions_should_break(self):
"""
Function definitions (and other tokens that cannot exist within call
signatures) should break and not be able to return a call signature.
"""
assert_signature('str(\ndef x', 'str', 0)
assert not Script('str(\ndef x(): pass').call_signatures()
def test_flow_call(self):
assert not Script('if (1').call_signatures()
def test_chained_calls(self):
source = dedent('''
class B():
def test2(self, arg):
pass
class A():
def test1(self):
return B()
A().test1().test2(''')
assert_signature(source, 'test2', 0)
def test_return(self):
source = dedent('''
def foo():
return '.'.join()''')
assert_signature(source, 'join', 0, column=len(" return '.'.join("))
class TestParams(TestCase): def _params(Script, source, line=None, column=None):
def params(self, source, line=None, column=None): signatures = Script(source, line, column).call_signatures()
signatures = Script(source, line, column).call_signatures() assert len(signatures) == 1
assert len(signatures) == 1 return signatures[0].params
return signatures[0].params
def test_param_name(self):
if not is_py33:
p = self.params('''int(''')
# int is defined as: `int(x[, base])`
assert p[0].name == 'x'
# `int` docstring has been redefined:
# http://bugs.python.org/issue14783
# TODO have multiple call signatures for int (like in the docstr)
#assert p[1].name == 'base'
p = self.params('''open(something,''')
assert p[0].name in ['file', 'name']
assert p[1].name == 'mode'
def test_builtins(self):
"""
The self keyword should be visible even for builtins, if not
instantiated.
"""
p = self.params('str.endswith(')
assert p[0].name == 'self'
assert p[1].name == 'suffix'
p = self.params('str().endswith(')
assert p[0].name == 'suffix'
def test_signature_is_definition(): def test_param_name(Script):
if not is_py33:
p = _params(Script, '''int(''')
# int is defined as: `int(x[, base])`
assert p[0].name == 'x'
# `int` docstring has been redefined:
# http://bugs.python.org/issue14783
# TODO have multiple call signatures for int (like in the docstr)
#assert p[1].name == 'base'
p = _params(Script, '''open(something,''')
assert p[0].name in ['file', 'name']
assert p[1].name == 'mode'
def test_builtins(Script):
"""
The self keyword should be visible even for builtins, if not
instantiated.
"""
p = _params(Script, 'str.endswith(')
assert p[0].name == 'self'
assert p[1].name == 'suffix'
p = _params(Script, 'str().endswith(')
assert p[0].name == 'suffix'
def test_signature_is_definition(Script):
""" """
Through inheritance, a call signature is a sub class of Definition. Through inheritance, a call signature is a sub class of Definition.
Check if the attributes match. Check if the attributes match.
@@ -279,7 +300,7 @@ def test_signature_is_definition():
assert attribute == signature_attribute assert attribute == signature_attribute
def test_no_signature(): def test_no_signature(Script):
# str doesn't have a __call__ method # str doesn't have a __call__ method
assert Script('str()(').call_signatures() == [] assert Script('str()(').call_signatures() == []
@@ -292,7 +313,7 @@ def test_no_signature():
assert Script('').call_signatures() == [] assert Script('').call_signatures() == []
def test_dict_literal_in_incomplete_call(): def test_dict_literal_in_incomplete_call(Script):
source = """\ source = """\
import json import json
@@ -309,7 +330,7 @@ def test_dict_literal_in_incomplete_call():
assert script.call_signatures() assert script.call_signatures()
def test_completion_interference(): def test_completion_interference(Script):
"""Seems to cause problems, see also #396.""" """Seems to cause problems, see also #396."""
cache.parser_cache.pop(None, None) cache.parser_cache.pop(None, None)
assert Script('open(').call_signatures() assert Script('open(').call_signatures()
@@ -320,12 +341,12 @@ def test_completion_interference():
assert Script('open(').call_signatures() assert Script('open(').call_signatures()
def test_keyword_argument_index(): def test_keyword_argument_index(Script, environment):
def get(source, column=None): def get(source, column=None):
return Script(source, column=column).call_signatures()[0] return Script(source, column=column).call_signatures()[0]
# The signature of sorted changed from 2 to 3. # The signature of sorted changed from 2 to 3.
py2_offset = int(py_version < 30) py2_offset = int(environment.version_info.major == 2)
assert get('sorted([], key=a').index == 1 + py2_offset assert get('sorted([], key=a').index == 1 + py2_offset
assert get('sorted([], key=').index == 1 + py2_offset assert get('sorted([], key=').index == 1 + py2_offset
assert get('sorted([], no_key=a').index is None assert get('sorted([], no_key=a').index is None
@@ -354,7 +375,7 @@ def test_keyword_argument_index():
assert get(both + 'foo(a, b, c').index == 0 assert get(both + 'foo(a, b, c').index == 0
def test_bracket_start(): def test_bracket_start(Script):
def bracket_start(src): def bracket_start(src):
signatures = Script(src).call_signatures() signatures = Script(src).call_signatures()
assert len(signatures) == 1 assert len(signatures) == 1
@@ -363,20 +384,20 @@ def test_bracket_start():
assert bracket_start('str(') == (1, 3) assert bracket_start('str(') == (1, 3)
def test_different_caller(): def test_different_caller(Script):
""" """
It's possible to not use names, but another function result or an array It's possible to not use names, but another function result or an array
index and then get the call signature of it. index and then get the call signature of it.
""" """
assert_signature('[str][0](', 'str', 0) assert_signature(Script, '[str][0](', 'str', 0)
assert_signature('[str][0]()', 'str', 0, column=len('[str][0](')) assert_signature(Script, '[str][0]()', 'str', 0, column=len('[str][0]('))
assert_signature('(str)(', 'str', 0) assert_signature(Script, '(str)(', 'str', 0)
assert_signature('(str)()', 'str', 0, column=len('(str)(')) assert_signature(Script, '(str)()', 'str', 0, column=len('(str)('))
def test_in_function(): def test_in_function(Script):
code = dedent('''\ code = dedent('''\
class X(): class X():
@property @property
@@ -384,7 +405,7 @@ def test_in_function():
assert not Script(code).call_signatures() assert not Script(code).call_signatures()
def test_lambda_params(): def test_lambda_params(Script):
code = dedent('''\ code = dedent('''\
my_lambda = lambda x: x+1 my_lambda = lambda x: x+1
my_lambda(1)''') my_lambda(1)''')
@@ -394,7 +415,7 @@ def test_lambda_params():
assert [p.name for p in sig.params] == ['x'] assert [p.name for p in sig.params] == ['x']
def test_class_creation(): def test_class_creation(Script):
code = dedent('''\ code = dedent('''\
class X(): class X():
def __init__(self, foo, bar): def __init__(self, foo, bar):
@@ -411,7 +432,7 @@ def test_class_creation():
assert [p.name for p in sig.params] == ['foo', 'bar'] assert [p.name for p in sig.params] == ['foo', 'bar']
def test_call_magic_method(): def test_call_magic_method(Script):
code = dedent('''\ code = dedent('''\
class X(): class X():
def __call__(self, baz): def __call__(self, baz):

View File

@@ -6,19 +6,20 @@ from inspect import cleandoc
import pytest import pytest
from jedi import Script, __doc__ as jedi_doc, names import jedi
from jedi import __doc__ as jedi_doc, names
from ..helpers import cwd_at from ..helpers import cwd_at
from ..helpers import TestCase from ..helpers import TestCase
def test_is_keyword(): def test_is_keyword(Script):
#results = Script('import ', 1, 1, None).goto_definitions() #results = Script('import ', 1, 1, None).goto_definitions()
#assert len(results) == 1 and results[0].is_keyword is True #assert len(results) == 1 and results[0].is_keyword is True
results = Script('str', 1, 1, None).goto_definitions() results = Script('str', 1, 1, None).goto_definitions()
assert len(results) == 1 and results[0].is_keyword is False assert len(results) == 1 and results[0].is_keyword is False
def test_basedefinition_type(): def test_basedefinition_type(Script, environment):
def make_definitions(): def make_definitions():
""" """
Return a list of definitions for parametrized tests. Return a list of definitions for parametrized tests.
@@ -43,7 +44,7 @@ def test_basedefinition_type():
""") """)
definitions = [] definitions = []
definitions += names(source) definitions += names(source, environment=environment)
source += dedent(""" source += dedent("""
variable = sys or C or x or f or g or g() or h""") variable = sys or C or x or f or g or g() or h""")
@@ -66,7 +67,7 @@ def test_basedefinition_type():
'generator', 'statement', 'import', 'param') 'generator', 'statement', 'import', 'param')
def test_basedefinition_type_import(): def test_basedefinition_type_import(Script):
def get_types(source, **kwargs): def get_types(source, **kwargs):
return set([t.type for t in Script(source, **kwargs).completions()]) return set([t.type for t in Script(source, **kwargs).completions()])
@@ -89,7 +90,7 @@ def test_basedefinition_type_import():
assert get_types('import json.tool', column=9) == set(['module']) assert get_types('import json.tool', column=9) == set(['module'])
def test_function_call_signature_in_doc(): def test_function_call_signature_in_doc(Script):
defs = Script(""" defs = Script("""
def f(x, y=1, z='a'): def f(x, y=1, z='a'):
pass pass
@@ -98,7 +99,7 @@ def test_function_call_signature_in_doc():
assert "f(x, y=1, z='a')" in str(doc) assert "f(x, y=1, z='a')" in str(doc)
def test_class_call_signature(): def test_class_call_signature(Script):
defs = Script(""" defs = Script("""
class Foo: class Foo:
def __init__(self, x, y=1, z='a'): def __init__(self, x, y=1, z='a'):
@@ -108,14 +109,14 @@ def test_class_call_signature():
assert "Foo(self, x, y=1, z='a')" in str(doc) assert "Foo(self, x, y=1, z='a')" in str(doc)
def test_position_none_if_builtin(): def test_position_none_if_builtin(Script):
gotos = Script('import sys; sys.path').goto_assignments() gotos = Script('import sys; sys.path').goto_assignments()
assert gotos[0].line is None assert gotos[0].line is None
assert gotos[0].column is None assert gotos[0].column is None
@cwd_at('.') @cwd_at('.')
def test_completion_docstring(): def test_completion_docstring(Script):
""" """
Jedi should follow imports in certain conditions Jedi should follow imports in certain conditions
""" """
@@ -126,7 +127,7 @@ def test_completion_docstring():
c = Script('import jedi\njed').completions()[0] c = Script('import jedi\njed').completions()[0]
assert c.docstring(fast=False) == cleandoc(jedi_doc) assert c.docstring(fast=False) == cleandoc(jedi_doc)
docstr('import jedi\njedi.Scr', cleandoc(Script.__doc__)) docstr('import jedi\njedi.Scr', cleandoc(jedi.Script.__doc__))
docstr('abcd=3;abcd', '') docstr('abcd=3;abcd', '')
docstr('"hello"\nabcd=3\nabcd', '') docstr('"hello"\nabcd=3\nabcd', '')
@@ -160,12 +161,12 @@ def test_completion_docstring():
) )
def test_completion_params(): def test_completion_params(Script):
c = Script('import string; string.capwords').completions()[0] c = Script('import string; string.capwords').completions()[0]
assert [p.name for p in c.params] == ['s', 'sep'] assert [p.name for p in c.params] == ['s', 'sep']
def test_signature_params(): def test_signature_params(Script):
def check(defs): def check(defs):
params = defs[0].params params = defs[0].params
assert len(params) == 1 assert len(params) == 1
@@ -182,7 +183,7 @@ def test_signature_params():
check(Script(s + '\nbar=foo\nbar').goto_assignments()) check(Script(s + '\nbar=foo\nbar').goto_assignments())
def test_param_endings(): def test_param_endings(Script):
""" """
Params should be represented without the comma and whitespace they have Params should be represented without the comma and whitespace they have
around them. around them.
@@ -192,8 +193,17 @@ def test_param_endings():
class TestIsDefinition(TestCase): class TestIsDefinition(TestCase):
@pytest.fixture(autouse=True)
def init(self, environment):
self.environment = environment
def _def(self, source, index=-1): def _def(self, source, index=-1):
return names(dedent(source), references=True, all_scopes=True)[index] return names(
dedent(source),
references=True,
all_scopes=True,
environment=self.environment
)[index]
def _bool_is_definitions(self, source): def _bool_is_definitions(self, source):
ns = names(dedent(source), references=True, all_scopes=True) ns = names(dedent(source), references=True, all_scopes=True)
@@ -225,8 +235,12 @@ class TestIsDefinition(TestCase):
class TestParent(TestCase): class TestParent(TestCase):
@pytest.fixture(autouse=True)
def init(self, Script):
self.Script = Script
def _parent(self, source, line=None, column=None): def _parent(self, source, line=None, column=None):
def_, = Script(dedent(source), line, column).goto_assignments() def_, = self.Script(dedent(source), line, column).goto_assignments()
return def_.parent() return def_.parent()
def test_parent(self): def test_parent(self):
@@ -248,20 +262,21 @@ class TestParent(TestCase):
assert parent.name == '' assert parent.name == ''
assert parent.type == 'module' assert parent.type == 'module'
def test_parent_on_completion(self):
parent = Script(dedent('''\
class Foo():
def bar(): pass
Foo().bar''')).completions()[0].parent()
assert parent.name == 'Foo'
assert parent.type == 'class'
parent = Script('str.join').completions()[0].parent() def test_parent_on_completion(Script):
assert parent.name == 'str' parent = Script(dedent('''\
assert parent.type == 'class' class Foo():
def bar(): pass
Foo().bar''')).completions()[0].parent()
assert parent.name == 'Foo'
assert parent.type == 'class'
parent = Script('str.join').completions()[0].parent()
assert parent.name == 'str'
assert parent.type == 'class'
def test_type(): def test_type(Script):
for c in Script('a = [str()]; a[0].').completions(): for c in Script('a = [str()]; a[0].').completions():
if c.name == '__class__': if c.name == '__class__':
assert c.type == 'class' assert c.type == 'class'
@@ -272,7 +287,8 @@ def test_type():
for c in Script('import os; os.path.').completions(): for c in Script('import os; os.path.').completions():
assert c.type assert c.type
def test_type_II():
def test_type_II(Script):
""" """
GitHub Issue #833, `keyword`s are seen as `module`s GitHub Issue #833, `keyword`s are seen as `module`s
""" """
@@ -281,100 +297,106 @@ def test_type_II():
assert c.type == 'keyword' assert c.type == 'keyword'
class TestGotoAssignments(TestCase): """
""" This tests the BaseDefinition.goto_assignments function, not the jedi
This tests the BaseDefinition.goto_assignments function, not the jedi function. They are not really different in functionality, but really
function. They are not really different in functionality, but really different as an implementation.
different as an implementation. """
"""
def test_repetition(self):
defs = names('a = 1; a', references=True, definitions=False)
# Repeat on the same variable. Shouldn't change once we're on a
# definition.
for _ in range(3):
assert len(defs) == 1
ass = defs[0].goto_assignments()
assert ass[0].description == 'a = 1'
def test_named_params(self):
src = """\
def foo(a=1, bar=2):
pass
foo(bar=1)
"""
bar = names(dedent(src), references=True)[-1]
param = bar.goto_assignments()[0]
assert (param.line, param.column) == (1, 13)
assert param.type == 'param'
def test_class_call(self):
src = 'from threading import Thread; Thread(group=1)'
n = names(src, references=True)[-1]
assert n.name == 'group'
param_def = n.goto_assignments()[0]
assert param_def.name == 'group'
assert param_def.type == 'param'
def test_parentheses(self):
n = names('("").upper', references=True)[-1]
assert n.goto_assignments()[0].name == 'upper'
def test_import(self):
nms = names('from json import load', references=True)
assert nms[0].name == 'json'
assert nms[0].type == 'module'
n = nms[0].goto_assignments()[0]
assert n.name == 'json'
assert n.type == 'module'
assert nms[1].name == 'load'
assert nms[1].type == 'function'
n = nms[1].goto_assignments()[0]
assert n.name == 'load'
assert n.type == 'function'
nms = names('import os; os.path', references=True)
assert nms[0].name == 'os'
assert nms[0].type == 'module'
n = nms[0].goto_assignments()[0]
assert n.name == 'os'
assert n.type == 'module'
n = nms[2].goto_assignments()[0]
assert n.name == 'path'
assert n.type == 'module'
nms = names('import os.path', references=True)
n = nms[0].goto_assignments()[0]
assert n.name == 'os'
assert n.type == 'module'
n = nms[1].goto_assignments()[0]
# This is very special, normally the name doesn't chance, but since
# os.path is a sys.modules hack, it does.
assert n.name in ('ntpath', 'posixpath', 'os2emxpath')
assert n.type == 'module'
def test_import_alias(self):
nms = names('import json as foo', references=True)
assert nms[0].name == 'json'
assert nms[0].type == 'module'
assert nms[0]._name.tree_name.parent.type == 'dotted_as_name'
n = nms[0].goto_assignments()[0]
assert n.name == 'json'
assert n.type == 'module'
assert n._name._context.tree_node.type == 'file_input'
assert nms[1].name == 'foo'
assert nms[1].type == 'module'
assert nms[1]._name.tree_name.parent.type == 'dotted_as_name'
ass = nms[1].goto_assignments()
assert len(ass) == 1
assert ass[0].name == 'json'
assert ass[0].type == 'module'
assert ass[0]._name._context.tree_node.type == 'file_input'
def test_added_equals_to_params(): def test_goto_assignment_repetition(environment):
defs = names('a = 1; a', references=True, definitions=False, environment=environment)
# Repeat on the same variable. Shouldn't change once we're on a
# definition.
for _ in range(3):
assert len(defs) == 1
ass = defs[0].goto_assignments()
assert ass[0].description == 'a = 1'
def test_goto_assignments_named_params(environment):
src = """\
def foo(a=1, bar=2):
pass
foo(bar=1)
"""
bar = names(dedent(src), references=True, environment=environment)[-1]
param = bar.goto_assignments()[0]
assert (param.line, param.column) == (1, 13)
assert param.type == 'param'
def test_class_call(environment):
src = 'from threading import Thread; Thread(group=1)'
n = names(src, references=True, environment=environment)[-1]
assert n.name == 'group'
param_def = n.goto_assignments()[0]
assert param_def.name == 'group'
assert param_def.type == 'param'
def test_parentheses(environment):
n = names('("").upper', references=True, environment=environment)[-1]
assert n.goto_assignments()[0].name == 'upper'
def test_import(environment):
nms = names('from json import load', references=True, environment=environment)
assert nms[0].name == 'json'
assert nms[0].type == 'module'
n = nms[0].goto_assignments()[0]
assert n.name == 'json'
assert n.type == 'module'
assert nms[1].name == 'load'
assert nms[1].type == 'function'
n = nms[1].goto_assignments()[0]
assert n.name == 'load'
assert n.type == 'function'
nms = names('import os; os.path', references=True, environment=environment)
assert nms[0].name == 'os'
assert nms[0].type == 'module'
n = nms[0].goto_assignments()[0]
assert n.name == 'os'
assert n.type == 'module'
n = nms[2].goto_assignments()[0]
assert n.name == 'path'
assert n.type == 'module'
nms = names('import os.path', references=True, environment=environment)
n = nms[0].goto_assignments()[0]
assert n.name == 'os'
assert n.type == 'module'
n = nms[1].goto_assignments()[0]
# This is very special, normally the name doesn't chance, but since
# os.path is a sys.modules hack, it does.
assert n.name in ('ntpath', 'posixpath', 'os2emxpath')
assert n.type == 'module'
def test_import_alias(environment):
nms = names('import json as foo', references=True, environment=environment)
assert nms[0].name == 'json'
assert nms[0].type == 'module'
assert nms[0]._name.tree_name.parent.type == 'dotted_as_name'
n = nms[0].goto_assignments()[0]
assert n.name == 'json'
assert n.type == 'module'
assert n._name._context.tree_node.type == 'file_input'
assert nms[1].name == 'foo'
assert nms[1].type == 'module'
assert nms[1]._name.tree_name.parent.type == 'dotted_as_name'
ass = nms[1].goto_assignments()
assert len(ass) == 1
assert ass[0].name == 'json'
assert ass[0].type == 'module'
assert ass[0]._name._context.tree_node.type == 'file_input'
def test_added_equals_to_params(Script):
def run(rest_source): def run(rest_source):
source = dedent(""" source = dedent("""
def foo(bar, baz): def foo(bar, baz):

View File

@@ -1,15 +1,14 @@
from textwrap import dedent from textwrap import dedent
from jedi import Script
def test_in_whitespace(): def test_in_whitespace(Script):
code = dedent(''' code = dedent('''
def x(): def x():
pass''') pass''')
assert len(Script(code, column=2).completions()) > 20 assert len(Script(code, column=2).completions()) > 20
def test_empty_init(): def test_empty_init(Script):
"""This was actually an issue.""" """This was actually an issue."""
code = dedent('''\ code = dedent('''\
class X(object): pass class X(object): pass
@@ -17,7 +16,7 @@ def test_empty_init():
assert Script(code).completions() assert Script(code).completions()
def test_in_empty_space(): def test_in_empty_space(Script):
code = dedent('''\ code = dedent('''\
class X(object): class X(object):
def __init__(self): def __init__(self):
@@ -30,7 +29,7 @@ def test_in_empty_space():
assert def_.name == 'X' assert def_.name == 'X'
def test_indent_context(): def test_indent_context(Script):
""" """
If an INDENT is the next supposed token, we should still be able to If an INDENT is the next supposed token, we should still be able to
complete. complete.
@@ -40,7 +39,7 @@ def test_indent_context():
assert comp.name == 'isinstance' assert comp.name == 'isinstance'
def test_keyword_context(): def test_keyword_context(Script):
def get_names(*args, **kwargs): def get_names(*args, **kwargs):
return [d.name for d in Script(*args, **kwargs).completions()] return [d.name for d in Script(*args, **kwargs).completions()]

View File

@@ -4,16 +4,22 @@ Tests for `api.defined_names`.
from textwrap import dedent from textwrap import dedent
import pytest
from jedi import names from jedi import names
from ..helpers import TestCase from ..helpers import TestCase
class TestDefinedNames(TestCase): class TestDefinedNames(TestCase):
@pytest.fixture(autouse=True)
def init(self, environment):
self.environment = environment
def assert_definition_names(self, definitions, names_): def assert_definition_names(self, definitions, names_):
assert [d.name for d in definitions] == names_ assert [d.name for d in definitions] == names_
def check_defined_names(self, source, names_): def check_defined_names(self, source, names_):
definitions = names(dedent(source)) definitions = names(dedent(source), environment=self.environment)
self.assert_definition_names(definitions, names_) self.assert_definition_names(definitions, names_)
return definitions return definitions
@@ -74,19 +80,19 @@ class TestDefinedNames(TestCase):
self.assert_definition_names(subsubdefs[0].defined_names(), ['f']) self.assert_definition_names(subsubdefs[0].defined_names(), ['f'])
def test_follow_imports(): def test_follow_imports(environment):
# github issue #344 # github issue #344
imp = names('import datetime')[0] imp = names('import datetime', environment=environment)[0]
assert imp.name == 'datetime' assert imp.name == 'datetime'
datetime_names = [str(d.name) for d in imp.defined_names()] datetime_names = [str(d.name) for d in imp.defined_names()]
assert 'timedelta' in datetime_names assert 'timedelta' in datetime_names
def test_names_twice(): def test_names_twice(environment):
source = dedent(''' source = dedent('''
def lol(): def lol():
pass pass
''') ''')
defs = names(source=source) defs = names(source=source, environment=environment)
assert defs[0].defined_names() == [] assert defs[0].defined_names() == []

View File

@@ -24,8 +24,12 @@ from ..helpers import TestCase
class MixinTestFullName(object): class MixinTestFullName(object):
operation = None operation = None
@pytest.fixture(autouse=True)
def init(self, Script):
self.Script = Script
def check(self, source, desired): def check(self, source, desired):
script = jedi.Script(textwrap.dedent(source)) script = self.Script(textwrap.dedent(source))
definitions = getattr(script, type(self).operation)() definitions = getattr(script, type(self).operation)()
for d in definitions: for d in definitions:
self.assertEqual(d.full_name, desired) self.assertEqual(d.full_name, desired)
@@ -80,25 +84,25 @@ class TestFullDefinedName(TestCase):
""", ['os', 'os.path', 'os.path.join', 'os.path']) """, ['os', 'os.path', 'os.path.join', 'os.path'])
def test_sub_module(): def test_sub_module(Script):
""" """
``full_name needs to check sys.path to actually find it's real path module ``full_name needs to check sys.path to actually find it's real path module
path. path.
""" """
defs = jedi.Script('from jedi.api import classes; classes').goto_definitions() defs = Script('from jedi.api import classes; classes').goto_definitions()
assert [d.full_name for d in defs] == ['jedi.api.classes'] assert [d.full_name for d in defs] == ['jedi.api.classes']
defs = jedi.Script('import jedi.api; jedi.api').goto_definitions() defs = Script('import jedi.api; jedi.api').goto_definitions()
assert [d.full_name for d in defs] == ['jedi.api'] assert [d.full_name for d in defs] == ['jedi.api']
def test_os_path(): def test_os_path(Script):
d, = jedi.Script('from os.path import join').completions() d, = Script('from os.path import join').completions()
assert d.full_name == 'os.path.join' assert d.full_name == 'os.path.join'
d, = jedi.Script('import os.p').completions() d, = Script('import os.p').completions()
assert d.full_name == 'os.path' assert d.full_name == 'os.path'
def test_os_issues(): def test_os_issues(Script):
"""Issue #873""" """Issue #873"""
c, = jedi.Script('import os\nos.nt''').completions() c, = Script('import os\nos.nt''').completions()
assert c.full_name == 'nt' assert c.full_name == 'nt'

View File

@@ -2,11 +2,10 @@
""" """
All character set and unicode related tests. All character set and unicode related tests.
""" """
from jedi import Script
from jedi._compatibility import u, unicode from jedi._compatibility import u, unicode
def test_unicode_script(): def test_unicode_script(Script):
""" normally no unicode objects are being used. (<=2.7) """ """ normally no unicode objects are being used. (<=2.7) """
s = unicode("import datetime; datetime.timedelta") s = unicode("import datetime; datetime.timedelta")
completions = Script(s).completions() completions = Script(s).completions()
@@ -24,7 +23,7 @@ def test_unicode_script():
assert type(completions[0].description) is unicode assert type(completions[0].description) is unicode
def test_unicode_attribute(): def test_unicode_attribute(Script):
""" github jedi-vim issue #94 """ """ github jedi-vim issue #94 """
s1 = u('#-*- coding: utf-8 -*-\nclass Person():\n' s1 = u('#-*- coding: utf-8 -*-\nclass Person():\n'
' name = "e"\n\nPerson().name.') ' name = "e"\n\nPerson().name.')
@@ -36,7 +35,7 @@ def test_unicode_attribute():
assert 'strip' in [c.name for c in completions2] assert 'strip' in [c.name for c in completions2]
def test_multibyte_script(): def test_multibyte_script(Script):
""" `jedi.Script` must accept multi-byte string source. """ """ `jedi.Script` must accept multi-byte string source. """
try: try:
code = u("import datetime; datetime.d") code = u("import datetime; datetime.d")
@@ -48,7 +47,7 @@ def test_multibyte_script():
assert len(Script(s, 1, len(code)).completions()) assert len(Script(s, 1, len(code)).completions())
def test_goto_definition_at_zero(): def test_goto_definition_at_zero(Script):
"""At zero usually sometimes raises unicode issues.""" """At zero usually sometimes raises unicode issues."""
assert Script("a", 1, 1).goto_definitions() == [] assert Script("a", 1, 1).goto_definitions() == []
s = Script("str", 1, 1).goto_definitions() s = Script("str", 1, 1).goto_definitions()
@@ -57,7 +56,7 @@ def test_goto_definition_at_zero():
assert Script("", 1, 0).goto_definitions() == [] assert Script("", 1, 0).goto_definitions() == []
def test_complete_at_zero(): def test_complete_at_zero(Script):
s = Script("str", 1, 3).completions() s = Script("str", 1, 3).completions()
assert len(s) == 1 assert len(s) == 1
assert list(s)[0].name == 'str' assert list(s)[0].name == 'str'

View File

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