Adding new stuff
This commit is contained in:
parent
9ef8a96f9a
commit
0b3d063cb3
1580 changed files with 0 additions and 0 deletions
179
vim-plugins/bundle/jedi-vim/jedi/test/test_api/test_api.py
Normal file
179
vim-plugins/bundle/jedi-vim/jedi/test/test_api/test_api.py
Normal 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)
|
||||
|
|
@ -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']
|
||||
|
|
@ -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']
|
||||
354
vim-plugins/bundle/jedi-vim/jedi/test/test_api/test_classes.py
Normal file
354
vim-plugins/bundle/jedi-vim/jedi/test/test_api/test_classes.py
Normal 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'
|
||||
|
|
@ -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
|
||||
|
|
@ -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() == []
|
||||
|
|
@ -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']
|
||||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
|
@ -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]
|
||||
Loading…
Add table
Add a link
Reference in a new issue