mirror of
https://github.com/xonsh/xonsh.git
synced 2025-03-04 16:34:47 +01:00

* refactor: rewrite xontribs/jedi.xsh -> xontribs/jedi.py to take advantage of python tooling * chore: update elm ci workflow * test: update test for jedi xontrib
218 lines
7.3 KiB
Python
218 lines
7.3 KiB
Python
"""Tests for the Jedi completer xontrib"""
|
|
import sys
|
|
import pytest
|
|
import builtins
|
|
import importlib
|
|
from unittest.mock import MagicMock, call
|
|
|
|
from xonsh.xontribs import find_xontrib
|
|
from xonsh.completers.tools import RichCompletion
|
|
|
|
|
|
@pytest.fixture
|
|
def jedi_mock(monkeypatch):
|
|
jedi_mock = MagicMock()
|
|
jedi_mock.__version__ = "0.16.0"
|
|
jedi_mock.Interpreter().complete.return_value = []
|
|
jedi_mock.reset_mock()
|
|
monkeypatch.setitem(sys.modules, "jedi", jedi_mock)
|
|
yield jedi_mock
|
|
|
|
|
|
@pytest.fixture
|
|
def completer_mock(monkeypatch):
|
|
completer_mock = MagicMock()
|
|
|
|
# so that args will be passed
|
|
def comp(args):
|
|
completer_mock(args)
|
|
|
|
monkeypatch.setitem(builtins.aliases, "completer", comp)
|
|
yield completer_mock
|
|
|
|
|
|
@pytest.fixture
|
|
def jedi_xontrib(monkeypatch, source_path, jedi_mock, completer_mock):
|
|
monkeypatch.syspath_prepend(source_path)
|
|
spec = find_xontrib("jedi")
|
|
yield importlib.import_module(spec.name)
|
|
del sys.modules[spec.name]
|
|
|
|
|
|
def test_completer_added(jedi_xontrib):
|
|
assert "xontrib.jedi" in sys.modules
|
|
assert "python" not in builtins.__xonsh__.completers
|
|
assert "python_mode" not in builtins.__xonsh__.completers
|
|
assert "jedi_python" in builtins.__xonsh__.completers
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"prefix, line, start, end, ctx", [("x", "10 + x", 5, 6, {}),], ids="x"
|
|
)
|
|
@pytest.mark.parametrize("version", ["new", "old"])
|
|
def test_jedi_api(jedi_xontrib, jedi_mock, version, prefix, line, start, end, ctx):
|
|
if version == "old":
|
|
jedi_mock.__version__ = "0.15.0"
|
|
jedi_mock.Interpreter().completions.return_value = []
|
|
jedi_mock.reset_mock()
|
|
|
|
jedi_xontrib.complete_jedi(prefix, line, start, end, ctx)
|
|
|
|
extra_namespace = {"__xonsh__": builtins.__xonsh__}
|
|
try:
|
|
extra_namespace["_"] = _
|
|
except NameError:
|
|
pass
|
|
namespaces = [{}, extra_namespace]
|
|
|
|
if version == "new":
|
|
assert jedi_mock.Interpreter.call_args_list == [call(line, namespaces)]
|
|
assert jedi_mock.Interpreter().complete.call_args_list == [call(1, end)]
|
|
else:
|
|
assert jedi_mock.Interpreter.call_args_list == [
|
|
call(line, namespaces, line=1, column=end)
|
|
]
|
|
assert jedi_mock.Interpreter().completions.call_args_list == [call()]
|
|
|
|
|
|
def test_multiline(jedi_xontrib, jedi_mock, monkeypatch):
|
|
shell_mock = MagicMock()
|
|
complete_document = "xx = 1\n1 + x"
|
|
shell_mock.shell_type = "prompt_toolkit"
|
|
shell_mock.shell.pt_completer.current_document.text = complete_document
|
|
shell_mock.shell.pt_completer.current_document.cursor_position_row = 1
|
|
shell_mock.shell.pt_completer.current_document.cursor_position_col = 5
|
|
monkeypatch.setattr(builtins.__xonsh__, "shell", shell_mock)
|
|
jedi_xontrib.complete_jedi("x", "x", 0, 1, {})
|
|
|
|
assert jedi_mock.Interpreter.call_args_list[0][0][0] == complete_document
|
|
assert jedi_mock.Interpreter().complete.call_args_list == [
|
|
call(2, 5) # line (one-indexed), column (zero-indexed)
|
|
]
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"completion, rich_completion",
|
|
[
|
|
(
|
|
# from jedi when code is 'x' and xx=3
|
|
(
|
|
"instance",
|
|
"xx",
|
|
"x",
|
|
"int(x=None, /) -> int",
|
|
("instance", "instance int"),
|
|
),
|
|
RichCompletion("x", display="xx", description="instance int"),
|
|
),
|
|
(
|
|
# from jedi when code is 'xx=3\nx'
|
|
("statement", "xx", "x", None, ("instance", "instance int")),
|
|
RichCompletion("x", display="xx", description="instance int"),
|
|
),
|
|
(
|
|
# from jedi when code is 'x.' and x=3
|
|
(
|
|
"function",
|
|
"from_bytes",
|
|
"from_bytes",
|
|
"from_bytes(bytes, byteorder, *, signed=False)",
|
|
("function", "def __get__"),
|
|
),
|
|
RichCompletion(
|
|
"from_bytes",
|
|
display="from_bytes()",
|
|
description="from_bytes(bytes, byteorder, *, signed=False)",
|
|
),
|
|
),
|
|
(
|
|
# from jedi when code is 'x=3\nx.'
|
|
("function", "imag", "imag", None, ("instance", "instance int")),
|
|
RichCompletion("imag", display="imag", description="instance int"),
|
|
),
|
|
(
|
|
# from '(3).from_bytes(byt'
|
|
("param", "bytes=", "es=", None, ("instance", "instance Sequence")),
|
|
RichCompletion("es=", display="bytes=", description="instance Sequence"),
|
|
),
|
|
(
|
|
# from 'x.from_bytes(byt' when x=3
|
|
("param", "bytes=", "es=", None, None),
|
|
RichCompletion("es=", display="bytes=", description="param"),
|
|
),
|
|
(
|
|
# from 'import colle'
|
|
("module", "collections", "ctions", None, ("module", "module collections")),
|
|
RichCompletion(
|
|
"ctions", display="collections", description="module collections"
|
|
),
|
|
),
|
|
(
|
|
# from 'NameErr'
|
|
(
|
|
"class",
|
|
"NameError",
|
|
"or",
|
|
"NameError(*args: object)",
|
|
("class", "class NameError"),
|
|
),
|
|
RichCompletion(
|
|
"or", display="NameError", description="NameError(*args: object)"
|
|
),
|
|
),
|
|
(
|
|
# from 'a["' when a={'name':None}
|
|
("string", '"name"', 'name"', None, None),
|
|
RichCompletion('name"', display='"name"', description="string"),
|
|
),
|
|
(
|
|
# from 'open("/etc/pass'
|
|
("path", 'passwd"', 'wd"', None, None),
|
|
RichCompletion('wd"', display='passwd"', description="path"),
|
|
),
|
|
(
|
|
# from 'cla'
|
|
("keyword", "class", "ss", None, None),
|
|
RichCompletion("ss", display="class", description="keyword"),
|
|
),
|
|
],
|
|
)
|
|
def test_rich_completions(jedi_xontrib, jedi_mock, completion, rich_completion):
|
|
comp_type, comp_name, comp_complete, sig, inf = completion
|
|
comp_mock = MagicMock()
|
|
comp_mock.type = comp_type
|
|
comp_mock.name = comp_name
|
|
comp_mock.complete = comp_complete
|
|
if sig:
|
|
sig_mock = MagicMock()
|
|
sig_mock.to_string.return_value = sig
|
|
comp_mock.get_signatures.return_value = [sig_mock]
|
|
else:
|
|
comp_mock.get_signatures.return_value = []
|
|
if inf:
|
|
inf_type, inf_desc = inf
|
|
inf_mock = MagicMock()
|
|
inf_mock.type = inf_type
|
|
inf_mock.description = inf_desc
|
|
comp_mock.infer.return_value = [inf_mock]
|
|
else:
|
|
comp_mock.infer.return_value = []
|
|
|
|
jedi_xontrib.XONSH_SPECIAL_TOKENS = []
|
|
jedi_mock.Interpreter().complete.return_value = [comp_mock]
|
|
completions = jedi_xontrib.complete_jedi("", "", 0, 0, {})
|
|
assert len(completions) == 1
|
|
(ret_completion,) = completions
|
|
assert isinstance(ret_completion, RichCompletion)
|
|
assert ret_completion == rich_completion
|
|
assert ret_completion.display == rich_completion.display
|
|
assert ret_completion.description == rich_completion.description
|
|
|
|
|
|
def test_special_tokens(jedi_xontrib):
|
|
assert (
|
|
jedi_xontrib.complete_jedi("", "", 0, 0, {})
|
|
== jedi_xontrib.XONSH_SPECIAL_TOKENS
|
|
)
|
|
assert jedi_xontrib.complete_jedi("@", "@", 0, 1, {}) == {"@", "@(", "@$("}
|
|
assert jedi_xontrib.complete_jedi("$", "$", 0, 1, {}) == {"$[", "${", "$("}
|