# -*- coding: utf-8 -*- """Tests the xonfig command. Actually, just a down payment on a full test. Currently exercises only these options: - xonfig info - xonfig jupyter_kernel """ import os import re import sys import json import pytest # noqa F401 from xonsh.tools import ON_WINDOWS from xonsh.xonfig import XONFIG_MAIN_ACTIONS, xonfig_main def test_xonfg_help(capsys, xonsh_builtins): """verify can invoke it, and usage knows about all the options""" with pytest.raises(SystemExit): xonfig_main(["-h"]) capout = capsys.readouterr().out pat = re.compile(r"^usage:\s*xonfig[^\n]*{([\w,-]+)}", re.MULTILINE) m = pat.match(capout) assert m[1] verbs = set(v.strip().lower() for v in m[1].split(",")) exp = set(v.lower() for v in XONFIG_MAIN_ACTIONS) assert verbs == exp @pytest.mark.parametrize( "args", [ ([]), ( [ "info", ] ), ], # NOQA E231 ) def test_xonfig_info(args, xonsh_builtins): """info works, and reports no jupyter if none in environment""" capout = xonfig_main(args) assert capout.startswith("+---") assert capout.endswith("---+\n") pat = re.compile(r".*on jupyter\s+\|\s+false", re.MULTILINE | re.IGNORECASE) m = pat.search(capout) assert m def strip_sep(path: str) -> str: """remove all path separators from argument""" retval = path.replace(os.sep, "") if ON_WINDOWS: retval = retval.replace(os.altsep, "") return retval @pytest.fixture def fake_lib(monkeypatch): """insulate sys.modules from hacking test modules may do with it. Apparently, monkeypath.syspath_prepend() doesn't flush imported modules, so they're still visible in other test cases. """ # get absolute path to fake_lib, assuming this test file itself is in same folder. fake_lib_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "fake_lib")) monkeypatch.syspath_prepend(fake_lib_path) yield # monkeypatch will have restored sys.path, but it's up to us to purge the imported modules fake_packages = tuple(f.name for f in os.scandir(fake_lib_path) if os.path.isdir(f)) modules_to_delete = [] for (m, mod) in sys.modules.items(): if m.startswith(fake_packages): if mod.__file__.startswith(fake_lib_path): modules_to_delete.append(m) # can't modify collection while iterating for m in modules_to_delete: del sys.modules[m] def test_xonfig_kernel_with_jupyter(monkeypatch, capsys, fake_lib, xonsh_builtins): cap_args = None cap_spec = None import jupyter_client.kernelspec # from fake_lib, hopefully. def mock_install_kernel_spec(*args, **kwargs): # arg[0] is self nonlocal cap_args nonlocal cap_spec cap_args = dict(args=args, kw=kwargs) spec_file = os.path.join(args[1], "kernel.json") cap_spec = json.load(open(spec_file, "r")) def mock_get_kernel_spec(*args, **kwargs): raise jupyter_client.kernelspec.NoSuchKernel monkeypatch.setattr( jupyter_client.kernelspec.KernelSpecManager, "install_kernel_spec", value=mock_install_kernel_spec, raising=False, ) monkeypatch.setattr( jupyter_client.kernelspec.KernelSpecManager, "get_kernel_spec", value=mock_get_kernel_spec, raising=False, ) rc = xonfig_main(["jupyter-kernel"]) assert rc == 0 capout = capsys.readouterr().out assert "Jupyter" in capout assert "xonsh" == cap_args["args"][2] assert cap_spec assert cap_spec["language"] == "xonsh" assert strip_sep(cap_spec["argv"][0]) == strip_sep(sys.executable) assert cap_spec["argv"][2] == "xonsh.jupyter_kernel" def test_xonfig_kernel_no_jupyter(capsys, xonsh_builtins): with pytest.raises(ImportError): rc = xonfig_main(["jupyter-kernel"]) # noqa F841