Adding new stuff

This commit is contained in:
ViktorBarzin 2017-07-09 00:23:01 +03:00
parent 9ef8a96f9a
commit 0b3d063cb3
1580 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,179 @@
"""
Test all things related to the ``jedi.api`` module.
"""
from textwrap import dedent
from jedi import api
from jedi._compatibility import is_py3
from pytest import raises
from jedi.parser import utils
def test_preload_modules():
def check_loaded(*modules):
# +1 for None module (currently used)
assert len(parser_cache) == len(modules) + 1
for i in modules:
assert [i in k for k in parser_cache.keys() if k is not None]
temp_cache, utils.parser_cache = utils.parser_cache, {}
parser_cache = utils.parser_cache
api.preload_module('sys')
check_loaded() # compiled (c_builtin) modules shouldn't be in the cache.
api.preload_module('json', 'token')
check_loaded('json', 'token')
utils.parser_cache = temp_cache
def test_empty_script():
assert api.Script('')
def test_line_number_errors():
"""
Script should raise a ValueError if line/column numbers are not in a
valid range.
"""
s = 'hello'
# lines
with raises(ValueError):
api.Script(s, 2, 0)
with raises(ValueError):
api.Script(s, 0, 0)
# columns
with raises(ValueError):
api.Script(s, 1, len(s) + 1)
with raises(ValueError):
api.Script(s, 1, -1)
# ok
api.Script(s, 1, 0)
api.Script(s, 1, len(s))
def _check_number(source, result='float'):
completions = api.Script(source).completions()
assert completions[0].parent().name == result
def test_completion_on_number_literals():
# No completions on an int literal (is a float).
assert [c.name for c in api.Script('1.').completions()] \
== ['and', 'if', 'in', 'is', 'not', 'or']
# Multiple points after an int literal basically mean that there's a float
# and a call after that.
_check_number('1..')
_check_number('1.0.')
# power notation
_check_number('1.e14.')
_check_number('1.e-3.')
_check_number('9e3.')
assert api.Script('1.e3..').completions() == []
assert api.Script('1.e-13..').completions() == []
def test_completion_on_hex_literals():
assert api.Script('0x1..').completions() == []
_check_number('0x1.', 'int') # hexdecimal
# Completing binary literals doesn't work if they are not actually binary
# (invalid statements).
assert api.Script('0b2.b').completions() == []
_check_number('0b1.', 'int') # binary
_check_number('0x2e.', 'int')
_check_number('0xE7.', 'int')
_check_number('0xEa.', 'int')
# theoretically, but people can just check for syntax errors:
#assert api.Script('0x.').completions() == []
def test_completion_on_complex_literals():
assert api.Script('1j..').completions() == []
_check_number('1j.', 'complex')
_check_number('44.j.', 'complex')
_check_number('4.0j.', 'complex')
# No dot no completion - I thought, but 4j is actually a literall after
# which a keyword like or is allowed. Good times, haha!
assert (set([c.name for c in api.Script('4j').completions()]) ==
set(['if', 'and', 'in', 'is', 'not', 'or']))
def test_goto_assignments_on_non_name():
assert api.Script('for').goto_assignments() == []
assert api.Script('assert').goto_assignments() == []
if is_py3:
assert api.Script('True').goto_assignments() == []
else:
# In Python 2.7 True is still a name.
assert api.Script('True').goto_assignments()[0].description == 'class bool'
def test_goto_definitions_on_non_name():
assert api.Script('import x', column=0).goto_definitions() == []
def test_goto_definition_not_multiple():
"""
There should be only one Definition result if it leads back to the same
origin (e.g. instance method)
"""
s = dedent('''\
import random
class A():
def __init__(self, a):
self.a = 3
def foo(self):
pass
if random.randint(0, 1):
a = A(2)
else:
a = A(1)
a''')
assert len(api.Script(s).goto_definitions()) == 1
def test_usage_description():
descs = [u.description for u in api.Script("foo = ''; foo").usages()]
assert set(descs) == set(["foo = ''", 'foo'])
def test_get_line_code():
def get_line_code(source, line=None, **kwargs):
return api.Script(source, line=line).completions()[0].get_line_code(**kwargs)
# On builtin
assert get_line_code('') == ''
# On custom code
line = ' foo'
assert get_line_code('def foo():\n%s' % line) == line
# With before/after
line = ' foo'
source = 'def foo():\n%s\nother_line' % line
assert get_line_code(source, line=2) == line
assert get_line_code(source, line=2, after=1) == line + '\nother_line'
assert get_line_code(source, line=2, after=1, before=1) == source
def test_goto_assignments_follow_imports():
code = dedent("""
import inspect
inspect.isfunction""")
definition, = api.Script(code, column=0).goto_assignments(follow_imports=True)
assert 'inspect.py' in definition.module_path
assert definition.start_pos == (1, 0)
definition, = api.Script(code).goto_assignments(follow_imports=True)
assert 'inspect.py' in definition.module_path
assert definition.start_pos > (1, 0)

View file

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

View file

@ -0,0 +1,389 @@
from textwrap import dedent
import inspect
from ..helpers import TestCase
from jedi import Script
from jedi import cache
from jedi._compatibility import is_py33
def assert_signature(source, expected_name, expected_index=0, line=None, column=None):
signatures = Script(source, line, column).call_signatures()
assert len(signatures) <= 1
if not signatures:
assert expected_name is None, \
'There are no signatures, but `%s` expected.' % expected_name
else:
assert signatures[0].name == expected_name
assert signatures[0].index == expected_index
return signatures[0]
class TestCallSignatures(TestCase):
def _run_simple(self, source, name, index=0, column=None, line=1):
assert_signature(source, name, index, line, column)
def test_valid_call(self):
assert_signature('str()', 'str', column=4)
def test_simple(self):
run = self._run_simple
# simple
s1 = "sorted(a, str("
run(s1, 'sorted', 0, 7)
run(s1, 'sorted', 1, 9)
run(s1, 'sorted', 1, 10)
run(s1, 'sorted', 1, 11)
run(s1, 'str', 0, 14)
s2 = "abs(), "
run(s2, 'abs', 0, 4)
run(s2, None, column=5)
run(s2, None)
s3 = "abs()."
run(s3, None, column=5)
run(s3, None)
def test_more_complicated(self):
run = self._run_simple
'''
s4 = 'abs(zip(), , set,'
run(s4, None, column=3)
run(s4, 'abs', 0, 4)
run(s4, 'zip', 0, 8)
run(s4, 'abs', 0, 9)
#run(s4, 'abs', 1, 10)
'''
s5 = "sorted(1,\nif 2:\n def a():"
run(s5, 'sorted', 0, 7)
run(s5, 'sorted', 1, 9)
s6 = "str().center("
run(s6, 'center', 0)
run(s6, 'str', 0, 4)
s7 = "str().upper().center("
s8 = "str(int[zip("
run(s7, 'center', 0)
run(s8, 'zip', 0)
run(s8, 'str', 0, 8)
run("import time; abc = time; abc.sleep(", 'sleep', 0)
def test_issue_57(self):
# jedi #57
s = "def func(alpha, beta): pass\n" \
"func(alpha='101',"
self._run_simple(s, 'func', 0, column=13, line=2)
def test_flows(self):
# jedi-vim #9
self._run_simple("with open(", 'open', 0)
# jedi-vim #11
self._run_simple("for 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):
abc(
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
s = """def foo("""
assert Script(s).call_signatures() == []
# 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):
pass
f( )""")
assert_signature(s, 'f', 0, line=3, column=3)
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
""")
assert_signature(s, 'abs', 0, line=1, column=5)
def test_decorator_in_class(self):
"""
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 == ['*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(self, source, line=None, column=None):
signatures = Script(source, line, column).call_signatures()
assert len(signatures) == 1
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():
"""
Through inheritance, a call signature is a sub class of Definition.
Check if the attributes match.
"""
s = """class Spam(): pass\nSpam"""
signature = Script(s + '(').call_signatures()[0]
definition = Script(s + '(', column=0).goto_definitions()[0]
signature.line == 1
signature.column == 6
# Now compare all the attributes that a CallSignature must also have.
for attr_name in dir(definition):
dont_scan = ['defined_names', 'line_nr', 'start_pos', 'documentation',
'doc', 'parent', 'goto_assignments']
if attr_name.startswith('_') or attr_name in dont_scan:
continue
attribute = getattr(definition, attr_name)
signature_attribute = getattr(signature, attr_name)
if inspect.ismethod(attribute):
assert attribute() == signature_attribute()
else:
assert attribute == signature_attribute
def test_no_signature():
# str doesn't have a __call__ method
assert Script('str()(').call_signatures() == []
s = dedent("""\
class X():
pass
X()(""")
assert Script(s).call_signatures() == []
assert len(Script(s, column=2).call_signatures()) == 1
def test_dict_literal_in_incomplete_call():
source = """\
import json
def foo():
json.loads(
json.load.return_value = {'foo': [],
'bar': True}
c = Foo()
"""
script = Script(dedent(source), line=4, column=15)
assert script.call_signatures()
def test_completion_interference():
"""Seems to cause problems, see also #396."""
cache.parser_cache.pop(None, None)
assert Script('open(').call_signatures()
# complete something usual, before doing the same call_signatures again.
assert Script('from datetime import ').completions()
assert Script('open(').call_signatures()
def test_keyword_argument_index():
def get(source, column=None):
return Script(source, column=column).call_signatures()[0]
assert get('sorted([], key=a').index == 2
assert get('sorted([], key=').index == 2
assert get('sorted([], no_key=a').index is None
kw_func = 'def foo(a, b): pass\nfoo(b=3, a=4)'
assert get(kw_func, column=len('foo(b')).index == 0
assert get(kw_func, column=len('foo(b=')).index == 1
assert get(kw_func, column=len('foo(b=3, a=')).index == 0
kw_func_simple = 'def foo(a, b): pass\nfoo(b=4)'
assert get(kw_func_simple, column=len('foo(b')).index == 0
assert get(kw_func_simple, column=len('foo(b=')).index == 1
args_func = 'def foo(*kwargs): pass\n'
assert get(args_func + 'foo(a').index == 0
assert get(args_func + 'foo(a, b').index == 0
kwargs_func = 'def foo(**kwargs): pass\n'
assert get(kwargs_func + 'foo(a=2').index == 0
assert get(kwargs_func + 'foo(a=2, b=2').index == 0
both = 'def foo(*args, **kwargs): pass\n'
assert get(both + 'foo(a=2').index == 1
assert get(both + 'foo(a=2, b=2').index == 1
assert get(both + 'foo(a=2, b=2)', column=len('foo(b=2, a=2')).index == 1
assert get(both + 'foo(a, b, c').index == 0
def test_bracket_start():
def bracket_start(src):
signatures = Script(src).call_signatures()
assert len(signatures) == 1
return signatures[0].bracket_start
assert bracket_start('str(') == (1, 3)
def test_different_caller():
"""
It's possible to not use names, but another function result or an array
index and then get the call signature of it.
"""
assert_signature('[str][0](', 'str', 0)
assert_signature('[str][0]()', 'str', 0, column=len('[str][0]('))
assert_signature('(str)(', 'str', 0)
assert_signature('(str)()', 'str', 0, column=len('(str)('))
def test_in_function():
code = dedent('''\
class X():
@property
def func(''')
assert not Script(code).call_signatures()
def test_lambda_params():
code = dedent('''\
my_lambda = lambda x: x+1
my_lambda(1)''')
sig, = Script(code, column=11).call_signatures()
assert sig.index == 0
assert sig.name == '<lambda>'
assert [p.name for p in sig.params] == ['x']

View file

@ -0,0 +1,354 @@
""" Test all things related to the ``jedi.api_classes`` module.
"""
from textwrap import dedent
from inspect import cleandoc
import pytest
from jedi import Script, defined_names, __doc__ as jedi_doc, names
from ..helpers import cwd_at
from ..helpers import TestCase
def test_is_keyword():
#results = Script('import ', 1, 1, None).goto_definitions()
#assert len(results) == 1 and results[0].is_keyword is True
results = Script('str', 1, 1, None).goto_definitions()
assert len(results) == 1 and results[0].is_keyword is False
def make_definitions():
"""
Return a list of definitions for parametrized tests.
:rtype: [jedi.api_classes.BaseDefinition]
"""
source = dedent("""
import sys
class C:
pass
x = C()
def f():
pass
def g():
yield
h = lambda: None
""")
definitions = []
definitions += defined_names(source)
source += dedent("""
variable = sys or C or x or f or g or g() or h""")
lines = source.splitlines()
script = Script(source, len(lines), len('variable'), None)
definitions += script.goto_definitions()
script2 = Script(source, 4, len('class C'), None)
definitions += script2.usages()
source_param = "def f(a): return a"
script_param = Script(source_param, 1, len(source_param), None)
definitions += script_param.goto_assignments()
return definitions
@pytest.mark.parametrize('definition', make_definitions())
def test_basedefinition_type(definition):
assert definition.type in ('module', 'class', 'instance', 'function',
'generator', 'statement', 'import', 'param')
def test_basedefinition_type_import():
def get_types(source, **kwargs):
return set([t.type for t in Script(source, **kwargs).completions()])
# import one level
assert get_types('import t') == set(['module'])
assert get_types('import ') == set(['module'])
assert get_types('import datetime; datetime') == set(['module'])
# from
assert get_types('from datetime import timedelta') == set(['class'])
assert get_types('from datetime import timedelta; timedelta') == set(['class'])
assert get_types('from json import tool') == set(['module'])
assert get_types('from json import tool; tool') == set(['module'])
# import two levels
assert get_types('import json.tool; json') == set(['module'])
assert get_types('import json.tool; json.tool') == set(['module'])
assert get_types('import json.tool; json.tool.main') == set(['function'])
assert get_types('import json.tool') == set(['module'])
assert get_types('import json.tool', column=9) == set(['module'])
def test_function_call_signature_in_doc():
defs = Script("""
def f(x, y=1, z='a'):
pass
f""").goto_definitions()
doc = defs[0].doc
assert "f(x, y=1, z='a')" in str(doc)
def test_class_call_signature():
defs = Script("""
class Foo:
def __init__(self, x, y=1, z='a'):
pass
Foo""").goto_definitions()
doc = defs[0].doc
assert "Foo(self, x, y=1, z='a')" in str(doc)
def test_position_none_if_builtin():
gotos = Script('import sys; sys.path').goto_assignments()
assert gotos[0].line is None
assert gotos[0].column is None
@cwd_at('.')
def test_completion_docstring():
"""
Jedi should follow imports in certain conditions
"""
def docstr(src, result):
c = Script(src).completions()[0]
assert c.docstring(raw=True, fast=False) == cleandoc(result)
c = Script('import jedi\njed').completions()[0]
assert c.docstring(fast=False) == cleandoc(jedi_doc)
docstr('import jedi\njedi.Scr', cleandoc(Script.__doc__))
docstr('abcd=3;abcd', '')
docstr('"hello"\nabcd=3\nabcd', 'hello')
# It works with a ; as well.
docstr('"hello"\nabcd=3;abcd', 'hello')
# Shouldn't work with a tuple.
docstr('"hello",0\nabcd=3\nabcd', '')
def test_completion_params():
c = Script('import string; string.capwords').completions()[0]
assert [p.name for p in c.params] == ['s', 'sep']
def test_signature_params():
def check(defs):
params = defs[0].params
assert len(params) == 1
assert params[0].name == 'bar'
s = dedent('''
def foo(bar):
pass
foo''')
check(Script(s).goto_definitions())
check(Script(s).goto_assignments())
check(Script(s + '\nbar=foo\nbar').goto_assignments())
def test_param_endings():
"""
Params should be represented without the comma and whitespace they have
around them.
"""
sig = Script('def x(a, b=5, c=""): pass\n x(').call_signatures()[0]
assert [p.description for p in sig.params] == ['a', 'b=5', 'c=""']
class TestIsDefinition(TestCase):
def _def(self, source, index=-1):
return names(dedent(source), references=True, all_scopes=True)[index]
def _bool_is_definitions(self, source):
ns = names(dedent(source), references=True, all_scopes=True)
# Assure that names are definitely sorted.
ns = sorted(ns, key=lambda name: (name.line, name.column))
return [name.is_definition() for name in ns]
def test_name(self):
d = self._def('name')
assert d.name == 'name'
assert not d.is_definition()
def test_stmt(self):
src = 'a = f(x)'
d = self._def(src, 0)
assert d.name == 'a'
assert d.is_definition()
d = self._def(src, 1)
assert d.name == 'f'
assert not d.is_definition()
d = self._def(src)
assert d.name == 'x'
assert not d.is_definition()
def test_import(self):
assert self._bool_is_definitions('import x as a') == [False, True]
assert self._bool_is_definitions('from x import y') == [False, True]
assert self._bool_is_definitions('from x.z import y') == [False, False, True]
class TestParent(TestCase):
def _parent(self, source, line=None, column=None):
defs = Script(dedent(source), line, column).goto_assignments()
assert len(defs) == 1
return defs[0].parent()
def test_parent(self):
parent = self._parent('foo=1\nfoo')
assert parent.type == 'module'
parent = self._parent('''
def spam():
if 1:
y=1
y''')
assert parent.name == 'spam'
assert parent.parent().type == 'module'
def test_on_function(self):
parent = self._parent('''\
def spam():
pass''', 1, len('def spam'))
assert parent.name == ''
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 == 'instance'
parent = Script('str.join').completions()[0].parent()
assert parent.name == 'str'
assert parent.type == 'class'
def test_type():
"""
Github issue #397, type should never raise an error.
"""
for c in Script('import os; os.path.').completions():
assert c.type
class TestGotoAssignments(TestCase):
"""
This tests the BaseDefinition.goto_assignments function, not the jedi
function. They are not really different in functionality, but really
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.start_pos == (1, 13)
assert param.type == 'param'
def test_class_call(self):
src = 'from threading import Thread; Thread(group=1)'
n = names(src, references=True)[-1]
assert n.name == 'group'
param_def = n.goto_assignments()[0]
assert param_def.name == 'group'
assert param_def.type == 'param'
def test_parentheses(self):
n = names('("").upper', references=True)[-1]
assert n.goto_assignments()[0].name == 'upper'
def test_import(self):
nms = names('from json import load', references=True)
assert nms[0].name == 'json'
assert nms[0].type == 'import'
n = nms[0].goto_assignments()[0]
assert n.name == 'json'
assert n.type == 'module'
assert nms[1].name == 'load'
assert nms[1].type == 'import'
n = nms[1].goto_assignments()[0]
assert n.name == 'load'
assert n.type == 'function'
nms = names('import os; os.path', references=True)
assert nms[0].name == 'os'
assert nms[0].type == 'import'
n = nms[0].goto_assignments()[0]
assert n.name == 'os'
assert n.type == 'module'
n = nms[2].goto_assignments()[0]
assert n.name == 'path'
assert n.type == 'import'
nms = names('import os.path', references=True)
n = nms[0].goto_assignments()[0]
assert n.name == 'os'
assert n.type == 'module'
n = nms[1].goto_assignments()[0]
# 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 == 'import'
n = nms[0].goto_assignments()[0]
assert n.name == 'json'
assert n.type == 'module'
assert nms[1].name == 'foo'
assert nms[1].type == 'import'
ass = nms[1].goto_assignments()
assert len(ass) == 1
assert ass[0].name == 'json'
assert ass[0].type == 'module'
def test_added_equals_to_params():
def run(rest_source):
source = dedent("""
def foo(bar, baz):
pass
""")
results = Script(source + rest_source).completions()
assert len(results) == 1
return results[0]
assert run('foo(bar').name_with_symbols == 'bar='
assert run('foo(bar').complete == '='
assert run('foo(bar, baz').complete == '='
assert run(' bar').name_with_symbols == 'bar'
assert run(' bar').complete == ''
x = run('foo(bar=isins').name_with_symbols
assert x == 'isinstance'

View file

@ -0,0 +1,9 @@
from textwrap import dedent
from jedi import Script
def test_in_whitespace():
code = dedent('''
def x():
pass''')
assert len(Script(code, column=2).completions()) > 20

View file

@ -0,0 +1,92 @@
"""
Tests for `api.defined_names`.
"""
from textwrap import dedent
from jedi import defined_names, names
from ..helpers import TestCase
class TestDefinedNames(TestCase):
def assert_definition_names(self, definitions, names_):
assert [d.name for d in definitions] == names_
def check_defined_names(self, source, names_):
definitions = names(dedent(source))
self.assert_definition_names(definitions, names_)
return definitions
def test_get_definitions_flat(self):
self.check_defined_names("""
import module
class Class:
pass
def func():
pass
data = None
""", ['module', 'Class', 'func', 'data'])
def test_dotted_assignment(self):
self.check_defined_names("""
x = Class()
x.y.z = None
""", ['x', 'z']) # TODO is this behavior what we want?
def test_multiple_assignment(self):
self.check_defined_names("""
x = y = None
""", ['x', 'y'])
def test_multiple_imports(self):
self.check_defined_names("""
from module import a, b
from another_module import *
""", ['a', 'b'])
def test_nested_definitions(self):
definitions = self.check_defined_names("""
class Class:
def f():
pass
def g():
pass
""", ['Class'])
subdefinitions = definitions[0].defined_names()
self.assert_definition_names(subdefinitions, ['f', 'g'])
self.assertEqual([d.full_name for d in subdefinitions],
['Class.f', 'Class.g'])
def test_nested_class(self):
definitions = self.check_defined_names("""
class L1:
class L2:
class L3:
def f(): pass
def f(): pass
def f(): pass
def f(): pass
""", ['L1', 'f'])
subdefs = definitions[0].defined_names()
subsubdefs = subdefs[0].defined_names()
self.assert_definition_names(subdefs, ['L2', 'f'])
self.assert_definition_names(subsubdefs, ['L3', 'f'])
self.assert_definition_names(subsubdefs[0].defined_names(), ['f'])
def test_follow_imports():
# github issue #344
imp = defined_names('import datetime')[0]
assert imp.name == 'datetime'
datetime_names = [str(d.name) for d in imp.defined_names()]
assert 'timedelta' in datetime_names
def test_names_twice():
source = dedent('''
def lol():
pass
''')
defs = names(source=source)
assert defs[0].defined_names() == []

View file

@ -0,0 +1,91 @@
"""
Tests for :attr:`.BaseDefinition.full_name`.
There are three kinds of test:
#. Test classes derived from :class:`MixinTestFullName`.
Child class defines :attr:`.operation` to alter how
the api definition instance is created.
#. :class:`TestFullDefinedName` is to test combination of
``obj.full_name`` and ``jedi.defined_names``.
#. Misc single-function tests.
"""
import textwrap
import pytest
import jedi
from ..helpers import TestCase
class MixinTestFullName(object):
operation = None
def check(self, source, desired):
script = jedi.Script(textwrap.dedent(source))
definitions = getattr(script, type(self).operation)()
for d in definitions:
self.assertEqual(d.full_name, desired)
def test_os_path_join(self):
self.check('import os; os.path.join', 'os.path.join')
def test_builtin(self):
self.check('TypeError', 'TypeError')
class TestFullNameWithGotoDefinitions(MixinTestFullName, TestCase):
operation = 'goto_definitions'
@pytest.mark.skipif('sys.version_info[0] < 3', reason='Python 2 also yields None.')
def test_tuple_mapping(self):
self.check("""
import re
any_re = re.compile('.*')
any_re""", '_sre.compile.SRE_Pattern')
def test_from_import(self):
self.check('from os import path', 'os.path')
class TestFullNameWithCompletions(MixinTestFullName, TestCase):
operation = 'completions'
class TestFullDefinedName(TestCase):
"""
Test combination of ``obj.full_name`` and ``jedi.defined_names``.
"""
def check(self, source, desired):
definitions = jedi.defined_names(textwrap.dedent(source))
full_names = [d.full_name for d in definitions]
self.assertEqual(full_names, desired)
def test_local_names(self):
self.check("""
def f(): pass
class C: pass
""", ['f', 'C'])
def test_imports(self):
self.check("""
import os
from os import path
from os.path import join
from os import path as opath
""", ['os', 'os.path', 'os.path.join', 'os.path'])
def test_sub_module():
"""
``full_name needs to check sys.path to actually find it's real path module
path.
"""
defs = jedi.Script('from jedi.api import classes; classes').goto_definitions()
assert [d.full_name for d in defs] == ['jedi.api.classes']
defs = jedi.Script('import jedi.api; jedi.api').goto_definitions()
assert [d.full_name for d in defs] == ['jedi.api']

View file

@ -0,0 +1,160 @@
"""
Tests of ``jedi.api.Interpreter``.
"""
from ..helpers import TestCase
import jedi
from jedi._compatibility import is_py33
from jedi.evaluate.compiled import mixed
class _GlobalNameSpace():
class SideEffectContainer():
pass
def get_completion(source, namespace):
i = jedi.Interpreter(source, [namespace])
completions = i.completions()
assert len(completions) == 1
return completions[0]
def test_builtin_details():
import keyword
class EmptyClass:
pass
variable = EmptyClass()
def func():
pass
cls = get_completion('EmptyClass', locals())
var = get_completion('variable', locals())
f = get_completion('func', locals())
m = get_completion('keyword', locals())
assert cls.type == 'class'
assert var.type == 'instance'
assert f.type == 'function'
assert m.type == 'module'
def test_nested_resolve():
class XX():
def x():
pass
cls = get_completion('XX', locals())
func = get_completion('XX.x', locals())
assert func.start_pos == (cls.start_pos[0] + 1, 12)
def test_side_effect_completion():
"""
In the repl it's possible to cause side effects that are not documented in
Python code, however we want references to Python code as well. Therefore
we need some mixed kind of magic for tests.
"""
_GlobalNameSpace.SideEffectContainer.foo = 1
side_effect = get_completion('SideEffectContainer', _GlobalNameSpace.__dict__)
# It's a class that contains MixedObject.
assert isinstance(side_effect._definition.base, mixed.MixedObject)
foo = get_completion('SideEffectContainer.foo', _GlobalNameSpace.__dict__)
assert foo.name == 'foo'
class TestInterpreterAPI(TestCase):
def check_interpreter_complete(self, source, namespace, completions,
**kwds):
script = jedi.Interpreter(source, [namespace], **kwds)
cs = script.completions()
actual = [c.name for c in cs]
self.assertEqual(sorted(actual), sorted(completions))
def test_complete_raw_function(self):
from os.path import join
self.check_interpreter_complete('join("").up',
locals(),
['upper'])
def test_complete_raw_function_different_name(self):
from os.path import join as pjoin
self.check_interpreter_complete('pjoin("").up',
locals(),
['upper'])
def test_complete_raw_module(self):
import os
self.check_interpreter_complete('os.path.join("a").up',
locals(),
['upper'])
def test_complete_raw_instance(self):
import datetime
dt = datetime.datetime(2013, 1, 1)
completions = ['time', 'timetz', 'timetuple']
if is_py33:
completions += ['timestamp']
self.check_interpreter_complete('(dt - dt).ti',
locals(),
completions)
def test_list(self):
array = ['haha', 1]
self.check_interpreter_complete('array[0].uppe',
locals(),
['upper'])
self.check_interpreter_complete('array[0].real',
locals(),
[])
# something different, no index given, still just return the right
self.check_interpreter_complete('array[int].real',
locals(),
['real'])
self.check_interpreter_complete('array[int()].real',
locals(),
['real'])
# inexistent index
self.check_interpreter_complete('array[2].upper',
locals(),
['upper'])
def test_slice(self):
class Foo():
bar = []
baz = 'xbarx'
self.check_interpreter_complete('getattr(Foo, baz[1:-1]).append',
locals(),
['append'])
def test_getitem_side_effects(self):
class Foo():
def __getitem__(self, index):
# possible side effects here, should therefore not call this.
return index
foo = Foo()
self.check_interpreter_complete('foo[0].', locals(), [])
def test_property_error(self):
class Foo():
@property
def bar(self):
raise ValueError
foo = Foo()
self.check_interpreter_complete('foo.bar', locals(), ['bar'])
self.check_interpreter_complete('foo.bar.baz', locals(), [])
def test_param_completion(self):
def foo(bar):
pass
lambd = lambda xyz: 3
self.check_interpreter_complete('foo(bar', locals(), ['bar'])
# TODO we're not yet using the Python3.5 inspect.signature, yet.
assert not jedi.Interpreter('lambd(xyz', [locals()]).completions()

View file

@ -0,0 +1,66 @@
# -*- coding: utf-8 -*-
"""
All character set and unicode related tests.
"""
from jedi import Script
from jedi._compatibility import u, unicode
def test_unicode_script():
""" normally no unicode objects are being used. (<=2.7) """
s = unicode("import datetime; datetime.timedelta")
completions = Script(s).completions()
assert len(completions)
assert type(completions[0].description) is unicode
s = u("author='öä'; author")
completions = Script(s).completions()
x = completions[0].description
assert type(x) is unicode
s = u("#-*- coding: iso-8859-1 -*-\nauthor='öä'; author")
s = s.encode('latin-1')
completions = Script(s).completions()
assert type(completions[0].description) is unicode
def test_unicode_attribute():
""" github jedi-vim issue #94 """
s1 = u('#-*- coding: utf-8 -*-\nclass Person():\n'
' name = "e"\n\nPerson().name.')
completions1 = Script(s1).completions()
assert 'strip' in [c.name for c in completions1]
s2 = u('#-*- coding: utf-8 -*-\nclass Person():\n'
' name = "é"\n\nPerson().name.')
completions2 = Script(s2).completions()
assert 'strip' in [c.name for c in completions2]
def test_multibyte_script():
""" `jedi.Script` must accept multi-byte string source. """
try:
code = u("import datetime; datetime.d")
comment = u("# multi-byte comment あいうえおä")
s = (u('%s\n%s') % (code, comment)).encode('utf-8')
except NameError:
pass # python 3 has no unicode method
else:
assert len(Script(s, 1, len(code)).completions())
def test_goto_definition_at_zero():
"""At zero usually sometimes raises unicode issues."""
assert Script("a", 1, 1).goto_definitions() == []
s = Script("str", 1, 1).goto_definitions()
assert len(s) == 1
assert list(s)[0].description == 'class str'
assert Script("", 1, 0).goto_definitions() == []
def test_complete_at_zero():
s = Script("str", 1, 3).completions()
assert len(s) == 1
assert list(s)[0].name == 'str'
s = Script("", 1, 0).completions()
assert len(s) > 0

View file

@ -0,0 +1,6 @@
import jedi
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]