From 38295a1dd941451362d2e3d14dd29d94ba4f54ce Mon Sep 17 00:00:00 2001 From: Noorhteen Raja NJ Date: Thu, 20 May 2021 15:44:26 +0530 Subject: [PATCH] Remove globals (#4280) * refactor: remove usage of global variables in abbrevs.py * chore: add flake8-mutable to prevent mutable defaults * fix: abbrevs expand test * refactor: add xonsh session singleton * refactor: fix circular errors when using xonshSession as singleton * refactor: remove black magicked builtin attributes * style: black format tests as well * refactor: update tests to use xonsh-session singleton * refactor: update abbrevs to not use builtins * test: remove DummyCommandsCache and patch orig class * fix: failing test_command_completers * test: use monkeypatch to update xession fixture * fix: failing test_pipelines * fix: failing test_main * chore: run test suit as single invocation * test: fix tests/test_xonsh.xsh * refactor: remove builtins from docs/conf.py * fix: mypy error in jobs * fix: test error from test_main * test: close xession error in test_command_completers * chore: use pytest-cov for reporting coverage this will include subprocess calls, and will increase coverage * style: --- docs/conf.py | 15 +- requirements/tests.txt | 1 + run-tests.xsh | 24 +- setup.cfg | 7 +- tests/aliases/test_source.py | 26 +- tests/completers/test_base_completer.py | 16 +- tests/completers/test_bash_completer.py | 169 +++- tests/completers/test_command_completers.py | 33 +- tests/completers/test_completer_command.py | 34 +- tests/completers/test_dir_completers.py | 63 +- .../completers/test_environment_completer.py | 17 +- tests/completers/test_pip_completer.py | 30 +- tests/completers/test_xompletions.py | 41 +- tests/conftest.py | 171 ++-- tests/procs/test_specs.py | 4 +- tests/prompt/test_base.py | 44 +- tests/prompt/test_vc.py | 28 +- tests/test_aliases.py | 32 +- tests/test_ansi_colors.py | 2 +- tests/test_base_shell.py | 18 +- tests/test_bashisms.py | 4 +- tests/test_builtins.py | 6 +- tests/test_commands_cache.py | 27 +- tests/test_completer.py | 94 ++- tests/test_completion_context.py | 777 +++++++++++++----- tests/test_dirstack.py | 26 +- tests/test_dirstack_unc.py | 47 +- tests/test_environ.py | 46 +- tests/test_events.py | 4 +- tests/test_history_dummy.py | 13 +- tests/test_history_json.py | 100 ++- tests/test_history_sqlite.py | 72 +- tests/test_imphooks.py | 9 +- tests/test_integrations.py | 20 +- tests/test_jupyter_kernel.py | 22 +- tests/test_lexer.py | 27 +- tests/test_main.py | 93 +-- tests/test_man.py | 18 +- tests/test_parser.py | 8 +- tests/test_path_completers.py | 16 +- tests/test_pipelines.py | 80 +- tests/test_ptk_completer.py | 53 +- tests/test_ptk_highlight.py | 29 +- tests/test_ptk_multiline.py | 14 +- tests/test_pyghooks.py | 40 +- tests/test_python_completers.py | 115 ++- tests/test_shell.py | 66 +- tests/test_tools.py | 62 +- tests/test_vox.py | 78 +- tests/test_xonfig.py | 14 +- tests/test_xonsh.xsh | 10 +- tests/test_xoreutils.py | 6 +- tests/tools.py | 56 +- tests/xontribs/test_abbrevs.py | 9 +- tests/xontribs/test_jedi.py | 71 +- xonsh/aliases.py | 30 +- xonsh/ansi_colors.py | 6 +- xonsh/ast.py | 6 +- xonsh/base_shell.py | 26 +- xonsh/built_ins.py | 169 ++-- xonsh/codecache.py | 13 +- xonsh/commands_cache.py | 18 +- xonsh/completer.py | 4 +- xonsh/completers/_aliases.py | 4 +- xonsh/completers/bash.py | 6 +- xonsh/completers/commands.py | 7 +- xonsh/completers/completer.py | 29 +- xonsh/completers/environment.py | 5 +- xonsh/completers/man.py | 5 +- xonsh/completers/path.py | 21 +- xonsh/completers/python.py | 7 +- xonsh/completers/tools.py | 4 +- xonsh/contexts.py | 9 +- xonsh/dirstack.py | 18 +- xonsh/dumb_shell.py | 4 +- xonsh/environ.py | 21 +- xonsh/events.py | 8 +- xonsh/execer.py | 8 +- xonsh/foreign_shells.py | 14 +- xonsh/history/json.py | 35 +- xonsh/history/main.py | 12 +- xonsh/history/sqlite.py | 12 +- xonsh/imphooks.py | 10 +- xonsh/jobs.py | 38 +- xonsh/jupyter_kernel.py | 18 +- xonsh/jupyter_shell.py | 6 +- xonsh/main.py | 33 +- xonsh/platform.py | 9 +- xonsh/procs/pipelines.py | 32 +- xonsh/procs/posix.py | 4 +- xonsh/procs/proxies.py | 12 +- xonsh/procs/readers.py | 4 +- xonsh/procs/specs.py | 50 +- xonsh/prompt/base.py | 12 +- xonsh/prompt/cwd.py | 16 +- xonsh/prompt/env.py | 14 +- xonsh/prompt/gitstatus.py | 9 +- xonsh/prompt/times.py | 5 +- xonsh/prompt/vc.py | 28 +- xonsh/ptk_shell/completer.py | 8 +- xonsh/ptk_shell/history.py | 5 +- xonsh/ptk_shell/key_bindings.py | 21 +- xonsh/ptk_shell/shell.py | 24 +- xonsh/ptk_shell/updator.py | 8 +- xonsh/pyghooks.py | 33 +- xonsh/readline_shell.py | 32 +- xonsh/shell.py | 11 +- xonsh/style_tools.py | 9 +- xonsh/timings.py | 8 +- xonsh/tools.py | 91 +- xonsh/wizard.py | 6 +- xonsh/xonfig.py | 26 +- xonsh/xontribs.py | 6 +- xonsh/xoreutils/_which.py | 5 +- xonsh/xoreutils/cat.py | 4 +- xonsh/xoreutils/pwd.py | 3 +- xonsh/xoreutils/which.py | 18 +- xontrib/abbrevs.py | 94 +-- xontrib/autovox.py | 15 +- xontrib/bashisms.py | 47 +- xontrib/coreutils.py | 13 +- xontrib/distributed.py | 3 +- xontrib/free_cwd.py | 10 +- xontrib/jedi.py | 10 +- xontrib/mpl.py | 11 +- xontrib/mplhooks.py | 3 +- xontrib/prompt_ret_code.py | 12 +- xontrib/voxapi.py | 19 +- xontrib/whole_word_jumping.py | 4 +- xontrib/xog.py | 9 +- 130 files changed, 2452 insertions(+), 1824 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 72c3f7e7c..321eec234 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -27,22 +27,17 @@ from xonsh.environ import Env, Var, Xettings if tp.TYPE_CHECKING: from xonsh.environ import VarKeyType +from xonsh.built_ins import XSH from xonsh.xontribs_meta import get_xontribs from xonsh.commands_cache import CommandsCache import rst_helpers -if not hasattr(builtins, "__xonsh__"): - from argparse import Namespace - - builtins.__xonsh__ = Namespace() - builtins.__xonsh__.load = lambda *a, **kw: None - builtins.__xonsh__.link_builtins = lambda *a, **kw: None spec = importlib.util.find_spec("prompt_toolkit") if spec is not None: # hacky runaround to import PTK-specific events - builtins.__xonsh__.env = Env() + XSH.env = Env() from xonsh.ptk_shell.shell import events else: from xonsh.events import events @@ -452,9 +447,9 @@ def make_events(): make_xontribs() make_events() -builtins.__xonsh__.history = None -builtins.__xonsh__.env = {} -builtins.__xonsh__.commands_cache = CommandsCache() +XSH.history = None +XSH.env = {} +XSH.commands_cache = CommandsCache() def setup(app): diff --git a/requirements/tests.txt b/requirements/tests.txt index 675af3910..89d210808 100644 --- a/requirements/tests.txt +++ b/requirements/tests.txt @@ -2,6 +2,7 @@ py pytest>=6 flake8 flake8-docstrings +flake8-mutable pytest-cov pytest-timeout prompt-toolkit>=3.0 diff --git a/run-tests.xsh b/run-tests.xsh index 241b1c168..1a2da3531 100755 --- a/run-tests.xsh +++ b/run-tests.xsh @@ -24,42 +24,26 @@ def test(ns: argparse.Namespace): `xonsh run-tests.xsh -- --junitxml=junit/test-results.%%d.xml` """ - run_separately = [ - 'tests/test_main.py', - 'tests/test_ptk_highlight.py', - ] - - - ignores = [] - for fname in run_separately: - ignores.append('--ignore') - ignores.append(fname) - args = ns.pytest_args if ns.report_coverage: - ![coverage run -m pytest @(_replace_args(args, 0)) @(ignores)] - for index, fname in enumerate(run_separately): - ![coverage run --append -m pytest @(_replace_args(args, index+1)) @(fname)] - ![coverage report -m] - ![coverage xml] + ![pytest @(_replace_args(args, 0)) --cov --cov-report=xml --cov-report=term] else: - ![pytest @(_replace_args(args, 0)) @(ignores)] - for index, fname in enumerate(run_separately): - ![pytest @(_replace_args(args, index + 1)) @(fname)] + ![pytest @(_replace_args(args, 0))] def qa(ns: argparse.Namespace): """QA checks""" echo "---------- Check Black formatter -----------" - black --check xonsh xontrib + black --check xonsh xontrib tests echo "---------- Running flake8 ----------" python -m flake8 echo "---------- Running mypy ----------" mypy --version + # todo: add xontrib folder here mypy xonsh --exclude xonsh/ply diff --git a/setup.cfg b/setup.cfg index 97c5461c7..457c43a37 100644 --- a/setup.cfg +++ b/setup.cfg @@ -48,12 +48,7 @@ ignore = E402, # module level import not at top of file W503, # line break before binary operators is a good thing E731, # accept lambda assigned to a variable -# also acceptable in Xonsh project: reference to global names defined at runtime by black magic -builtins = - __xonsh__, - events, - aliases, - XonshError, + per-file-ignores = # flake8 gives incorrect unused import errors, F401 tests/tools.py:E128, diff --git a/tests/aliases/test_source.py b/tests/aliases/test_source.py index b38532b7d..86962b58e 100644 --- a/tests/aliases/test_source.py +++ b/tests/aliases/test_source.py @@ -1,9 +1,10 @@ import os.path import pytest +import builtins from contextlib import contextmanager from unittest.mock import MagicMock -from xonsh.aliases import source_alias, builtins +from xonsh.aliases import source_alias @pytest.fixture @@ -15,27 +16,26 @@ def mockopen(xonsh_builtins, monkeypatch): monkeypatch.setattr(builtins, "open", mocked_open) -def test_source_current_dir(mockopen, monkeypatch): +@pytest.fixture +def mocked_execx_checker(xession, monkeypatch): checker = [] def mocked_execx(src, *args, **kwargs): checker.append(src.strip()) - monkeypatch.setattr(builtins, "execx", mocked_execx) + monkeypatch.setattr(xession.builtins, "execx", mocked_execx) + return checker + + +def test_source_current_dir(mockopen, monkeypatch, mocked_execx_checker): monkeypatch.setattr(os.path, "isfile", lambda x: True) source_alias(["foo", "bar"]) - assert checker == ["foo", "bar"] + assert mocked_execx_checker == ["foo", "bar"] -def test_source_path(mockopen, monkeypatch): - checker = [] - - def mocked_execx(src, *args, **kwargs): - checker.append(src.strip()) - - monkeypatch.setattr(builtins, "execx", mocked_execx) +def test_source_path(mockopen, mocked_execx_checker): source_alias(["foo", "bar"]) path_foo = os.path.join("tests", "bin", "foo") path_bar = os.path.join("tests", "bin", "bar") - assert checker[0].endswith(path_foo) - assert checker[1].endswith(path_bar) + assert mocked_execx_checker[0].endswith(path_foo) + assert mocked_execx_checker[1].endswith(path_bar) diff --git a/tests/completers/test_base_completer.py b/tests/completers/test_base_completer.py index 6aff2db8b..06a37689d 100644 --- a/tests/completers/test_base_completer.py +++ b/tests/completers/test_base_completer.py @@ -10,20 +10,19 @@ from xonsh.parsers.completion_context import ( ) -CUR_DIR = "." if ON_WINDOWS else "./" # for some reason this is what happens in `complete_path` +CUR_DIR = ( + "." if ON_WINDOWS else "./" +) # for some reason this is what happens in `complete_path` @pytest.fixture(autouse=True) -def setup(xonsh_builtins, xonsh_execer, monkeypatch): - monkeypatch.setattr(xonsh_builtins.__xonsh__, "commands_cache", ["cool"]) +def setup(xession, xonsh_execer, monkeypatch): + monkeypatch.setattr(xession, "commands_cache", ["cool"]) def test_empty_line(): completions = complete_base( - CompletionContext( - command=CommandContext((), 0), - python=PythonContext("", 0) - ) + CompletionContext(command=CommandContext((), 0), python=PythonContext("", 0)) ) assert completions for exp in ["cool", "abs"]: @@ -33,8 +32,7 @@ def test_empty_line(): def test_empty_subexpr(): completions = complete_base( CompletionContext( - command=CommandContext((), 0, subcmd_opening="$("), - python=None + command=CommandContext((), 0, subcmd_opening="$("), python=None ) ) assert completions diff --git a/tests/completers/test_bash_completer.py b/tests/completers/test_bash_completer.py index 38a2914ce..1714d45b9 100644 --- a/tests/completers/test_bash_completer.py +++ b/tests/completers/test_bash_completer.py @@ -4,70 +4,163 @@ from tests.tools import skip_if_on_windows, skip_if_on_darwin from xonsh.completers.tools import RichCompletion from xonsh.completers.bash import complete_from_bash -from xonsh.parsers.completion_context import CompletionContext, CommandContext, CommandArg +from xonsh.parsers.completion_context import ( + CompletionContext, + CommandContext, + CommandArg, +) @pytest.fixture(autouse=True) -def setup(monkeypatch, tmp_path, xonsh_builtins): - if not xonsh_builtins.__xonsh__.env.get("BASH_COMPLETIONS"): - monkeypatch.setitem(xonsh_builtins.__xonsh__.env, "BASH_COMPLETIONS", ["/usr/share/bash-completion/bash_completion"]) +def setup(monkeypatch, tmp_path, xession): + if not xession.env.get("BASH_COMPLETIONS"): + monkeypatch.setitem( + xession.env, + "BASH_COMPLETIONS", + ["/usr/share/bash-completion/bash_completion"], + ) (tmp_path / "testdir").mkdir() (tmp_path / "spaced dir").mkdir() monkeypatch.chdir(str(tmp_path)) - @skip_if_on_darwin @skip_if_on_windows -@pytest.mark.parametrize("command_context, completions, lprefix", ( - (CommandContext(args=(CommandArg("bash"),), arg_index=1, prefix="--deb"), {"--debug", "--debugger"}, 5), - (CommandContext(args=(CommandArg("ls"),), arg_index=1, prefix=""), {"'testdir/'", "'spaced dir/'"}, 0), - (CommandContext(args=(CommandArg("ls"),), arg_index=1, prefix="", opening_quote="'"), {"'testdir/'", "'spaced dir/'"}, 1), -)) +@pytest.mark.parametrize( + "command_context, completions, lprefix", + ( + ( + CommandContext(args=(CommandArg("bash"),), arg_index=1, prefix="--deb"), + {"--debug", "--debugger"}, + 5, + ), + ( + CommandContext(args=(CommandArg("ls"),), arg_index=1, prefix=""), + {"'testdir/'", "'spaced dir/'"}, + 0, + ), + ( + CommandContext( + args=(CommandArg("ls"),), arg_index=1, prefix="", opening_quote="'" + ), + {"'testdir/'", "'spaced dir/'"}, + 1, + ), + ), +) def test_bash_completer(command_context, completions, lprefix): - bash_completions, bash_lprefix = complete_from_bash(CompletionContext(command_context)) + bash_completions, bash_lprefix = complete_from_bash( + CompletionContext(command_context) + ) assert bash_completions == completions and bash_lprefix == lprefix @skip_if_on_darwin @skip_if_on_windows -@pytest.mark.parametrize("command_context, completions, lprefix", ( +@pytest.mark.parametrize( + "command_context, completions, lprefix", + ( # ls /pro -> ls /proc/ - (CommandContext(args=(CommandArg("ls"),), arg_index=1, prefix="/pro"), {"/proc/"}, 4), - + ( + CommandContext(args=(CommandArg("ls"),), arg_index=1, prefix="/pro"), + {"/proc/"}, + 4, + ), # ls '/pro -> ls '/proc/' - (CommandContext(args=(CommandArg("ls"),), arg_index=1, prefix="/pro", opening_quote="'"), {"'/proc/'"}, 5), - + ( + CommandContext( + args=(CommandArg("ls"),), arg_index=1, prefix="/pro", opening_quote="'" + ), + {"'/proc/'"}, + 5, + ), # ls '/pro' -> ls '/proc/' - (CommandContext(args=(CommandArg("ls"),), arg_index=1, prefix="/pro", opening_quote="'", closing_quote="'"), - {"'/proc/"}, 5), - + ( + CommandContext( + args=(CommandArg("ls"),), + arg_index=1, + prefix="/pro", + opening_quote="'", + closing_quote="'", + ), + {"'/proc/"}, + 5, + ), # ls '/pro' -> ls '/proc/' - (CommandContext(args=(CommandArg("ls"),), arg_index=1, prefix="/pro", opening_quote="'", closing_quote="'", - is_after_closing_quote=True), {"'/proc/'"}, 6), - + ( + CommandContext( + args=(CommandArg("ls"),), + arg_index=1, + prefix="/pro", + opening_quote="'", + closing_quote="'", + is_after_closing_quote=True, + ), + {"'/proc/'"}, + 6, + ), # ls """/pro""" -> ls """/proc/""" - (CommandContext(args=(CommandArg("ls"),), arg_index=1, prefix="/pro", opening_quote='"""', closing_quote='"""', - is_after_closing_quote=True), {'"""/proc/"""'}, 10), - + ( + CommandContext( + args=(CommandArg("ls"),), + arg_index=1, + prefix="/pro", + opening_quote='"""', + closing_quote='"""', + is_after_closing_quote=True, + ), + {'"""/proc/"""'}, + 10, + ), # Completions that have to be quoted: - # ls ./sp -> ls './spaced dir/' - (CommandContext(args=(CommandArg("ls"),), arg_index=1, prefix="./sp"), {"'./spaced dir/'"}, 4), - + ( + CommandContext(args=(CommandArg("ls"),), arg_index=1, prefix="./sp"), + {"'./spaced dir/'"}, + 4, + ), # ls './sp -> ls './spaced dir/' - (CommandContext(args=(CommandArg("ls"),), arg_index=1, prefix="./sp", opening_quote="'"), {"'./spaced dir/'"}, 5), - + ( + CommandContext( + args=(CommandArg("ls"),), arg_index=1, prefix="./sp", opening_quote="'" + ), + {"'./spaced dir/'"}, + 5, + ), # ls './sp' -> ls './spaced dir/' - (CommandContext(args=(CommandArg("ls"),), arg_index=1, prefix="./sp", opening_quote="'", closing_quote="'"), - {"'./spaced dir/"}, 5), - + ( + CommandContext( + args=(CommandArg("ls"),), + arg_index=1, + prefix="./sp", + opening_quote="'", + closing_quote="'", + ), + {"'./spaced dir/"}, + 5, + ), # ls './sp' -> ls './spaced dir/' - (CommandContext(args=(CommandArg("ls"),), arg_index=1, prefix="./sp", opening_quote="'", closing_quote="'", - is_after_closing_quote=True), {"'./spaced dir/'"}, 6), -)) + ( + CommandContext( + args=(CommandArg("ls"),), + arg_index=1, + prefix="./sp", + opening_quote="'", + closing_quote="'", + is_after_closing_quote=True, + ), + {"'./spaced dir/'"}, + 6, + ), + ), +) def test_quote_handling(command_context, completions, lprefix): - bash_completions, bash_lprefix = complete_from_bash(CompletionContext(command_context)) + bash_completions, bash_lprefix = complete_from_bash( + CompletionContext(command_context) + ) assert bash_completions == completions and bash_lprefix == lprefix - assert all(isinstance(comp, RichCompletion) and not comp.append_closing_quote for comp in bash_completions) # make sure the completer handles the closing quote by itself + assert all( + isinstance(comp, RichCompletion) and not comp.append_closing_quote + for comp in bash_completions + ) # make sure the completer handles the closing quote by itself diff --git a/tests/completers/test_command_completers.py b/tests/completers/test_command_completers.py index 3d5ef6344..50abfc710 100644 --- a/tests/completers/test_command_completers.py +++ b/tests/completers/test_command_completers.py @@ -1,6 +1,12 @@ from unittest.mock import Mock -from xonsh.parsers.completion_context import CompletionContext, CommandArg, CommandContext +import pytest + +from xonsh.parsers.completion_context import ( + CompletionContext, + CommandArg, + CommandContext, +) from tests.tools import ON_WINDOWS, skip_if_on_windows, completions_from_result @@ -8,6 +14,12 @@ from xonsh.completer import Completer from xonsh.completers.commands import complete_command, complete_skipper +@pytest.fixture(autouse=True) +def xs_orig_commands_cache(xession, monkeypatch, xonsh_execer): + xession.unload() + xession.load(execer=xonsh_execer) + + def test_complete_command(completion_context_parse): if ON_WINDOWS: command = "dir.exe" @@ -15,29 +27,34 @@ def test_complete_command(completion_context_parse): command = "grep" assert command in complete_command( - completion_context_parse(command[:-1], len(command) - 1).command) + completion_context_parse(command[:-1], len(command) - 1).command + ) @skip_if_on_windows def test_skipper_command(completion_context_parse): assert "grep" in completions_from_result( - complete_skipper(completion_context_parse("sudo gre", 8))) + complete_skipper(completion_context_parse("sudo gre", 8)) + ) @skip_if_on_windows -def test_skipper_arg(completion_context_parse, xonsh_builtins, monkeypatch): - monkeypatch.setattr(xonsh_builtins.__xonsh__.shell.shell, "completer", Completer(), raising=False) +def test_skipper_arg(completion_context_parse, xession, monkeypatch): + monkeypatch.setattr(xession.shell.shell, "completer", Completer(), raising=False) bash_completer_mock = Mock() - monkeypatch.setattr(xonsh_builtins.__xonsh__, "completers", {"bash": bash_completer_mock}) + monkeypatch.setattr(xession, "completers", {"bash": bash_completer_mock}) bash_completer_mock.return_value = {"--count "} assert "--count " in completions_from_result( - complete_skipper(completion_context_parse(f"sudo grep --coun", 16))) + complete_skipper(completion_context_parse(f"sudo grep --coun", 16)) + ) call_args = bash_completer_mock.call_args[0] assert len(call_args) == 1 context = call_args[0] assert isinstance(context, CompletionContext) - assert context.command == CommandContext(args=(CommandArg("grep"),), arg_index=1, prefix="--coun") + assert context.command == CommandContext( + args=(CommandArg("grep"),), arg_index=1, prefix="--coun" + ) diff --git a/tests/completers/test_completer_command.py b/tests/completers/test_completer_command.py index b1affa0cb..fc3bc5705 100644 --- a/tests/completers/test_completer_command.py +++ b/tests/completers/test_completer_command.py @@ -1,14 +1,34 @@ -from xonsh.parsers.completion_context import CommandArg, CommandContext, CompletionContext +from xonsh.parsers.completion_context import ( + CommandArg, + CommandContext, + CompletionContext, +) from xonsh.completers.completer import complete_completer def test_options(): - assert complete_completer(CompletionContext(CommandContext( - args=(CommandArg("completer"),), arg_index=1, - ))) == {"add", "remove", "list", "help"} + assert ( + complete_completer( + CompletionContext( + CommandContext( + args=(CommandArg("completer"),), + arg_index=1, + ) + ) + ) + == {"add", "remove", "list", "help"} + ) def test_help_options(): - assert complete_completer(CompletionContext(CommandContext( - args=(CommandArg("completer"),CommandArg("help")), arg_index=2, - ))) == {"add", "remove", "list"} + assert ( + complete_completer( + CompletionContext( + CommandContext( + args=(CommandArg("completer"), CommandArg("help")), + arg_index=2, + ) + ) + ) + == {"add", "remove", "list"} + ) diff --git a/tests/completers/test_dir_completers.py b/tests/completers/test_dir_completers.py index b6ed34d35..ac04cc395 100644 --- a/tests/completers/test_dir_completers.py +++ b/tests/completers/test_dir_completers.py @@ -6,7 +6,9 @@ from os import sep from xonsh.completers.tools import RichCompletion from xonsh.completers.dirs import complete_cd, complete_rmdir from xonsh.parsers.completion_context import ( - CompletionContext, CommandContext, CommandArg, + CompletionContext, + CommandContext, + CommandArg, ) from tests.tools import ON_WINDOWS @@ -19,11 +21,12 @@ COMPLETERS = { CUR_DIR = "." if ON_WINDOWS else "./" PARENT_DIR = ".." if ON_WINDOWS else "../" + @pytest.fixture(autouse=True) -def setup(xonsh_builtins, xonsh_execer): +def setup(xession, xonsh_execer): with tempfile.TemporaryDirectory() as tmp: - xonsh_builtins.__xonsh__.env["XONSH_DATA_DIR"] = tmp - xonsh_builtins.__xonsh__.env["CDPATH"] = set() + xession.env["XONSH_DATA_DIR"] = tmp + xession.env["CDPATH"] = set() @pytest.fixture(params=list(COMPLETERS)) @@ -33,20 +36,34 @@ def cmd(request): def test_not_cmd(cmd): """Ensure the cd completer doesn't complete other commands""" - assert not COMPLETERS[cmd](CompletionContext(CommandContext( - args=(CommandArg(f"not-{cmd}"),), arg_index=1, - ))) + assert not COMPLETERS[cmd]( + CompletionContext( + CommandContext( + args=(CommandArg(f"not-{cmd}"),), + arg_index=1, + ) + ) + ) def complete_cmd(cmd, prefix, opening_quote="", closing_quote=""): - result = COMPLETERS[cmd](CompletionContext(CommandContext( - args=(CommandArg(cmd),), arg_index=1, prefix=prefix, - opening_quote=opening_quote, closing_quote=closing_quote, - is_after_closing_quote=bool(closing_quote), - ))) + result = COMPLETERS[cmd]( + CompletionContext( + CommandContext( + args=(CommandArg(cmd),), + arg_index=1, + prefix=prefix, + opening_quote=opening_quote, + closing_quote=closing_quote, + is_after_closing_quote=bool(closing_quote), + ) + ) + ) assert result and len(result) == 2 completions, lprefix = result - assert lprefix == len(opening_quote) + len(prefix) + len(closing_quote) # should override the quotes + assert lprefix == len(opening_quote) + len(prefix) + len( + closing_quote + ) # should override the quotes return completions @@ -92,24 +109,24 @@ def test_closing_quotes(cmd, dir_path): assert completion.append_closing_quote is False -def test_complete_dots(xonsh_builtins): - with xonsh_builtins.__xonsh__.env.swap(COMPLETE_DOTS='never'): - dirs = complete_cmd_dirs('cd', '') +def test_complete_dots(xession): + with xession.env.swap(COMPLETE_DOTS="never"): + dirs = complete_cmd_dirs("cd", "") assert CUR_DIR not in dirs and PARENT_DIR not in dirs - dirs = complete_cmd_dirs('cd', '.') + dirs = complete_cmd_dirs("cd", ".") assert CUR_DIR not in dirs and PARENT_DIR not in dirs - with xonsh_builtins.__xonsh__.env.swap(COMPLETE_DOTS='matching'): - dirs = complete_cmd_dirs('cd', '') + with xession.env.swap(COMPLETE_DOTS="matching"): + dirs = complete_cmd_dirs("cd", "") assert CUR_DIR not in dirs and PARENT_DIR not in dirs - dirs = complete_cmd_dirs('cd', '.') + dirs = complete_cmd_dirs("cd", ".") assert CUR_DIR in dirs and PARENT_DIR in dirs - with xonsh_builtins.__xonsh__.env.swap(COMPLETE_DOTS='always'): - dirs = complete_cmd_dirs('cd', '') + with xession.env.swap(COMPLETE_DOTS="always"): + dirs = complete_cmd_dirs("cd", "") assert CUR_DIR in dirs and PARENT_DIR in dirs - dirs = complete_cmd_dirs('cd', '.') + dirs = complete_cmd_dirs("cd", ".") assert CUR_DIR in dirs and PARENT_DIR in dirs diff --git a/tests/completers/test_environment_completer.py b/tests/completers/test_environment_completer.py index 91252d203..e873f5992 100644 --- a/tests/completers/test_environment_completer.py +++ b/tests/completers/test_environment_completer.py @@ -9,13 +9,16 @@ def parser(): return CompletionContextParser() -@pytest.mark.parametrize("cmd", ( - "ls $WO", - "ls /home/$WO", - "ls @('hi ' + $WO", -)) -def test_simple(cmd, xonsh_builtins, monkeypatch, parser): - monkeypatch.setitem(xonsh_builtins.__xonsh__.env, "WOW", 1) +@pytest.mark.parametrize( + "cmd", + ( + "ls $WO", + "ls /home/$WO", + "ls @('hi ' + $WO", + ), +) +def test_simple(cmd, xession, monkeypatch, parser): + monkeypatch.setitem(xession.env, "WOW", 1) context = parser.parse(cmd, len(cmd)) assert complete_environment_vars(context) == ({"$WOW"}, 3) diff --git a/tests/completers/test_pip_completer.py b/tests/completers/test_pip_completer.py index 57a18a9e8..1364f119d 100644 --- a/tests/completers/test_pip_completer.py +++ b/tests/completers/test_pip_completer.py @@ -2,7 +2,11 @@ import pytest from xonsh.completers.tools import RichCompletion from xonsh.completers.pip import PIP_RE, complete_pip -from xonsh.parsers.completion_context import CompletionContext, CommandContext, CommandArg +from xonsh.parsers.completion_context import ( + CompletionContext, + CommandContext, + CommandArg, +) @pytest.mark.parametrize( @@ -31,10 +35,15 @@ def test_pip_list_re1(line): def test_commands(): - comps = complete_pip(CompletionContext(CommandContext( - args=(CommandArg("pip3"),), arg_index=1, - prefix="c", - ))) + comps = complete_pip( + CompletionContext( + CommandContext( + args=(CommandArg("pip3"),), + arg_index=1, + prefix="c", + ) + ) + ) assert comps.intersection({"cache", "check", "config"}) for comp in comps: assert isinstance(comp, RichCompletion) @@ -42,9 +51,14 @@ def test_commands(): def test_package_list(): - comps = complete_pip(CompletionContext(CommandContext( - args=(CommandArg("pip3"), CommandArg("show")), arg_index=2, - ))) + comps = complete_pip( + CompletionContext( + CommandContext( + args=(CommandArg("pip3"), CommandArg("show")), + arg_index=2, + ) + ) + ) assert "Package" not in comps assert "-----------------------------" not in comps assert "pytest" in comps diff --git a/tests/completers/test_xompletions.py b/tests/completers/test_xompletions.py index 054698063..3d012d321 100644 --- a/tests/completers/test_xompletions.py +++ b/tests/completers/test_xompletions.py @@ -1,21 +1,40 @@ -from xonsh.parsers.completion_context import CommandArg, CommandContext, CompletionContext +from xonsh.parsers.completion_context import ( + CommandArg, + CommandContext, + CompletionContext, +) from xonsh.completers.xompletions import complete_xonfig, complete_xontrib def test_xonfig(): - assert complete_xonfig(CompletionContext(CommandContext( - args=(CommandArg("xonfig"),), arg_index=1, prefix="-" - ))) == {"-h"} + assert complete_xonfig( + CompletionContext( + CommandContext(args=(CommandArg("xonfig"),), arg_index=1, prefix="-") + ) + ) == {"-h"} def test_xonfig_colors(monkeypatch): - monkeypatch.setattr("xonsh.tools.color_style_names", lambda: ["blue", "brown", "other"]) - assert complete_xonfig(CompletionContext(CommandContext( - args=(CommandArg("xonfig"), CommandArg("colors")), arg_index=2, prefix="b" - ))) == {"blue", "brown"} + monkeypatch.setattr( + "xonsh.tools.color_style_names", lambda: ["blue", "brown", "other"] + ) + assert ( + complete_xonfig( + CompletionContext( + CommandContext( + args=(CommandArg("xonfig"), CommandArg("colors")), + arg_index=2, + prefix="b", + ) + ) + ) + == {"blue", "brown"} + ) def test_xontrib(): - assert complete_xontrib(CompletionContext(CommandContext( - args=(CommandArg("xontrib"),), arg_index=1, prefix="l" - ))) == {"list", "load"} + assert complete_xontrib( + CompletionContext( + CommandContext(args=(CommandArg("xontrib"),), arg_index=1, prefix="l") + ) + ) == {"list", "load"} diff --git a/tests/conftest.py b/tests/conftest.py index b8e200493..a51d63160 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,30 +2,21 @@ import builtins import glob import os import sys +import types +import typing as tp +from unittest.mock import MagicMock import pytest -from xonsh.built_ins import ( - ensure_list_of_strs, - XonshSession, - pathsearch, - globsearch, - regexsearch, - list_of_strs_or_callables, - list_of_list_of_strs_outer_product, - call_macro, - enter_macro, - path_literal, - _BuiltIns, - eval_fstring_field, -) +from xonsh.built_ins import XonshSession, XSH from xonsh.execer import Execer from xonsh.jobs import tasks from xonsh.events import events from xonsh.platform import ON_WINDOWS from xonsh.parsers.completion_context import CompletionContextParser -from tools import DummyShell, sp, DummyCommandsCache, DummyEnv, DummyHistory +from xonsh import commands_cache +from tools import DummyShell, sp, DummyEnv, DummyHistory @pytest.fixture @@ -35,54 +26,26 @@ def source_path(): return os.path.dirname(pwd) -def ensure_attached_session(monkeypatch, session): - for i in range(1, 11): - - # next try to monkey patch with raising. - try: - monkeypatch.setattr(builtins, "__xonsh__", session, raising=True) - except AttributeError: - pass - if hasattr(builtins, "__xonsh__"): - break - # first try to monkey patch without raising. - try: - monkeypatch.setattr(builtins, "__xonsh__", session, raising=False) - except AttributeError: - pass - if hasattr(builtins, "__xonsh__"): - break - # now just try to apply it - builtins.__xonsh__ = session - if hasattr(builtins, "__xonsh__"): - break - # I have no idea why pytest fails to assign into the builtins module - # sometimes, but the following globals trick seems to work -scopatz - globals()["__builtins__"]["__xonsh__"] = session - if hasattr(builtins, "__xonsh__"): - break - else: - raise RuntimeError( - "Could not attach xonsh session to builtins " "after many tries!" - ) - - @pytest.fixture def xonsh_execer(monkeypatch): """Initiate the Execer with a mocked nop `load_builtins`""" - monkeypatch.setattr( - "xonsh.built_ins.load_builtins.__code__", - (lambda *args, **kwargs: None).__code__, - ) - added_session = False - if not hasattr(builtins, "__xonsh__"): - added_session = True - ensure_attached_session(monkeypatch, XonshSession()) execer = Execer(unload=False) - builtins.__xonsh__.execer = execer + monkeypatch.setattr(XSH, "execer", execer) yield execer - if added_session: - monkeypatch.delattr(builtins, "__xonsh__", raising=False) + + +@pytest.fixture +def patch_commands_cache_bins(xession, tmp_path, monkeypatch): + def _factory(binaries: tp.List[str]): + if not xession.env.get("PATH"): + xession.env["PATH"] = [tmp_path] + exec_mock = MagicMock(return_value=binaries) + monkeypatch.setattr(commands_cache, "executables_in", exec_mock) + cc = commands_cache.CommandsCache() + xession.commands_cache = cc + return cc + + return _factory @pytest.fixture @@ -107,60 +70,60 @@ def xonsh_events(): def xonsh_builtins(monkeypatch, xonsh_events): """Mock out most of the builtins xonsh attributes.""" old_builtins = set(dir(builtins)) - execer = getattr(getattr(builtins, "__xonsh__", None), "execer", None) - session = XonshSession(execer=execer, ctx={}) - ensure_attached_session(monkeypatch, session) - builtins.__xonsh__.env = DummyEnv() - if ON_WINDOWS: - builtins.__xonsh__.env["PATHEXT"] = [".EXE", ".BAT", ".CMD"] - builtins.__xonsh__.shell = DummyShell() - builtins.__xonsh__.help = lambda x: x - builtins.__xonsh__.glob = glob.glob - builtins.__xonsh__.exit = False - builtins.__xonsh__.superhelp = lambda x: x - builtins.__xonsh__.pathsearch = pathsearch - builtins.__xonsh__.globsearch = globsearch - builtins.__xonsh__.regexsearch = regexsearch - builtins.__xonsh__.regexpath = lambda x: [] - builtins.__xonsh__.expand_path = lambda x: x - builtins.__xonsh__.subproc_captured = sp - builtins.__xonsh__.subproc_uncaptured = sp - builtins.__xonsh__.stdout_uncaptured = None - builtins.__xonsh__.stderr_uncaptured = None - builtins.__xonsh__.ensure_list_of_strs = ensure_list_of_strs - builtins.__xonsh__.commands_cache = DummyCommandsCache() - builtins.__xonsh__.all_jobs = {} - builtins.__xonsh__.list_of_strs_or_callables = list_of_strs_or_callables - builtins.__xonsh__.list_of_list_of_strs_outer_product = ( - list_of_list_of_strs_outer_product + XSH.load( + execer=Execer(unload=False), + ctx={}, ) - builtins.__xonsh__.eval_fstring_field = eval_fstring_field - builtins.__xonsh__.history = DummyHistory() - builtins.__xonsh__.subproc_captured_stdout = sp - builtins.__xonsh__.subproc_captured_inject = sp - builtins.__xonsh__.subproc_captured_object = sp - builtins.__xonsh__.subproc_captured_hiddenobject = sp - builtins.__xonsh__.enter_macro = enter_macro - builtins.__xonsh__.completers = None - builtins.__xonsh__.call_macro = call_macro - builtins.__xonsh__.enter_macro = enter_macro - builtins.__xonsh__.path_literal = path_literal - builtins.__xonsh__.builtins = _BuiltIns(execer=execer) - builtins.evalx = eval - builtins.execx = None - builtins.compilex = None - builtins.aliases = {} - # Unlike all the other stuff, this has to refer to the "real" one because all modules that would - # be firing events on the global instance. - builtins.events = xonsh_events + if ON_WINDOWS: + XSH.env["PATHEXT"] = [".EXE", ".BAT", ".CMD"] + + def locate_binary(self, name): + return os.path.join(os.path.dirname(__file__), "bin", name) + + for attr, val in [ + ("env", DummyEnv()), + ("shell", DummyShell()), + ("help", lambda x: x), + ("aliases", {}), + ("exit", False), + ("history", DummyHistory()), + # ("subproc_captured", sp), + ("subproc_uncaptured", sp), + ("subproc_captured_stdout", sp), + ("subproc_captured_inject", sp), + ("subproc_captured_object", sp), + ("subproc_captured_hiddenobject", sp), + ]: + monkeypatch.setattr(XSH, attr, val) + + cc = XSH.commands_cache + monkeypatch.setattr(cc, "locate_binary", types.MethodType(locate_binary, cc)) + + for attr, val in [ + ("evalx", eval), + ("execx", None), + ("compilex", None), + # Unlike all the other stuff, this has to refer to the "real" one because all modules that would + # be firing events on the global instance. + ("events", xonsh_events), + ]: + # attributes to builtins are dynamicProxy and should pickup the following + monkeypatch.setattr(XSH.builtins, attr, val) + + # todo: remove using builtins for tests at all yield builtins - monkeypatch.delattr(builtins, "__xonsh__", raising=False) + XSH.unload() for attr in set(dir(builtins)) - old_builtins: if hasattr(builtins, attr): delattr(builtins, attr) tasks.clear() # must to this to enable resetting all_jobs +@pytest.fixture +def xession(xonsh_builtins) -> XonshSession: + return XSH + + @pytest.fixture(scope="session") def completion_context_parse(): return CompletionContextParser().parse diff --git a/tests/procs/test_specs.py b/tests/procs/test_specs.py index f753a00c3..7eed00552 100644 --- a/tests/procs/test_specs.py +++ b/tests/procs/test_specs.py @@ -13,8 +13,8 @@ from .tools import skip_if_on_windows @skip_if_on_windows -def test_cmds_to_specs_thread_subproc(xonsh_builtins): - env = xonsh_builtins.__xonsh__.env +def test_cmds_to_specs_thread_subproc(xession): + env = xession.env cmds = [["pwd"]] # First check that threadable subprocs become threadable env["THREAD_SUBPROCS"] = True diff --git a/tests/prompt/test_base.py b/tests/prompt/test_base.py index 1b4118347..55251cbeb 100644 --- a/tests/prompt/test_base.py +++ b/tests/prompt/test_base.py @@ -7,7 +7,7 @@ from xonsh.prompt.base import PromptFormatter, PROMPT_FIELDS @pytest.fixture -def formatter(xonsh_builtins): +def formatter(xession): return PromptFormatter() @@ -75,8 +75,8 @@ def test_format_prompt_with_broken_template_in_func(inp, formatter): assert "{user" in formatter(lambda: inp) -def test_format_prompt_with_invalid_func(formatter, xonsh_builtins): - xonsh_builtins.__xonsh__.env = Env() +def test_format_prompt_with_invalid_func(formatter, xession): + xession.env = Env() def p(): foo = bar # raises exception # noqa @@ -85,8 +85,8 @@ def test_format_prompt_with_invalid_func(formatter, xonsh_builtins): assert isinstance(formatter(p), str) -def test_format_prompt_with_func_that_raises(formatter, capsys, xonsh_builtins): - xonsh_builtins.__xonsh__.env = Env() +def test_format_prompt_with_func_that_raises(formatter, capsys, xession): + xession.env = Env() template = "tt {zerodiv} tt" exp = "tt {BACKGROUND_RED}{ERROR:zerodiv}{RESET} tt" fields = {"zerodiv": lambda: 1 / 0} @@ -96,25 +96,23 @@ def test_format_prompt_with_func_that_raises(formatter, capsys, xonsh_builtins): assert "prompt: error" in err -def test_format_prompt_with_no_env(formatter, xonsh_builtins, live_fields): - xonsh_builtins.__xonsh__.shell.prompt_formatter = formatter +def test_format_prompt_with_no_env(formatter, xession, live_fields): + xession.shell.prompt_formatter = formatter env = Env() env.pop("VIRTUAL_ENV", None) # For virtualenv env.pop("CONDA_DEFAULT_ENV", None) # For conda/CircleCI - xonsh_builtins.__xonsh__.env = env + xession.env = env assert formatter("{env_name}", fields=live_fields) == "" @pytest.mark.parametrize("envname", ["env", "foo", "bar"]) -def test_format_prompt_with_various_envs( - formatter, xonsh_builtins, live_fields, envname -): - xonsh_builtins.__xonsh__.shell.prompt_formatter = formatter +def test_format_prompt_with_various_envs(formatter, xession, live_fields, envname): + xession.shell.prompt_formatter = formatter env = Env(VIRTUAL_ENV=envname) - xonsh_builtins.__xonsh__.env = env + xession.env = env exp = live_fields["env_prefix"] + envname + live_fields["env_postfix"] assert formatter("{env_name}", fields=live_fields) == exp @@ -122,13 +120,11 @@ def test_format_prompt_with_various_envs( @pytest.mark.parametrize("pre", ["(", "[[", "", " "]) @pytest.mark.parametrize("post", [")", "]]", "", " "]) -def test_format_prompt_with_various_prepost( - formatter, xonsh_builtins, live_fields, pre, post -): - xonsh_builtins.__xonsh__.shell.prompt_formatter = formatter +def test_format_prompt_with_various_prepost(formatter, xession, live_fields, pre, post): + xession.shell.prompt_formatter = formatter env = Env(VIRTUAL_ENV="env") - xonsh_builtins.__xonsh__.env = env + xession.env = env live_fields.update({"env_prefix": pre, "env_postfix": post}) @@ -136,26 +132,26 @@ def test_format_prompt_with_various_prepost( assert formatter("{env_name}", fields=live_fields) == exp -def test_noenv_with_disable_set(formatter, xonsh_builtins, live_fields): - xonsh_builtins.__xonsh__.shell.prompt_formatter = formatter +def test_noenv_with_disable_set(formatter, xession, live_fields): + xession.shell.prompt_formatter = formatter env = Env(VIRTUAL_ENV="env", VIRTUAL_ENV_DISABLE_PROMPT=1) - xonsh_builtins.__xonsh__.env = env + xession.env = env exp = "" assert formatter("{env_name}", fields=live_fields) == exp @pytest.mark.parametrize("disable", [0, 1]) -def test_custom_env_overrides_default(formatter, xonsh_builtins, live_fields, disable): - xonsh_builtins.__xonsh__.shell.prompt_formatter = formatter +def test_custom_env_overrides_default(formatter, xession, live_fields, disable): + xession.shell.prompt_formatter = formatter prompt = "!venv active! " env = Env( VIRTUAL_ENV="env", VIRTUAL_ENV_PROMPT=prompt, VIRTUAL_ENV_DISABLE_PROMPT=disable ) - xonsh_builtins.__xonsh__.env = env + xession.env = env exp = "" if disable else prompt assert formatter("{env_name}", fields=live_fields) == exp diff --git a/tests/prompt/test_vc.py b/tests/prompt/test_vc.py index 52ed43f5d..b4589b8e0 100644 --- a/tests/prompt/test_vc.py +++ b/tests/prompt/test_vc.py @@ -53,14 +53,14 @@ def test_test_repo(test_repo): assert test_file.exists() -def test_no_repo(xonsh_builtins, tmpdir): - xonsh_builtins.__xonsh__.env = Env(VC_BRANCH_TIMEOUT=2, PWD=tmpdir) +def test_no_repo(xession, tmpdir): + xession.env = Env(VC_BRANCH_TIMEOUT=2, PWD=tmpdir) assert vc.get_hg_branch() is None assert vc.get_git_branch() is None -def test_vc_get_branch(test_repo, xonsh_builtins): - xonsh_builtins.__xonsh__.env = Env(VC_BRANCH_TIMEOUT=2, PWD=test_repo["dir"]) +def test_vc_get_branch(test_repo, xession): + xession.env = Env(VC_BRANCH_TIMEOUT=2, PWD=test_repo["dir"]) # get corresponding function from vc module get_branch = "get_{}_branch".format(test_repo["vc"]) branch = getattr(vc, get_branch)() @@ -84,9 +84,9 @@ current = yellow reverse assert not branch.startswith(u"\u001b[") -def test_current_branch_calls_locate_binary_for_empty_cmds_cache(xonsh_builtins): - cache = xonsh_builtins.__xonsh__.commands_cache - xonsh_builtins.__xonsh__.env = DummyEnv(VC_BRANCH_TIMEOUT=1) +def test_current_branch_calls_locate_binary_for_empty_cmds_cache(xession): + cache = xession.commands_cache + xession.env = DummyEnv(VC_BRANCH_TIMEOUT=1) cache.is_empty = Mock(return_value=True) cache.locate_binary = Mock(return_value="") vc.current_branch() @@ -94,10 +94,10 @@ def test_current_branch_calls_locate_binary_for_empty_cmds_cache(xonsh_builtins) def test_current_branch_does_not_call_locate_binary_for_non_empty_cmds_cache( - xonsh_builtins, + xession, ): - cache = xonsh_builtins.__xonsh__.commands_cache - xonsh_builtins.__xonsh__.env = DummyEnv(VC_BRANCH_TIMEOUT=1) + cache = xession.commands_cache + xession.env = DummyEnv(VC_BRANCH_TIMEOUT=1) cache.is_empty = Mock(return_value=False) cache.locate_binary = Mock(return_value="") # make lazy locate return nothing to avoid running vc binaries @@ -106,9 +106,9 @@ def test_current_branch_does_not_call_locate_binary_for_non_empty_cmds_cache( assert not cache.locate_binary.called -def test_dirty_working_directory(test_repo, xonsh_builtins): +def test_dirty_working_directory(test_repo, xession): get_dwd = "{}_dirty_working_directory".format(test_repo["vc"]) - xonsh_builtins.__xonsh__.env = Env(VC_BRANCH_TIMEOUT=2, PWD=test_repo["dir"]) + xession.env = Env(VC_BRANCH_TIMEOUT=2, PWD=test_repo["dir"]) # By default, git / hg do not care about untracked files Path("second-test-file").touch() @@ -120,9 +120,9 @@ def test_dirty_working_directory(test_repo, xonsh_builtins): @pytest.mark.parametrize("include_untracked", [True, False]) def test_git_dirty_working_directory_includes_untracked( - xonsh_builtins, test_repo, include_untracked + xession, test_repo, include_untracked ): - xonsh_builtins.__xonsh__.env = DummyEnv(VC_GIT_INCLUDE_UNTRACKED=include_untracked) + xession.env = DummyEnv(VC_GIT_INCLUDE_UNTRACKED=include_untracked) if test_repo["vc"] != "git": return diff --git a/tests/test_aliases.py b/tests/test_aliases.py index 765a961c8..0fd9a8ed0 100644 --- a/tests/test_aliases.py +++ b/tests/test_aliases.py @@ -57,9 +57,9 @@ def test_eval_recursive(xonsh_execer, xonsh_builtins): @skip_if_on_windows -def test_eval_recursive_callable_partial(xonsh_execer, xonsh_builtins): +def test_eval_recursive_callable_partial(xonsh_execer, xession): ales = make_aliases() - xonsh_builtins.__xonsh__.env = Env(HOME=os.path.expanduser("~")) + xession.env = Env(HOME=os.path.expanduser("~")) assert ales.get("indirect_cd")(["arg2", "arg3"]) == ["..", "arg2", "arg3"] @@ -151,44 +151,44 @@ def test_subprocess_io_operators(xonsh_execer, xonsh_builtins, alias): @pytest.mark.parametrize( "alias", [ - {'echocat': 'ls'}, + {"echocat": "ls"}, ], ) def test_dict_merging(xonsh_execer, xonsh_builtins, alias): ales = make_aliases() - assert (ales | alias)['echocat'] == ['ls'] - assert (alias | ales)['echocat'] == ['ls'] - assert 'echocat' not in ales + assert (ales | alias)["echocat"] == ["ls"] + assert (alias | ales)["echocat"] == ["ls"] + assert "echocat" not in ales @pytest.mark.parametrize( "alias", [ - {'echocat': 'echo Why do people still use python2.7?'}, - {'echocat': 'echo Why?'}, + {"echocat": "echo Why do people still use python2.7?"}, + {"echocat": "echo Why?"}, ], ) def test_dict_merging_assignment(xonsh_execer, xonsh_builtins, alias): ales = make_aliases() ales |= alias - assert 'echocat' in ales - assert ' '.join(ales['echocat']) == alias['echocat'] + assert "echocat" in ales + assert " ".join(ales["echocat"]) == alias["echocat"] ales = make_aliases() alias |= ales - assert 'o' in alias - assert alias['o'] == ales['o'] + assert "o" in alias + assert alias["o"] == ales["o"] def test_exec_alias_args(xonsh_execer, xonsh_builtins): stack = inspect.stack() try: - ExecAlias('myargs = $args')(['arg0'], stack=stack) - ExecAlias('myarg0 = $arg0')(['arg0'], stack=stack) + ExecAlias("myargs = $args")(["arg0"], stack=stack) + ExecAlias("myarg0 = $arg0")(["arg0"], stack=stack) except KeyError: assert False - assert stack[0][0].f_locals['myargs'] == ['arg0'] - assert stack[0][0].f_locals['myarg0'] == 'arg0' + assert stack[0][0].f_locals["myargs"] == ["arg0"] + assert stack[0][0].f_locals["myarg0"] == "arg0" diff --git a/tests/test_ansi_colors.py b/tests/test_ansi_colors.py index 88f05b579..c057b6900 100644 --- a/tests/test_ansi_colors.py +++ b/tests/test_ansi_colors.py @@ -149,7 +149,7 @@ def test_ansi_color_name_to_escape_code_for_all_styles(color, style): ("monokai"), # defined in `ansi_colors.py` ("rainbow_dash"), # not in `ansi_colors.py`, but in pygments ("foobar"), # invalid, should not fail - ] + ], ) def test_ansi_style_by_name(style_name): style = ansi_style_by_name(style_name) diff --git a/tests/test_base_shell.py b/tests/test_base_shell.py index b19b82f2f..7c67a5601 100644 --- a/tests/test_base_shell.py +++ b/tests/test_base_shell.py @@ -7,10 +7,10 @@ from xonsh.base_shell import BaseShell from xonsh.shell import transform_command -def test_pwd_tracks_cwd(xonsh_builtins, xonsh_execer, tmpdir_factory, monkeypatch): +def test_pwd_tracks_cwd(xession, xonsh_execer, tmpdir_factory, monkeypatch): asubdir = str(tmpdir_factory.mktemp("asubdir")) cur_wd = os.getcwd() - xonsh_builtins.__xonsh__.env = Env( + xession.env = Env( PWD=cur_wd, XONSH_CACHE_SCRIPTS=False, XONSH_CACHE_EVERYTHING=False ) @@ -22,17 +22,13 @@ def test_pwd_tracks_cwd(xonsh_builtins, xonsh_execer, tmpdir_factory, monkeypatc bc.default('os.chdir(r"' + asubdir + '")') assert os.path.abspath(os.getcwd()) == os.path.abspath(asubdir) - assert os.path.abspath(os.getcwd()) == os.path.abspath( - xonsh_builtins.__xonsh__.env["PWD"] - ) - assert "OLDPWD" in xonsh_builtins.__xonsh__.env - assert os.path.abspath(cur_wd) == os.path.abspath( - xonsh_builtins.__xonsh__.env["OLDPWD"] - ) + assert os.path.abspath(os.getcwd()) == os.path.abspath(xession.env["PWD"]) + assert "OLDPWD" in xession.env + assert os.path.abspath(cur_wd) == os.path.abspath(xession.env["OLDPWD"]) -def test_transform(xonsh_builtins): - @xonsh_builtins.events.on_transform_command +def test_transform(xession): + @xession.builtins.events.on_transform_command def spam2egg(cmd, **_): if cmd == "spam": return "egg" diff --git a/tests/test_bashisms.py b/tests/test_bashisms.py index 6c7d58c2b..f37103815 100644 --- a/tests/test_bashisms.py +++ b/tests/test_bashisms.py @@ -33,10 +33,10 @@ import pytest (["aa 1 2", "ab 3 4"], "echo !ab >log", "echo ab 3 4 >log"), ], ) -def test_preproc(history, inp, exp, xonsh_builtins): +def test_preproc(history, inp, exp, xession): """Test the bash preprocessor.""" from xontrib.bashisms import bash_preproc - xonsh_builtins.__xonsh__.history.inps = history + xession.history.inps = history obs = bash_preproc(inp) assert exp == obs diff --git a/tests/test_builtins.py b/tests/test_builtins.py index 582535ade..c901d5071 100644 --- a/tests/test_builtins.py +++ b/tests/test_builtins.py @@ -40,10 +40,10 @@ def test_reglob_tests(testfile): @pytest.fixture -def home_env(xonsh_builtins): +def home_env(xession): """Set `__xonsh__.env ` to a new Env instance on `xonsh_builtins`""" - xonsh_builtins.__xonsh__.env = Env(HOME=HOME_PATH) - return xonsh_builtins + xession.env = Env(HOME=HOME_PATH) + return xession @skip_if_on_windows diff --git a/tests/test_commands_cache.py b/tests/test_commands_cache.py index 29bfe9fc0..539da2503 100644 --- a/tests/test_commands_cache.py +++ b/tests/test_commands_cache.py @@ -1,5 +1,4 @@ import os -import builtins import pickle import time from unittest.mock import MagicMock @@ -13,7 +12,6 @@ from xonsh.commands_cache import ( predict_true, predict_false, ) -from xonsh import commands_cache from tools import skip_if_on_windows @@ -31,13 +29,10 @@ def test_predict_threadable_unknown_command(xonsh_builtins): @pytest.fixture -def commands_cache_tmp(xonsh_builtins, tmp_path, monkeypatch): - xonsh_builtins.__xonsh__.env["XONSH_DATA_DIR"] = tmp_path - xonsh_builtins.__xonsh__.env["COMMANDS_CACHE_SAVE_INTERMEDIATE"] = True - xonsh_builtins.__xonsh__.env["PATH"] = [tmp_path] - exec_mock = MagicMock(return_value=["bin1", "bin2"]) - monkeypatch.setattr(commands_cache, "executables_in", exec_mock) - return commands_cache.CommandsCache() +def commands_cache_tmp(xession, tmp_path, monkeypatch, patch_commands_cache_bins): + xession.env["XONSH_DATA_DIR"] = tmp_path + xession.env["COMMANDS_CACHE_SAVE_INTERMEDIATE"] = True + return patch_commands_cache_bins(["bin1", "bin2"]) def test_commands_cached_between_runs(commands_cache_tmp, tmp_path): @@ -158,9 +153,9 @@ def test_commands_cache_predictor_default(args, xonsh_builtins): @skip_if_on_windows -def test_cd_is_only_functional_alias(xonsh_builtins): +def test_cd_is_only_functional_alias(xession): cc = CommandsCache() - builtins.aliases["cd"] = lambda args: os.chdir(args[0]) + xession.aliases["cd"] = lambda args: os.chdir(args[0]) assert cc.is_only_functional_alias("cd") @@ -170,15 +165,15 @@ def test_non_exist_is_only_functional_alias(xonsh_builtins): @skip_if_on_windows -def test_bash_is_only_functional_alias(xonsh_builtins): - builtins.__xonsh__.env["PATH"] = os.environ["PATH"].split(os.pathsep) +def test_bash_is_only_functional_alias(xession): + xession.env["PATH"] = os.environ["PATH"].split(os.pathsep) cc = CommandsCache() assert not cc.is_only_functional_alias("bash") @skip_if_on_windows -def test_bash_and_is_alias_is_only_functional_alias(xonsh_builtins): - builtins.__xonsh__.env["PATH"] = os.environ["PATH"].split(os.pathsep) +def test_bash_and_is_alias_is_only_functional_alias(xession): + xession.env["PATH"] = os.environ["PATH"].split(os.pathsep) cc = CommandsCache() - builtins.aliases["bash"] = lambda args: os.chdir(args[0]) + xession.aliases["bash"] = lambda args: os.chdir(args[0]) assert not cc.is_only_functional_alias("bash") diff --git a/tests/test_completer.py b/tests/test_completer.py index 1632f41be..1e7a8bffa 100644 --- a/tests/test_completer.py +++ b/tests/test_completer.py @@ -1,7 +1,11 @@ """Tests for the base completer's logic (xonsh/completer.py)""" import pytest -from xonsh.completers.tools import RichCompletion, contextual_command_completer, non_exclusive_completer +from xonsh.completers.tools import ( + RichCompletion, + contextual_command_completer, + non_exclusive_completer, +) from xonsh.completer import Completer from xonsh.parsers.completion_context import CommandContext @@ -13,9 +17,9 @@ def completer(): @pytest.fixture -def completers_mock(xonsh_builtins, monkeypatch): +def completers_mock(xession, monkeypatch): completers = {} - monkeypatch.setattr(xonsh_builtins.__xonsh__, "completers", completers) + monkeypatch.setattr(xession, "completers", completers) return completers @@ -34,33 +38,40 @@ def test_sanity(completer, completers_mock): assert completer.complete("pre", "", 0, 0) == (("comp",), 2) # RichCompletion: completers_mock["a"] = lambda *a: {RichCompletion("comp", prefix_len=5)} - assert completer.complete("pre", "", 0, 0) == ((RichCompletion("comp", prefix_len=5),), 3) + assert completer.complete("pre", "", 0, 0) == ( + (RichCompletion("comp", prefix_len=5),), + 3, + ) def test_cursor_after_closing_quote(completer, completers_mock): """See ``Completer.complete`` in ``xonsh/completer.py``""" + @contextual_command_completer def comp(context: CommandContext): return {context.prefix + "1", context.prefix + "2"} completers_mock["a"] = comp - assert completer.complete("", "", 0, 0, {}, multiline_text="'test'", cursor_index=6) == ( - ("test1'", "test2'"), 5 - ) + assert completer.complete( + "", "", 0, 0, {}, multiline_text="'test'", cursor_index=6 + ) == (("test1'", "test2'"), 5) - assert completer.complete("", "", 0, 0, {}, multiline_text="'''test'''", cursor_index=10) == ( - ("test1'''", "test2'''"), 7 - ) + assert completer.complete( + "", "", 0, 0, {}, multiline_text="'''test'''", cursor_index=10 + ) == (("test1'''", "test2'''"), 7) def test_cursor_after_closing_quote_override(completer, completers_mock): """Test overriding the default values""" + @contextual_command_completer def comp(context: CommandContext): return { # replace the closing quote with "a" - RichCompletion("a", prefix_len=len(context.closing_quote), append_closing_quote=False), + RichCompletion( + "a", prefix_len=len(context.closing_quote), append_closing_quote=False + ), # add text after the closing quote RichCompletion(context.prefix + "_no_quote", append_closing_quote=False), # sanity @@ -69,66 +80,69 @@ def test_cursor_after_closing_quote_override(completer, completers_mock): completers_mock["a"] = comp - assert completer.complete("", "", 0, 0, {}, multiline_text="'test'", cursor_index=6) == ( + assert completer.complete( + "", "", 0, 0, {}, multiline_text="'test'", cursor_index=6 + ) == ( ( "a", "test1'", "test_no_quote", - ), 5 + ), + 5, ) - assert completer.complete("", "", 0, 0, {}, multiline_text="'''test'''", cursor_index=10) == ( + assert completer.complete( + "", "", 0, 0, {}, multiline_text="'''test'''", cursor_index=10 + ) == ( ( "a", "test1'''", "test_no_quote", - ), 7 + ), + 7, ) + def test_append_space(completer, completers_mock): @contextual_command_completer def comp(context: CommandContext): return { RichCompletion(context.prefix + "a", append_space=True), RichCompletion(context.prefix + " ", append_space=False), # bad usage - RichCompletion(context.prefix + "b", append_space=True, append_closing_quote=False), + RichCompletion( + context.prefix + "b", append_space=True, append_closing_quote=False + ), } completers_mock["a"] = comp - assert completer.complete("", "", 0, 0, {}, multiline_text="'test'", cursor_index=6) == ( + assert completer.complete( + "", "", 0, 0, {}, multiline_text="'test'", cursor_index=6 + ) == ( ( "test '", "testa' ", "testb ", - ), 5 + ), + 5, ) -@pytest.mark.parametrize("middle_result, exp", ( +@pytest.mark.parametrize( + "middle_result, exp", ( - # stop at the first exclusive result ( - {"b1", "b2"}, - ("a1", "a2", "b1", "b2") - ), - # pass empty exclusive results - ( - {}, - ("a1", "a2", "c1", "c2") - ), - # pass empty exclusive results - ( - None, - ("a1", "a2", "c1", "c2") - ), - # stop at StopIteration - ( - StopIteration, - ("a1", "a2") - ), - ) -)) + # stop at the first exclusive result + ({"b1", "b2"}, ("a1", "a2", "b1", "b2")), + # pass empty exclusive results + ({}, ("a1", "a2", "c1", "c2")), + # pass empty exclusive results + (None, ("a1", "a2", "c1", "c2")), + # stop at StopIteration + (StopIteration, ("a1", "a2")), + ) + ), +) def test_non_exclusive(completer, completers_mock, middle_result, exp): completers_mock["a"] = non_exclusive_completer(lambda *a: {"a1", "a2"}) diff --git a/tests/test_completion_context.py b/tests/test_completion_context.py index f61eb2bd6..356a245fd 100644 --- a/tests/test_completion_context.py +++ b/tests/test_completion_context.py @@ -3,7 +3,12 @@ import typing as tp import pytest -from xonsh.parsers.completion_context import CommandArg, CommandContext, CompletionContextParser, PythonContext +from xonsh.parsers.completion_context import ( + CommandArg, + CommandContext, + CompletionContextParser, + PythonContext, +) DEBUG = False @@ -24,7 +29,9 @@ def parse(command, inner_index): return PARSER.parse(command, inner_index) -def assert_match(commandline, command_context=MISSING, python_context=MISSING, is_main_command=False): +def assert_match( + commandline, command_context=MISSING, python_context=MISSING, is_main_command=False +): if X in commandline: index = commandline.index(X) commandline = commandline.replace(X, "") @@ -32,7 +39,9 @@ def assert_match(commandline, command_context=MISSING, python_context=MISSING, i index = len(commandline) context = parse(commandline, index) if context is None: - raise SyntaxError("Failed to parse the commandline - set DEBUG = True in this file to see the error") + raise SyntaxError( + "Failed to parse the commandline - set DEBUG = True in this file to see the error" + ) if is_main_command and python_context is MISSING: python_context = PythonContext(commandline, index) if command_context is not MISSING: @@ -48,17 +57,63 @@ COMMAND_EXAMPLES = ( (f"command {X}", CommandContext(args=(CommandArg("command"),), arg_index=1)), (f"{X} command", CommandContext(args=(CommandArg("command"),), arg_index=0)), (f" command {X}", CommandContext(args=(CommandArg("command"),), arg_index=1)), - (f"command --{X}", CommandContext(args=(CommandArg("command"),), arg_index=1, prefix="--")), - (f"command a {X}", CommandContext(args=(CommandArg("command"), CommandArg("a")), arg_index=2)), - (f"command a b{X}", CommandContext(args=(CommandArg("command"), CommandArg("a")), arg_index=2, prefix="b")), - (f"command a b{X}", CommandContext(args=(CommandArg("command"), CommandArg("a")), arg_index=2, prefix="b")), - (f"command {X} a", CommandContext(args=(CommandArg("command"), CommandArg("a")), arg_index=1)), - (f"command a {X} b", CommandContext(args=(CommandArg("command"), CommandArg("a"), CommandArg("b")), arg_index=2)), - (f"command -{X} b", CommandContext(args=(CommandArg("command"), CommandArg("b")), arg_index=1, prefix="-")), - (f"command a {X}b", CommandContext(args=(CommandArg("command"), CommandArg("a")), arg_index=2, suffix="b")), - (f"command a{X}b", CommandContext(args=(CommandArg("command"),), arg_index=1, prefix="a", suffix="b")), - (f"'comm and' a{X}b", CommandContext( - args=(CommandArg("comm and", opening_quote="'", closing_quote="'"),), arg_index=1, prefix="a", suffix="b")), + ( + f"command --{X}", + CommandContext(args=(CommandArg("command"),), arg_index=1, prefix="--"), + ), + ( + f"command a {X}", + CommandContext(args=(CommandArg("command"), CommandArg("a")), arg_index=2), + ), + ( + f"command a b{X}", + CommandContext( + args=(CommandArg("command"), CommandArg("a")), arg_index=2, prefix="b" + ), + ), + ( + f"command a b{X}", + CommandContext( + args=(CommandArg("command"), CommandArg("a")), arg_index=2, prefix="b" + ), + ), + ( + f"command {X} a", + CommandContext(args=(CommandArg("command"), CommandArg("a")), arg_index=1), + ), + ( + f"command a {X} b", + CommandContext( + args=(CommandArg("command"), CommandArg("a"), CommandArg("b")), arg_index=2 + ), + ), + ( + f"command -{X} b", + CommandContext( + args=(CommandArg("command"), CommandArg("b")), arg_index=1, prefix="-" + ), + ), + ( + f"command a {X}b", + CommandContext( + args=(CommandArg("command"), CommandArg("a")), arg_index=2, suffix="b" + ), + ), + ( + f"command a{X}b", + CommandContext( + args=(CommandArg("command"),), arg_index=1, prefix="a", suffix="b" + ), + ), + ( + f"'comm and' a{X}b", + CommandContext( + args=(CommandArg("comm and", opening_quote="'", closing_quote="'"),), + arg_index=1, + prefix="a", + suffix="b", + ), + ), ) EMPTY_COMMAND_EXAMPLES = ( @@ -69,25 +124,100 @@ EMPTY_COMMAND_EXAMPLES = ( ) STRING_ARGS_EXAMPLES = ( - (f"'comm an{X}d'", CommandContext( - args=(), arg_index=0, prefix="comm an", suffix="d", opening_quote="'", closing_quote="'")), - (f"'comm and{X}'", CommandContext( - args=(), arg_index=0, prefix="comm and", suffix="", opening_quote="'", closing_quote="'")), - (f"'comm {X}'", CommandContext( - args=(), arg_index=0, prefix="comm ", suffix="", opening_quote="'", closing_quote="'")), - (f"\"comm an{X}d\"", CommandContext( - args=(), arg_index=0, prefix="comm an", suffix="d", opening_quote="\"", closing_quote="\"")), - (f"'''comm an{X}d'''", CommandContext( - args=(), arg_index=0, prefix="comm an", suffix="d", opening_quote="'''", closing_quote="'''")), - (f"fr'comm an{X}d'", CommandContext( - args=(), arg_index=0, prefix="comm an", suffix="d", opening_quote="fr'", closing_quote="'")), - (f"'()+{X}'", CommandContext( - args=(), arg_index=0, prefix="()+", opening_quote="'", closing_quote="'")), - (f"'comm and'{X}", CommandContext( - args=(), arg_index=0, prefix="comm and", opening_quote="'", closing_quote="'", is_after_closing_quote=True)), - (f"'''comm and'''{X}", CommandContext( - args=(), arg_index=0, prefix="comm and", - opening_quote="'''", closing_quote="'''", is_after_closing_quote=True)), + ( + f"'comm an{X}d'", + CommandContext( + args=(), + arg_index=0, + prefix="comm an", + suffix="d", + opening_quote="'", + closing_quote="'", + ), + ), + ( + f"'comm and{X}'", + CommandContext( + args=(), + arg_index=0, + prefix="comm and", + suffix="", + opening_quote="'", + closing_quote="'", + ), + ), + ( + f"'comm {X}'", + CommandContext( + args=(), + arg_index=0, + prefix="comm ", + suffix="", + opening_quote="'", + closing_quote="'", + ), + ), + ( + f'"comm an{X}d"', + CommandContext( + args=(), + arg_index=0, + prefix="comm an", + suffix="d", + opening_quote='"', + closing_quote='"', + ), + ), + ( + f"'''comm an{X}d'''", + CommandContext( + args=(), + arg_index=0, + prefix="comm an", + suffix="d", + opening_quote="'''", + closing_quote="'''", + ), + ), + ( + f"fr'comm an{X}d'", + CommandContext( + args=(), + arg_index=0, + prefix="comm an", + suffix="d", + opening_quote="fr'", + closing_quote="'", + ), + ), + ( + f"'()+{X}'", + CommandContext( + args=(), arg_index=0, prefix="()+", opening_quote="'", closing_quote="'" + ), + ), + ( + f"'comm and'{X}", + CommandContext( + args=(), + arg_index=0, + prefix="comm and", + opening_quote="'", + closing_quote="'", + is_after_closing_quote=True, + ), + ), + ( + f"'''comm and'''{X}", + CommandContext( + args=(), + arg_index=0, + prefix="comm and", + opening_quote="'''", + closing_quote="'''", + is_after_closing_quote=True, + ), + ), ) COMMAND_EXAMPLES += STRING_ARGS_EXAMPLES @@ -99,10 +229,14 @@ def test_command(commandline, context): assert_match(commandline, context, is_main_command=True) -@pytest.mark.parametrize("commandline, context", tuple( - (commandline, context) for commandline, context in STRING_ARGS_EXAMPLES - if commandline.endswith("'") or commandline.endswith('"') -)) +@pytest.mark.parametrize( + "commandline, context", + tuple( + (commandline, context) + for commandline, context in STRING_ARGS_EXAMPLES + if commandline.endswith("'") or commandline.endswith('"') + ), +) def test_partial_string_arg(commandline, context): partial_commandline = commandline.rstrip("\"'") partial_context = context._replace(closing_quote="") @@ -112,50 +246,147 @@ def test_partial_string_arg(commandline, context): CONT = "\\" "\n" -@pytest.mark.parametrize("commandline, context", ( +@pytest.mark.parametrize( + "commandline, context", + ( # line continuations: - (f"echo {CONT}a {X}", CommandContext(args=(CommandArg("echo"), CommandArg("a")), arg_index=2)), - (f"echo {CONT}{X}a {CONT} b", - CommandContext(args=(CommandArg("echo"), CommandArg("b")), arg_index=1, suffix="a")), - (f"echo a{CONT}{X}b", - CommandContext(args=(CommandArg("echo"),), arg_index=1, prefix="a", suffix="b")), - (f"echo a{X}{CONT}b", - CommandContext(args=(CommandArg("echo"),), arg_index=1, prefix="a", suffix="b")), - (f"echo ${CONT}(a) {CONT} {X}b", - CommandContext(args=(CommandArg("echo"), CommandArg("$(a)")), arg_index=2, suffix="b")), - + ( + f"echo {CONT}a {X}", + CommandContext(args=(CommandArg("echo"), CommandArg("a")), arg_index=2), + ), + ( + f"echo {CONT}{X}a {CONT} b", + CommandContext( + args=(CommandArg("echo"), CommandArg("b")), arg_index=1, suffix="a" + ), + ), + ( + f"echo a{CONT}{X}b", + CommandContext( + args=(CommandArg("echo"),), arg_index=1, prefix="a", suffix="b" + ), + ), + ( + f"echo a{X}{CONT}b", + CommandContext( + args=(CommandArg("echo"),), arg_index=1, prefix="a", suffix="b" + ), + ), + ( + f"echo ${CONT}(a) {CONT} {X}b", + CommandContext( + args=(CommandArg("echo"), CommandArg("$(a)")), arg_index=2, suffix="b" + ), + ), # line continuations in strings: - (f"echo 'a{CONT}{X}b'", - CommandContext(args=(CommandArg("echo"),), arg_index=1, prefix="a", suffix="b", opening_quote="'", - closing_quote="'")), - (f"echo '''a{CONT}{X}b'''", - CommandContext(args=(CommandArg("echo"),), arg_index=1, prefix="a", suffix="b", opening_quote="'''", - closing_quote="'''")), - (f"echo 'a{CONT}{X}b", - CommandContext(args=(CommandArg("echo"),), arg_index=1, prefix="a", suffix="b", opening_quote="'")), - (f"echo '''a{CONT}{X}b", - CommandContext(args=(CommandArg("echo"),), arg_index=1, prefix="a", suffix="b", opening_quote="'''")), - (f"echo ''{CONT}'a{X}b", - CommandContext(args=(CommandArg("echo"),), arg_index=1, prefix="a", suffix="b", opening_quote="'''")), - (f"echo '''a{CONT}{X} b", - CommandContext(args=(CommandArg("echo"),), arg_index=1, prefix="a", suffix=" b", opening_quote="'''")), - + ( + f"echo 'a{CONT}{X}b'", + CommandContext( + args=(CommandArg("echo"),), + arg_index=1, + prefix="a", + suffix="b", + opening_quote="'", + closing_quote="'", + ), + ), + ( + f"echo '''a{CONT}{X}b'''", + CommandContext( + args=(CommandArg("echo"),), + arg_index=1, + prefix="a", + suffix="b", + opening_quote="'''", + closing_quote="'''", + ), + ), + ( + f"echo 'a{CONT}{X}b", + CommandContext( + args=(CommandArg("echo"),), + arg_index=1, + prefix="a", + suffix="b", + opening_quote="'", + ), + ), + ( + f"echo '''a{CONT}{X}b", + CommandContext( + args=(CommandArg("echo"),), + arg_index=1, + prefix="a", + suffix="b", + opening_quote="'''", + ), + ), + ( + f"echo ''{CONT}'a{X}b", + CommandContext( + args=(CommandArg("echo"),), + arg_index=1, + prefix="a", + suffix="b", + opening_quote="'''", + ), + ), + ( + f"echo '''a{CONT}{X} b", + CommandContext( + args=(CommandArg("echo"),), + arg_index=1, + prefix="a", + suffix=" b", + opening_quote="'''", + ), + ), # triple-quoted strings: - (f"echo '''a\nb{X}\nc'''", CommandContext( - args=(CommandArg("echo"),), arg_index=1, - prefix="a\nb", suffix="\nc", opening_quote="'''", closing_quote="'''")), - (f"echo '''a\n b{X} \n c'''", CommandContext( - args=(CommandArg("echo"),), arg_index=1, - prefix="a\n b", suffix=" \n c", opening_quote="'''", closing_quote="'''")), - + ( + f"echo '''a\nb{X}\nc'''", + CommandContext( + args=(CommandArg("echo"),), + arg_index=1, + prefix="a\nb", + suffix="\nc", + opening_quote="'''", + closing_quote="'''", + ), + ), + ( + f"echo '''a\n b{X} \n c'''", + CommandContext( + args=(CommandArg("echo"),), + arg_index=1, + prefix="a\n b", + suffix=" \n c", + opening_quote="'''", + closing_quote="'''", + ), + ), # partial triple-quoted strings: - (f"echo '''a\nb{X}\nc", CommandContext( - args=(CommandArg("echo"),), arg_index=1, - prefix="a\nb", suffix="\nc", opening_quote="'''")), - (f"echo '''a\n b{X} \n c", CommandContext( - args=(CommandArg("echo"),), arg_index=1, - prefix="a\n b", suffix=" \n c", opening_quote="'''")), -)) + ( + f"echo '''a\nb{X}\nc", + CommandContext( + args=(CommandArg("echo"),), + arg_index=1, + prefix="a\nb", + suffix="\nc", + opening_quote="'''", + ), + ), + ( + f"echo '''a\n b{X} \n c", + CommandContext( + args=(CommandArg("echo"),), + arg_index=1, + prefix="a\n b", + suffix=" \n c", + opening_quote="'''", + ), + ), + ), +) def test_multiline_command(commandline, context): assert_match(commandline, context, is_main_command=True) @@ -172,15 +403,34 @@ NESTING_EXAMPLES = ( ) NESTED_SIMPLE_CMD_EXAMPLES = [ - (nesting, f"simple {X}", CommandContext(args=(CommandArg("simple"),), arg_index=1, subcmd_opening=prefix)) - for nesting, prefix in NESTING_EXAMPLES[1:]] + ( + nesting, + f"simple {X}", + CommandContext( + args=(CommandArg("simple"),), arg_index=1, subcmd_opening=prefix + ), + ) + for nesting, prefix in NESTING_EXAMPLES[1:] +] -@pytest.mark.parametrize("nesting, commandline, context", list(itertools.chain(( - # complex subcommand in a simple nested expression - (NESTING_EXAMPLES[0][0], commandline, context._replace(subcmd_opening=NESTING_EXAMPLES[0][1])) - for commandline, context in COMMAND_EXAMPLES -), NESTED_SIMPLE_CMD_EXAMPLES))) +@pytest.mark.parametrize( + "nesting, commandline, context", + list( + itertools.chain( + ( + # complex subcommand in a simple nested expression + ( + NESTING_EXAMPLES[0][0], + commandline, + context._replace(subcmd_opening=NESTING_EXAMPLES[0][1]), + ) + for commandline, context in COMMAND_EXAMPLES + ), + NESTED_SIMPLE_CMD_EXAMPLES, + ) + ), +) def test_nested_command(commandline, context, nesting): nested_commandline = nesting.replace(X, commandline) assert_match(nested_commandline, command_context=context, python_context=None) @@ -205,16 +455,17 @@ def test_malformed_subcmd(nesting, commandline, context, malformation): MALFORMED_SUBCOMMANDS_NESTINGS = ( # nesting, subcmd_opening - (f"echo $(a $({X}", "$("), - (f"echo $(a $(b; {X}", ""), - (f"$(echo $(a $({X}", "$("), - (f"echo $[a $({X}]", "$("), - (f"echo $(a $[{X})", "$["), - (f"echo @(x = $({X}", "$("), - (f"echo @(a; x = $({X}", "$("), - (f"echo @(x = $(a; {X}", ""), + (f"echo $(a $({X}", "$("), + (f"echo $(a $(b; {X}", ""), + (f"$(echo $(a $({X}", "$("), + (f"echo $[a $({X}]", "$("), + (f"echo $(a $[{X})", "$["), + (f"echo @(x = $({X}", "$("), + (f"echo @(a; x = $({X}", "$("), + (f"echo @(x = $(a; {X}", ""), ) + @pytest.mark.parametrize("nesting, subcmd_opening", MALFORMED_SUBCOMMANDS_NESTINGS) @pytest.mark.parametrize("commandline, context", COMMAND_EXAMPLES[:5]) def test_multiple_malformed_subcmds(nesting, subcmd_opening, commandline, context): @@ -228,7 +479,7 @@ def test_other_subcommand_arg(): assert_match( command, CommandContext((CommandArg("echo"), CommandArg("$(pwd)")), arg_index=2), - is_main_command=True + is_main_command=True, ) @@ -236,12 +487,18 @@ def test_combined_subcommand_arg(): command = f"echo file=$(pwd{X})/x" # index inside the subproc - assert_match(command, CommandContext( - (), arg_index=0, prefix="pwd", subcmd_opening="$("), python_context=None) + assert_match( + command, + CommandContext((), arg_index=0, prefix="pwd", subcmd_opening="$("), + python_context=None, + ) # index at the end of the command - assert_match(command.replace(X, ""), CommandContext( - (CommandArg("echo"),), arg_index=1, prefix="file=$(pwd)/x"), is_main_command=True) + assert_match( + command.replace(X, ""), + CommandContext((CommandArg("echo"),), arg_index=1, prefix="file=$(pwd)/x"), + is_main_command=True, + ) SUBCMD_BORDER_EXAMPLES = ( @@ -269,49 +526,71 @@ MULTIPLE_COMMAND_KEYWORDS = ( ) MULTIPLE_CMD_SIMPLE_EXAMPLES = [ - (keyword, ("echo hi", f"simple {X}"), CommandContext(args=(CommandArg("simple"),), arg_index=1)) - for keyword in MULTIPLE_COMMAND_KEYWORDS] + ( + keyword, + ("echo hi", f"simple {X}"), + CommandContext(args=(CommandArg("simple"),), arg_index=1), + ) + for keyword in MULTIPLE_COMMAND_KEYWORDS +] -EXTENSIVE_COMMAND_PAIRS = tuple(itertools.chain( - zip(COMMAND_EXAMPLES, COMMAND_EXAMPLES[::-1]), - zip(COMMAND_EXAMPLES, EMPTY_COMMAND_EXAMPLES), - zip(EMPTY_COMMAND_EXAMPLES, COMMAND_EXAMPLES), - zip(EMPTY_COMMAND_EXAMPLES, EMPTY_COMMAND_EXAMPLES), -)) +EXTENSIVE_COMMAND_PAIRS = tuple( + itertools.chain( + zip(COMMAND_EXAMPLES, COMMAND_EXAMPLES[::-1]), + zip(COMMAND_EXAMPLES, EMPTY_COMMAND_EXAMPLES), + zip(EMPTY_COMMAND_EXAMPLES, COMMAND_EXAMPLES), + zip(EMPTY_COMMAND_EXAMPLES, EMPTY_COMMAND_EXAMPLES), + ) +) -MULTIPLE_COMMAND_EXTENSIVE_EXAMPLES = tuple(itertools.chain( - ( - # cursor in first command - ((first, second.replace(X, "")), first_context) - for (first, first_context), (second, second_context) in EXTENSIVE_COMMAND_PAIRS - ), - ( - # cursor in second command - ((first.replace(X, ""), second), second_context) - for (first, first_context), (second, second_context) in EXTENSIVE_COMMAND_PAIRS - ), - ( - # cursor in middle command - ((first.replace(X, ""), second, third.replace(X, "")), second_context) - for (first, _1), (second, second_context), (third, _3) - in zip(COMMAND_EXAMPLES[:3], COMMAND_EXAMPLES[3:6], COMMAND_EXAMPLES[6:9]) - ), - ( - # cursor in third command - ((first.replace(X, ""), second.replace(X, ""), third), third_context) - for (first, _1), (second, _2), (third, third_context) - in zip(COMMAND_EXAMPLES[:3], COMMAND_EXAMPLES[3:6], COMMAND_EXAMPLES[6:9]) - ), -)) +MULTIPLE_COMMAND_EXTENSIVE_EXAMPLES = tuple( + itertools.chain( + ( + # cursor in first command + ((first, second.replace(X, "")), first_context) + for (first, first_context), ( + second, + second_context, + ) in EXTENSIVE_COMMAND_PAIRS + ), + ( + # cursor in second command + ((first.replace(X, ""), second), second_context) + for (first, first_context), ( + second, + second_context, + ) in EXTENSIVE_COMMAND_PAIRS + ), + ( + # cursor in middle command + ((first.replace(X, ""), second, third.replace(X, "")), second_context) + for (first, _1), (second, second_context), (third, _3) in zip( + COMMAND_EXAMPLES[:3], COMMAND_EXAMPLES[3:6], COMMAND_EXAMPLES[6:9] + ) + ), + ( + # cursor in third command + ((first.replace(X, ""), second.replace(X, ""), third), third_context) + for (first, _1), (second, _2), (third, third_context) in zip( + COMMAND_EXAMPLES[:3], COMMAND_EXAMPLES[3:6], COMMAND_EXAMPLES[6:9] + ) + ), + ) +) -@pytest.mark.parametrize("keyword, commands, context", tuple(itertools.chain( - ( - (MULTIPLE_COMMAND_KEYWORDS[0], commands, context) - for commands, context in MULTIPLE_COMMAND_EXTENSIVE_EXAMPLES +@pytest.mark.parametrize( + "keyword, commands, context", + tuple( + itertools.chain( + ( + (MULTIPLE_COMMAND_KEYWORDS[0], commands, context) + for commands, context in MULTIPLE_COMMAND_EXTENSIVE_EXAMPLES + ), + MULTIPLE_CMD_SIMPLE_EXAMPLES, + ) ), - MULTIPLE_CMD_SIMPLE_EXAMPLES, -))) +) def test_multiple_commands(keyword, commands, context): joined_command = keyword.join(commands) @@ -320,7 +599,11 @@ def test_multiple_commands(keyword, commands, context): relative_index = cursor_command.index(X) else: absolute_index = joined_command.index(X) - relative_index = absolute_index - joined_command.rindex(keyword, 0, absolute_index) - len(keyword) + relative_index = ( + absolute_index + - joined_command.rindex(keyword, 0, absolute_index) + - len(keyword) + ) if keyword.endswith(" "): # the last space is part of the command relative_index += 1 @@ -329,24 +612,35 @@ def test_multiple_commands(keyword, commands, context): assert_match(joined_command, context, is_main_command=True) -@pytest.mark.parametrize("commandline", ( - f"{X};", - f"; {X}", - f"{X};;", - f"; {X};", - f";; {X}", - f";;; {X}", -)) +@pytest.mark.parametrize( + "commandline", + ( + f"{X};", + f"; {X}", + f"{X};;", + f"; {X};", + f";; {X}", + f";;; {X}", + ), +) def test_multiple_empty_commands(commandline): assert_match(commandline, CommandContext((), 0), is_main_command=True) -@pytest.mark.parametrize("nesting, keyword, commands, context", tuple( - (nesting, keyword, commands, context) # no subcmd_opening in nested multi-commands - for nesting, prefix in NESTING_EXAMPLES - for keyword, commands, context in MULTIPLE_CMD_SIMPLE_EXAMPLES - if keyword != "\n" # the lexer ignores newlines inside subcommands -)) +@pytest.mark.parametrize( + "nesting, keyword, commands, context", + tuple( + ( + nesting, + keyword, + commands, + context, + ) # no subcmd_opening in nested multi-commands + for nesting, prefix in NESTING_EXAMPLES + for keyword, commands, context in MULTIPLE_CMD_SIMPLE_EXAMPLES + if keyword != "\n" # the lexer ignores newlines inside subcommands + ), +) def test_nested_multiple_commands(nesting, keyword, commands, context): joined_command = keyword.join(commands) nested_joined = nesting.replace(X, joined_command) @@ -354,15 +648,21 @@ def test_nested_multiple_commands(nesting, keyword, commands, context): def test_multiple_nested_commands(): - assert_match(f"echo hi; echo $(ls{X})", - CommandContext((), 0, prefix="ls", subcmd_opening="$("), - python_context=None) + assert_match( + f"echo hi; echo $(ls{X})", + CommandContext((), 0, prefix="ls", subcmd_opening="$("), + python_context=None, + ) -@pytest.mark.parametrize("commandline, context", tuple( - (commandline, context) for commandline, context in STRING_ARGS_EXAMPLES - if commandline.endswith("'") or commandline.endswith('"') -)) +@pytest.mark.parametrize( + "commandline, context", + tuple( + (commandline, context) + for commandline, context in STRING_ARGS_EXAMPLES + if commandline.endswith("'") or commandline.endswith('"') + ), +) def test_multiple_partial_string_arg(commandline, context): partial_commandline = commandline.rstrip("\"'") partial_context = context._replace(closing_quote="") @@ -370,11 +670,14 @@ def test_multiple_partial_string_arg(commandline, context): assert_match("echo $[a ;" + partial_commandline, partial_context) -@pytest.mark.parametrize("nesting, keyword, commands, context", tuple( - (nesting, keyword, commands, context) - for nesting, prefix in NESTING_EXAMPLES[:1] - for keyword, commands, context in MULTIPLE_CMD_SIMPLE_EXAMPLES[:1] -)) +@pytest.mark.parametrize( + "nesting, keyword, commands, context", + tuple( + (nesting, keyword, commands, context) + for nesting, prefix in NESTING_EXAMPLES[:1] + for keyword, commands, context in MULTIPLE_CMD_SIMPLE_EXAMPLES[:1] + ), +) @pytest.mark.parametrize("malformation", NESTING_MALFORMATIONS) def test_malformed_subcmd(malformation, nesting, keyword, commands, context): joined_command = keyword.join(commands) @@ -383,37 +686,70 @@ def test_malformed_subcmd(malformation, nesting, keyword, commands, context): assert_match(malformed_commandline, context, python_context=None) -MULTIPLE_COMMAND_BORDER_EXAMPLES = tuple(itertools.chain( - itertools.chain(*( +MULTIPLE_COMMAND_BORDER_EXAMPLES = tuple( + itertools.chain( + itertools.chain( + *( + ( + ( + f"ls{ws1}{X}{kwd}{ws2}echo", + CommandContext((CommandArg("ls"),), 1) + if ws1 + else CommandContext((), 0, prefix="ls"), + ), + ) + for ws1, ws2, kwd in itertools.product( + ("", " "), ("", " "), ("&&", ";") + ) + ) + ), + # all keywords are treated as a normal arg if the cursor is at the edge ( - (f"ls{ws1}{X}{kwd}{ws2}echo", - CommandContext((CommandArg("ls"),), 1) if ws1 else CommandContext((), 0, prefix="ls")), - ) for ws1, ws2, kwd in itertools.product(("", " "), ("", " "), ("&&", ";")) - )), - - # all keywords are treated as a normal arg if the cursor is at the edge - ( - (f"ls {X}and echo", CommandContext((CommandArg("ls"), CommandArg("echo")), 1, suffix="and")), - (f"ls and{X} echo", CommandContext((CommandArg("ls"), CommandArg("echo")), 1, prefix="and")), - (f"ls ||{X} echo", CommandContext((CommandArg("ls"), CommandArg("echo")), 1, prefix="||")), - ), - - # if the cursor is inside the keyword, it's treated as a normal arg - ( - (f"ls a{X}nd echo", CommandContext((CommandArg("ls"), CommandArg("echo")), 1, prefix="a", suffix="nd")), - (f"ls &{X}& echo", CommandContext((CommandArg("ls"), CommandArg("echo")), 1, prefix="&", suffix="&")), + ( + f"ls {X}and echo", + CommandContext((CommandArg("ls"), CommandArg("echo")), 1, suffix="and"), + ), + ( + f"ls and{X} echo", + CommandContext((CommandArg("ls"), CommandArg("echo")), 1, prefix="and"), + ), + ( + f"ls ||{X} echo", + CommandContext((CommandArg("ls"), CommandArg("echo")), 1, prefix="||"), + ), + ), + # if the cursor is inside the keyword, it's treated as a normal arg + ( + ( + f"ls a{X}nd echo", + CommandContext( + (CommandArg("ls"), CommandArg("echo")), 1, prefix="a", suffix="nd" + ), + ), + ( + f"ls &{X}& echo", + CommandContext( + (CommandArg("ls"), CommandArg("echo")), 1, prefix="&", suffix="&" + ), + ), + ), ) -)) +) -@pytest.mark.parametrize("commandline, context", tuple(itertools.chain( - MULTIPLE_COMMAND_BORDER_EXAMPLES, - ( - # ensure these rules work with more than one command - (f"cat | {commandline}", context) - for commandline, context in MULTIPLE_COMMAND_BORDER_EXAMPLES +@pytest.mark.parametrize( + "commandline, context", + tuple( + itertools.chain( + MULTIPLE_COMMAND_BORDER_EXAMPLES, + ( + # ensure these rules work with more than one command + (f"cat | {commandline}", context) + for commandline, context in MULTIPLE_COMMAND_BORDER_EXAMPLES + ), + ) ), -))) +) def test_cursor_in_multiple_keyword_borders(commandline, context): assert_match(commandline, context) @@ -433,52 +769,69 @@ PYTHON_NESTING_EXAMPLES = ( ) -@pytest.mark.parametrize("nesting, commandline, context", list(itertools.chain(( - # complex subcommand in a simple nested expression - (nesting, commandline, context._replace(is_sub_expression=True)) - for nesting in PYTHON_NESTING_EXAMPLES[:1] - for commandline, context in PYTHON_EXAMPLES -), ( - # simple subcommand in a complex nested expression - (nesting, commandline, context._replace(is_sub_expression=True)) - for nesting in PYTHON_NESTING_EXAMPLES - for commandline, context in PYTHON_EXAMPLES[:1] -)))) +@pytest.mark.parametrize( + "nesting, commandline, context", + list( + itertools.chain( + ( + # complex subcommand in a simple nested expression + (nesting, commandline, context._replace(is_sub_expression=True)) + for nesting in PYTHON_NESTING_EXAMPLES[:1] + for commandline, context in PYTHON_EXAMPLES + ), + ( + # simple subcommand in a complex nested expression + (nesting, commandline, context._replace(is_sub_expression=True)) + for nesting in PYTHON_NESTING_EXAMPLES + for commandline, context in PYTHON_EXAMPLES[:1] + ), + ) + ), +) def test_nested_python(commandline, context, nesting): nested_commandline = nesting.replace(X, commandline) assert_match(nested_commandline, command_context=None, python_context=context) -@pytest.mark.parametrize("commandline, context", [ - (commandline.replace("$", "@"), context._replace( - prefix=context.prefix.replace("$", "@"), - suffix=context.suffix.replace("$", "@"), - )) - for commandline, context in SUBCMD_BORDER_EXAMPLES -]) +@pytest.mark.parametrize( + "commandline, context", + [ + ( + commandline.replace("$", "@"), + context._replace( + prefix=context.prefix.replace("$", "@"), + suffix=context.suffix.replace("$", "@"), + ), + ) + for commandline, context in SUBCMD_BORDER_EXAMPLES + ], +) def test_cursor_in_sub_python_borders(commandline, context): assert_match(commandline, context, is_main_command=True) -@pytest.mark.parametrize("code", ( - f""" +@pytest.mark.parametrize( + "code", + ( + f""" x = 3 x.{X}""", - f""" + f""" x = 3; y = 4; x.{X}""", - f""" + f""" def func({X}): return 100 """, - f""" + f""" class A: def a(): return "a{X}" pass exit() """, -)) + ), +) def test_multiline_python(code): assert_match(code, is_main_command=True) diff --git a/tests/test_dirstack.py b/tests/test_dirstack.py index 16361460d..e6a2f490f 100644 --- a/tests/test_dirstack.py +++ b/tests/test_dirstack.py @@ -23,24 +23,24 @@ def chdir(adir): os.chdir(old_dir) -def test_simple(xonsh_builtins): - xonsh_builtins.__xonsh__.env = Env(CDPATH=PARENT, PWD=PARENT) +def test_simple(xession): + xession.env = Env(CDPATH=PARENT, PWD=PARENT) with chdir(PARENT): assert os.getcwd() != HERE dirstack.cd(["tests"]) assert os.getcwd() == HERE -def test_cdpath_simple(xonsh_builtins): - xonsh_builtins.__xonsh__.env = Env(CDPATH=PARENT, PWD=HERE) +def test_cdpath_simple(xession): + xession.env = Env(CDPATH=PARENT, PWD=HERE) with chdir(os.path.normpath("/")): assert os.getcwd() != HERE dirstack.cd(["tests"]) assert os.getcwd() == HERE -def test_cdpath_collision(xonsh_builtins): - xonsh_builtins.__xonsh__.env = Env(CDPATH=PARENT, PWD=HERE) +def test_cdpath_collision(xession): + xession.env = Env(CDPATH=PARENT, PWD=HERE) sub_tests = os.path.join(HERE, "tests") if not os.path.exists(sub_tests): os.mkdir(sub_tests) @@ -50,8 +50,8 @@ def test_cdpath_collision(xonsh_builtins): assert os.getcwd() == os.path.join(HERE, "tests") -def test_cdpath_expansion(xonsh_builtins): - xonsh_builtins.__xonsh__.env = Env(HERE=HERE, CDPATH=("~", "$HERE")) +def test_cdpath_expansion(xession): + xession.env = Env(HERE=HERE, CDPATH=("~", "$HERE")) test_dirs = ( os.path.join(HERE, "xonsh-test-cdpath-here"), os.path.expanduser("~/xonsh-test-cdpath-home"), @@ -69,13 +69,13 @@ def test_cdpath_expansion(xonsh_builtins): os.rmdir(d) -def test_cdpath_events(xonsh_builtins, tmpdir): - xonsh_builtins.__xonsh__.env = Env(CDPATH=PARENT, PWD=os.getcwd()) +def test_cdpath_events(xession, tmpdir): + xession.env = Env(CDPATH=PARENT, PWD=os.getcwd()) target = str(tmpdir) ev = None - @xonsh_builtins.events.on_chdir + @xession.builtins.events.on_chdir def handler(olddir, newdir, **kw): nonlocal ev ev = olddir, newdir @@ -92,8 +92,8 @@ def test_cdpath_events(xonsh_builtins, tmpdir): os.chdir(old_dir) -def test_cd_autopush(xonsh_builtins, tmpdir): - xonsh_builtins.__xonsh__.env = Env(CDPATH=PARENT, PWD=os.getcwd(), AUTO_PUSHD=True) +def test_cd_autopush(xession, tmpdir): + xession.env = Env(CDPATH=PARENT, PWD=os.getcwd(), AUTO_PUSHD=True) target = str(tmpdir) old_dir = os.getcwd() diff --git a/tests/test_dirstack_unc.py b/tests/test_dirstack_unc.py index 69f1fd9b7..819d38489 100644 --- a/tests/test_dirstack_unc.py +++ b/tests/test_dirstack_unc.py @@ -87,14 +87,13 @@ def shares_setup(tmpdir_factory): # unless I wait > 10 sec. see http://stackoverflow.com/questions/38448413/access-denied-in-net-share-delete -def test_pushdpopd(xonsh_builtins): - """Simple non-UNC push/pop to verify we didn't break nonUNC case. - """ - xonsh_builtins.__xonsh__.env = Env(CDPATH=PARENT, PWD=HERE) +def test_pushdpopd(xession): + """Simple non-UNC push/pop to verify we didn't break nonUNC case.""" + xession.env = Env(CDPATH=PARENT, PWD=HERE) dirstack.cd([PARENT]) owd = os.getcwd() - assert owd.casefold() == xonsh_builtins.__xonsh__.env["PWD"].casefold() + assert owd.casefold() == xession.env["PWD"].casefold() dirstack.pushd([HERE]) wd = os.getcwd() assert wd.casefold() == HERE.casefold() @@ -102,8 +101,8 @@ def test_pushdpopd(xonsh_builtins): assert owd.casefold() == os.getcwd().casefold(), "popd returned cwd to expected dir" -def test_cd_dot(xonsh_builtins): - xonsh_builtins.__xonsh__.env = Env(PWD=os.getcwd()) +def test_cd_dot(xession): + xession.env = Env(PWD=os.getcwd()) owd = os.getcwd().casefold() dirstack.cd(["."]) @@ -111,13 +110,13 @@ def test_cd_dot(xonsh_builtins): @pytest.mark.skipif(not ON_WINDOWS, reason="Windows-only UNC functionality") -def test_uncpushd_simple_push_pop(xonsh_builtins, shares_setup): +def test_uncpushd_simple_push_pop(xession, shares_setup): if shares_setup is None: return - xonsh_builtins.__xonsh__.env = Env(CDPATH=PARENT, PWD=HERE) + xession.env = Env(CDPATH=PARENT, PWD=HERE) dirstack.cd([PARENT]) owd = os.getcwd() - assert owd.casefold() == xonsh_builtins.__xonsh__.env["PWD"].casefold() + assert owd.casefold() == xession.env["PWD"].casefold() dirstack.pushd([r"\\localhost\uncpushd_test_HERE"]) wd = os.getcwd() assert os.path.splitdrive(wd)[0].casefold() == TEMP_DRIVE[0] @@ -128,14 +127,14 @@ def test_uncpushd_simple_push_pop(xonsh_builtins, shares_setup): @pytest.mark.skipif(not ON_WINDOWS, reason="Windows-only UNC functionality") -def test_uncpushd_push_to_same_share(xonsh_builtins, shares_setup): +def test_uncpushd_push_to_same_share(xession, shares_setup): if shares_setup is None: return - xonsh_builtins.__xonsh__.env = Env(CDPATH=PARENT, PWD=HERE) + xession.env = Env(CDPATH=PARENT, PWD=HERE) dirstack.cd([PARENT]) owd = os.getcwd() - assert owd.casefold() == xonsh_builtins.__xonsh__.env["PWD"].casefold() + assert owd.casefold() == xession.env["PWD"].casefold() dirstack.pushd([r"\\localhost\uncpushd_test_HERE"]) wd = os.getcwd() assert os.path.splitdrive(wd)[0].casefold() == TEMP_DRIVE[0] @@ -160,16 +159,16 @@ def test_uncpushd_push_to_same_share(xonsh_builtins, shares_setup): @pytest.mark.skipif(not ON_WINDOWS, reason="Windows-only UNC functionality") -def test_uncpushd_push_other_push_same(xonsh_builtins, shares_setup): +def test_uncpushd_push_other_push_same(xession, shares_setup): """push to a, then to b. verify drive letter is TEMP_DRIVE[2], skipping already used TEMP_DRIVE[1] - Then push to a again. Pop (check b unmapped and a still mapped), pop, pop (check a is unmapped)""" + Then push to a again. Pop (check b unmapped and a still mapped), pop, pop (check a is unmapped)""" if shares_setup is None: return - xonsh_builtins.__xonsh__.env = Env(CDPATH=PARENT, PWD=HERE) + xession.env = Env(CDPATH=PARENT, PWD=HERE) dirstack.cd([PARENT]) owd = os.getcwd() - assert owd.casefold() == xonsh_builtins.__xonsh__.env["PWD"].casefold() + assert owd.casefold() == xession.env["PWD"].casefold() dirstack.pushd([r"\\localhost\uncpushd_test_HERE"]) assert os.getcwd().casefold() == TEMP_DRIVE[0] + "\\" assert len(_unc_tempDrives) == 1 @@ -209,7 +208,7 @@ def test_uncpushd_push_other_push_same(xonsh_builtins, shares_setup): @pytest.mark.skipif(not ON_WINDOWS, reason="Windows-only UNC functionality") -def test_uncpushd_push_base_push_rempath(xonsh_builtins): +def test_uncpushd_push_base_push_rempath(xession): """push to subdir under share, verify mapped path includes subdir""" pass @@ -280,16 +279,16 @@ def with_unc_check_disabled(): # just like the above, but value is 1 to *disabl @pytest.fixture() -def xonsh_builtins_cd(xonsh_builtins): - xonsh_builtins.__xonsh__.env["CDPATH"] = PARENT - xonsh_builtins.__xonsh__.env["PWD"] = os.getcwd() - xonsh_builtins.__xonsh__.env["DIRSTACK_SIZE"] = 20 - return xonsh_builtins +def xonsh_builtins_cd(xession): + xession.env["CDPATH"] = PARENT + xession.env["PWD"] = os.getcwd() + xession.env["DIRSTACK_SIZE"] = 20 + return xession @pytest.mark.skipif(not ON_WINDOWS, reason="Windows-only UNC functionality") def test_uncpushd_cd_unc_auto_pushd(xonsh_builtins_cd, with_unc_check_enabled): - xonsh_builtins_cd.__xonsh__.env["AUTO_PUSHD"] = True + xonsh_builtins_cd.env["AUTO_PUSHD"] = True so, se, rc = dirstack.cd([r"\\localhost\uncpushd_test_PARENT"]) if rc != 0: return diff --git a/tests/test_environ.py b/tests/test_environ.py index 13f06d146..2c05a8434 100644 --- a/tests/test_environ.py +++ b/tests/test_environ.py @@ -151,7 +151,7 @@ def test_swap_exception_replacement(): @skip_if_on_unix -def test_locate_binary_on_windows(xonsh_builtins): +def test_locate_binary_on_windows(xession): files = ("file1.exe", "FILE2.BAT", "file3.txt") with TemporaryDirectory() as tmpdir: tmpdir = os.path.realpath(tmpdir) @@ -159,10 +159,8 @@ def test_locate_binary_on_windows(xonsh_builtins): fpath = os.path.join(tmpdir, fname) with open(fpath, "w") as f: f.write(fpath) - xonsh_builtins.__xonsh__.env.update( - {"PATH": [tmpdir], "PATHEXT": [".COM", ".EXE", ".BAT"]} - ) - xonsh_builtins.__xonsh__.commands_cache = CommandsCache() + xession.env.update({"PATH": [tmpdir], "PATHEXT": [".COM", ".EXE", ".BAT"]}) + xession.commands_cache = CommandsCache() assert locate_binary("file1") == os.path.join(tmpdir, "file1.exe") assert locate_binary("file1.exe") == os.path.join(tmpdir, "file1.exe") assert locate_binary("file2") == os.path.join(tmpdir, "FILE2.BAT") @@ -170,13 +168,13 @@ def test_locate_binary_on_windows(xonsh_builtins): assert locate_binary("file3") is None -def test_event_on_envvar_change(xonsh_builtins): +def test_event_on_envvar_change(xession): env = Env(TEST=0) - xonsh_builtins.__xonsh__.env = env + xession.env = env share = [] # register - @xonsh_builtins.events.on_envvar_change + @xession.builtins.events.on_envvar_change def handler(name, oldvalue, newvalue, **kwargs): share.extend((name, oldvalue, newvalue)) @@ -186,13 +184,13 @@ def test_event_on_envvar_change(xonsh_builtins): assert share == ["TEST", 0, 1] -def test_event_on_envvar_new(xonsh_builtins): +def test_event_on_envvar_new(xession): env = Env() - xonsh_builtins.__xonsh__.env = env + xession.env = env share = [] # register - @xonsh_builtins.events.on_envvar_new + @xession.builtins.events.on_envvar_new def handler(name, value, **kwargs): share.extend((name, value)) @@ -202,13 +200,13 @@ def test_event_on_envvar_new(xonsh_builtins): assert share == ["TEST", 1] -def test_event_on_envvar_change_from_none_value(xonsh_builtins): +def test_event_on_envvar_change_from_none_value(xession): env = Env(TEST=None) - xonsh_builtins.__xonsh__.env = env + xession.env = env share = [] # register - @xonsh_builtins.events.on_envvar_change + @xession.builtins.events.on_envvar_change def handler(name, oldvalue, newvalue, **kwargs): share.extend((name, oldvalue, newvalue)) @@ -219,13 +217,13 @@ def test_event_on_envvar_change_from_none_value(xonsh_builtins): @pytest.mark.parametrize("val", [1, None, True, "ok"]) -def test_event_on_envvar_change_no_fire_when_value_is_same(val, xonsh_builtins): +def test_event_on_envvar_change_no_fire_when_value_is_same(val, xession): env = Env(TEST=val) - xonsh_builtins.__xonsh__.env = env + xession.env = env share = [] # register - @xonsh_builtins.events.on_envvar_change + @xession.builtins.events.on_envvar_change def handler(name, oldvalue, newvalue, **kwargs): share.extend((name, oldvalue, newvalue)) @@ -235,17 +233,17 @@ def test_event_on_envvar_change_no_fire_when_value_is_same(val, xonsh_builtins): assert share == [] -def test_events_on_envvar_called_in_right_order(xonsh_builtins): +def test_events_on_envvar_called_in_right_order(xession): env = Env() - xonsh_builtins.__xonsh__.env = env + xession.env = env share = [] # register - @xonsh_builtins.events.on_envvar_new + @xession.builtins.events.on_envvar_new def handler(name, value, **kwargs): share[:] = ["new"] - @xonsh_builtins.events.on_envvar_change + @xession.builtins.events.on_envvar_change def handler1(name, oldvalue, newvalue, **kwargs): share[:] = ["change"] @@ -320,13 +318,13 @@ def test_lscolors_target(xonsh_builtins): ("pi", ("BACKGROUND_BLACK", "YELLOW"), None, "delete existing key"), ], ) -def test_lscolors_events(key_in, old_in, new_in, test, xonsh_builtins): +def test_lscolors_events(key_in, old_in, new_in, test, xession): lsc = LsColors.fromstring("fi=0:di=01;34:pi=40;33") # corresponding colors: [('RESET',), ('BOLD_CYAN',), ('BOLD_CYAN',), ('BACKGROUND_BLACK', 'YELLOW')] event_fired = False - @xonsh_builtins.events.on_lscolors_change + @xession.builtins.events.on_lscolors_change def handler(key, oldvalue, newvalue, **kwargs): nonlocal old_in, new_in, key_in, event_fired assert ( @@ -334,7 +332,7 @@ def test_lscolors_events(key_in, old_in, new_in, test, xonsh_builtins): ), "Old and new event values match" event_fired = True - xonsh_builtins.__xonsh__.env["LS_COLORS"] = lsc + xession.env["LS_COLORS"] = lsc if new_in is None: lsc.pop(key_in, "argle") diff --git a/tests/test_events.py b/tests/test_events.py index 842e8f0e4..c14e33c89 100644 --- a/tests/test_events.py +++ b/tests/test_events.py @@ -156,8 +156,8 @@ def test_load_2nd_call(events): assert called == 1 -def test_typos(xonsh_builtins): - for name, ev in vars(xonsh_builtins.events).items(): +def test_typos(xession): + for name, ev in vars(xession.builtins.events).items(): if "pytest" in name: continue assert inspect.getdoc(ev) diff --git a/tests/test_history_dummy.py b/tests/test_history_dummy.py index cbc9604cd..d0b1aa6c4 100644 --- a/tests/test_history_dummy.py +++ b/tests/test_history_dummy.py @@ -5,16 +5,17 @@ from xonsh.history.dummy import DummyHistory from xonsh.history.main import construct_history -def test_construct_history_str(xonsh_builtins): - xonsh_builtins.__xonsh__.env["XONSH_HISTORY_BACKEND"] = "dummy" + +def test_construct_history_str(xession): + xession.env["XONSH_HISTORY_BACKEND"] = "dummy" assert isinstance(construct_history(), DummyHistory) -def test_construct_history_class(xonsh_builtins): - xonsh_builtins.__xonsh__.env["XONSH_HISTORY_BACKEND"] = DummyHistory +def test_construct_history_class(xession): + xession.env["XONSH_HISTORY_BACKEND"] = DummyHistory assert isinstance(construct_history(), DummyHistory) -def test_construct_history_instance(xonsh_builtins): - xonsh_builtins.__xonsh__.env["XONSH_HISTORY_BACKEND"] = DummyHistory() +def test_construct_history_instance(xession): + xession.env["XONSH_HISTORY_BACKEND"] = DummyHistory() assert isinstance(construct_history(), DummyHistory) diff --git a/tests/test_history_json.py b/tests/test_history_json.py index a219dca15..6c271b1b3 100644 --- a/tests/test_history_json.py +++ b/tests/test_history_json.py @@ -23,24 +23,22 @@ IGNORE_OPTS = ",".join(["ignoredups", "ignoreerr", "ignorespace"]) @pytest.fixture -def hist(): - h = JsonHistory( - filename="xonsh-HISTORY-TEST.json", here="yup", sessionid="SESSIONID", gc=False - ) +def hist(tmpdir, xession): + file = tmpdir / "xonsh-HISTORY-TEST.json" + h = JsonHistory(filename=str(file), here="yup", sessionid="SESSIONID", gc=False) yield h - os.remove(h.filename) -def test_hist_init(hist): +def test_hist_init(hist, xession): """Test initialization of the shell history.""" with LazyJSON(hist.filename) as lj: obs = lj["here"] assert "yup" == obs -def test_hist_append(hist, xonsh_builtins): +def test_hist_append(hist, xession): """Verify appending to the history works.""" - xonsh_builtins.__xonsh__.env["HISTCONTROL"] = set() + xession.env["HISTCONTROL"] = set() hf = hist.append({"inp": "still alive", "rtn": 0}) assert hf is None assert "still alive" == hist.buffer[0]["inp"] @@ -56,11 +54,11 @@ def test_hist_append(hist, xonsh_builtins): assert 0 == hist.rtns[-1] -def test_hist_flush(hist, xonsh_builtins): +def test_hist_flush(hist, xession): """Verify explicit flushing of the history works.""" hf = hist.flush() assert hf is None - xonsh_builtins.__xonsh__.env["HISTCONTROL"] = set() + xession.env["HISTCONTROL"] = set() hist.append({"inp": "still alive?", "rtn": 0, "out": "yes"}) hf = hist.flush() assert hf is not None @@ -73,12 +71,12 @@ def test_hist_flush(hist, xonsh_builtins): assert not cmd.get("out", None) -def test_hist_flush_with_store_stdout(hist, xonsh_builtins): +def test_hist_flush_with_store_stdout(hist, xession): """Verify explicit flushing of the history works.""" hf = hist.flush() assert hf is None - xonsh_builtins.__xonsh__.env["HISTCONTROL"] = set() - xonsh_builtins.__xonsh__.env["XONSH_STORE_STDOUT"] = True + xession.env["HISTCONTROL"] = set() + xession.env["XONSH_STORE_STDOUT"] = True hist.append({"inp": "still alive?", "rtn": 0, "out": "yes"}) hf = hist.flush() assert hf is not None @@ -90,7 +88,7 @@ def test_hist_flush_with_store_stdout(hist, xonsh_builtins): assert lj["cmds"][0]["out"].strip() == "yes" -def test_hist_flush_with_store_cwd(hist, xonsh_builtins): +def test_hist_flush_with_store_cwd(hist, xession): hf = hist.flush() assert hf is None @@ -109,14 +107,14 @@ def test_hist_flush_with_store_cwd(hist, xonsh_builtins): with LazyJSON(hist.filename) as lj: assert len(lj["cmds"]) == 2 assert lj["cmds"][0]["cwd"] == "/tmp" - assert "cwd" not in lj["cmds"][1] + assert "cwd" not in lj["cmds"][1] -def test_hist_flush_with_hist_control(hist, xonsh_builtins): +def test_hist_flush_with_hist_control(hist, xession): """Verify explicit flushing of the history works.""" hf = hist.flush() assert hf is None - xonsh_builtins.__xonsh__.env["HISTCONTROL"] = IGNORE_OPTS + xession.env["HISTCONTROL"] = IGNORE_OPTS hist.append({"inp": "ls foo1", "rtn": 0}) hist.append({"inp": "ls foo1", "rtn": 1}) hist.append({"inp": "ls foo1", "rtn": 0}) @@ -135,9 +133,9 @@ def test_hist_flush_with_hist_control(hist, xonsh_builtins): assert [x["rtn"] for x in cmds] == [0, 0] -def test_cmd_field(hist, xonsh_builtins): +def test_cmd_field(hist, xession): # in-memory - xonsh_builtins.__xonsh__.env["HISTCONTROL"] = set() + xession.env["HISTCONTROL"] = set() hf = hist.append({"inp": "ls foo", "rtn": 1}) assert hf is None assert 1 == hist.rtns[0] @@ -166,11 +164,11 @@ def test_cmd_field(hist, xonsh_builtins): ("-4:-2", CMDS[-4:-2], (len(CMDS) - 4, 1)), ], ) -def test_show_cmd_numerate(inp, commands, offset, hist, xonsh_builtins, capsys): +def test_show_cmd_numerate(inp, commands, offset, hist, xession, capsys): """Verify that CLI history commands work.""" base_idx, step = offset - xonsh_builtins.__xonsh__.history = hist - xonsh_builtins.__xonsh__.env["HISTCONTROL"] = set() + xession.history = hist + xession.env["HISTCONTROL"] = set() for ts, cmd in enumerate(CMDS): # populate the shell history hist.append({"inp": cmd, "rtn": 0, "ts": (ts + 1, ts + 1.5)}) @@ -185,10 +183,10 @@ def test_show_cmd_numerate(inp, commands, offset, hist, xonsh_builtins, capsys): assert out.rstrip() == exp -def test_histcontrol(hist, xonsh_builtins): +def test_histcontrol(hist, xession): """Test HISTCONTROL=ignoredups,ignoreerr,ignorespacee""" - xonsh_builtins.__xonsh__.env["HISTCONTROL"] = IGNORE_OPTS + xession.env["HISTCONTROL"] = IGNORE_OPTS assert len(hist.buffer) == 0 # An error, buffer remains empty @@ -324,8 +322,8 @@ def test_parser_show(args, exp): ), ], ) -def test_history_getitem(index, exp, hist, xonsh_builtins): - xonsh_builtins.__xonsh__.env["HISTCONTROL"] = set() +def test_history_getitem(index, exp, hist, xession): + xession.env["HISTCONTROL"] = set() attrs = ("inp", "out", "rtn", "ts") for ts, cmd in enumerate(CMDS): # populate the shell history @@ -391,8 +389,10 @@ SEC_PER_DAY = 24 * 60 * 60 # 11p every day. The smallest interval is thus ten hours (from 11p to 9a), so # we can't spend more than five hours executing the tests. MAX_RUNTIME = 30 * 60 -MIN_DIFF = min(HISTORY_FILES_LIST[i+1][0] - HISTORY_FILES_LIST[i][0] - for i in range(len(HISTORY_FILES_LIST) - 1)) +MIN_DIFF = min( + HISTORY_FILES_LIST[i + 1][0] - HISTORY_FILES_LIST[i][0] + for i in range(len(HISTORY_FILES_LIST) - 1) +) assert MAX_RUNTIME < MIN_DIFF / 2 @@ -493,9 +493,7 @@ assert MAX_RUNTIME < MIN_DIFF / 2 ), ], ) -def test__xhj_gc_xx_to_rmfiles( - fn, hsize, in_files, exp_size, exp_files, xonsh_builtins -): +def test__xhj_gc_xx_to_rmfiles(fn, hsize, in_files, exp_size, exp_files, xession): act_size, act_files = fn(hsize, in_files) @@ -510,63 +508,63 @@ def test__xhj_gc_xx_to_rmfiles( assert act_size == exp_size -def test_hist_clear_cmd(hist, xonsh_builtins, capsys, tmpdir): +def test_hist_clear_cmd(hist, xession, capsys, tmpdir): """Verify that the CLI history clear command works.""" - xonsh_builtins.__xonsh__.env.update({"XONSH_DATA_DIR": str(tmpdir)}) - xonsh_builtins.__xonsh__.history = hist - xonsh_builtins.__xonsh__.env["HISTCONTROL"] = set() + xession.env.update({"XONSH_DATA_DIR": str(tmpdir)}) + xession.history = hist + xession.env["HISTCONTROL"] = set() for ts, cmd in enumerate(CMDS): # populate the shell history hist.append({"inp": cmd, "rtn": 0, "ts": (ts + 1, ts + 1.5)}) - assert len(xonsh_builtins.__xonsh__.history) == 6 + assert len(xession.history) == 6 history_main(["clear"]) out, err = capsys.readouterr() assert err.rstrip() == "History cleared" - assert len(xonsh_builtins.__xonsh__.history) == 0 + assert len(xession.history) == 0 -def test_hist_off_cmd(hist, xonsh_builtins, capsys, tmpdir): +def test_hist_off_cmd(hist, xession, capsys, tmpdir): """Verify that the CLI history off command works.""" - xonsh_builtins.__xonsh__.env.update({"XONSH_DATA_DIR": str(tmpdir)}) - xonsh_builtins.__xonsh__.history = hist - xonsh_builtins.__xonsh__.env["HISTCONTROL"] = set() + xession.env.update({"XONSH_DATA_DIR": str(tmpdir)}) + xession.history = hist + xession.env["HISTCONTROL"] = set() for ts, cmd in enumerate(CMDS): # populate the shell history hist.append({"inp": cmd, "rtn": 0, "ts": (ts + 1, ts + 1.5)}) - assert len(xonsh_builtins.__xonsh__.history) == 6 + assert len(xession.history) == 6 history_main(["off"]) out, err = capsys.readouterr() assert err.rstrip() == "History off" - assert len(xonsh_builtins.__xonsh__.history) == 0 + assert len(xession.history) == 0 for ts, cmd in enumerate(CMDS): # attempt to populate the shell history hist.append({"inp": cmd, "rtn": 0, "ts": (ts + 1, ts + 1.5)}) - assert len(xonsh_builtins.__xonsh__.history) == 0 + assert len(xession.history) == 0 -def test_hist_on_cmd(hist, xonsh_builtins, capsys, tmpdir): +def test_hist_on_cmd(hist, xession, capsys, tmpdir): """Verify that the CLI history on command works.""" - xonsh_builtins.__xonsh__.env.update({"XONSH_DATA_DIR": str(tmpdir)}) - xonsh_builtins.__xonsh__.history = hist - xonsh_builtins.__xonsh__.env["HISTCONTROL"] = set() + xession.env.update({"XONSH_DATA_DIR": str(tmpdir)}) + xession.history = hist + xession.env["HISTCONTROL"] = set() for ts, cmd in enumerate(CMDS): # populate the shell history hist.append({"inp": cmd, "rtn": 0, "ts": (ts + 1, ts + 1.5)}) - assert len(xonsh_builtins.__xonsh__.history) == 6 + assert len(xession.history) == 6 history_main(["off"]) history_main(["on"]) out, err = capsys.readouterr() assert err.rstrip().endswith("History on") - assert len(xonsh_builtins.__xonsh__.history) == 0 + assert len(xession.history) == 0 for ts, cmd in enumerate(CMDS): # populate the shell history hist.append({"inp": cmd, "rtn": 0, "ts": (ts + 1, ts + 1.5)}) - assert len(xonsh_builtins.__xonsh__.history) == 6 + assert len(xession.history) == 6 diff --git a/tests/test_history_sqlite.py b/tests/test_history_sqlite.py index 720581f46..a3b0ad797 100644 --- a/tests/test_history_sqlite.py +++ b/tests/test_history_sqlite.py @@ -19,9 +19,9 @@ def hist(): os.remove(h.filename) -def test_hist_append(hist, xonsh_builtins): +def test_hist_append(hist, xession): """Verify appending to the history works.""" - xonsh_builtins.__xonsh__.env["HISTCONTROL"] = set() + xession.env["HISTCONTROL"] = set() hf = hist.append({"inp": "still alive", "rtn": 1}) assert hf is None items = list(hist.items()) @@ -36,8 +36,8 @@ def test_hist_append(hist, xonsh_builtins): assert list(hist.all_items()) == items -def test_hist_attrs(hist, xonsh_builtins): - xonsh_builtins.__xonsh__.env["HISTCONTROL"] = set() +def test_hist_attrs(hist, xession): + xession.env["HISTCONTROL"] = set() hf = hist.append({"inp": "ls foo", "rtn": 1}) assert hf is None assert "ls foo" == hist.inps[0] @@ -73,11 +73,11 @@ CMDS = ["ls", "cat hello kitty", "abc", "def", "touch me", "grep from me"] ("-4:-2", CMDS[-4:-2], (len(CMDS) - 4, 1)), ], ) -def test_show_cmd_numerate(inp, commands, offset, hist, xonsh_builtins, capsys): +def test_show_cmd_numerate(inp, commands, offset, hist, xession, capsys): """Verify that CLI history commands work.""" base_idx, step = offset - xonsh_builtins.__xonsh__.history = hist - xonsh_builtins.__xonsh__.env["HISTCONTROL"] = set() + xession.history = hist + xession.env["HISTCONTROL"] = set() for ts, cmd in enumerate(CMDS): # populate the shell history hist.append({"inp": cmd, "rtn": 0, "ts": (ts + 1, ts + 1.5)}) @@ -92,11 +92,11 @@ def test_show_cmd_numerate(inp, commands, offset, hist, xonsh_builtins, capsys): assert out.rstrip() == exp -def test_histcontrol(hist, xonsh_builtins): +def test_histcontrol(hist, xession): """Test HISTCONTROL=ignoredups,ignoreerr""" ignore_opts = ",".join(["ignoredups", "ignoreerr", "ignorespace"]) - xonsh_builtins.__xonsh__.env["HISTCONTROL"] = ignore_opts + xession.env["HISTCONTROL"] = ignore_opts assert len(hist) == 0 # An error, items() remains empty @@ -186,10 +186,10 @@ def test_histcontrol(hist, xonsh_builtins): assert 0 == hist.rtns[-1] -def test_histcontrol_erase_dup(hist, xonsh_builtins): +def test_histcontrol_erase_dup(hist, xession): """Test HISTCONTROL=erasedups""" - xonsh_builtins.__xonsh__.env["HISTCONTROL"] = "erasedups" + xession.env["HISTCONTROL"] = "erasedups" assert len(hist) == 0 hist.append({"inp": "ls foo", "rtn": 2}) @@ -218,9 +218,9 @@ def test_histcontrol_erase_dup(hist, xonsh_builtins): ), ], ) -def test_history_getitem(index, exp, hist, xonsh_builtins): - xonsh_builtins.__xonsh__.env["HISTCONTROL"] = set() - xonsh_builtins.__xonsh__.env["XONSH_STORE_STDOUT"] = True +def test_history_getitem(index, exp, hist, xession): + xession.env["HISTCONTROL"] = set() + xession.env["XONSH_STORE_STDOUT"] = True attrs = ("inp", "out", "rtn", "ts") for ts, cmd in enumerate(CMDS): # populate the shell history @@ -234,69 +234,69 @@ def test_history_getitem(index, exp, hist, xonsh_builtins): assert (entry.cmd, entry.out, entry.rtn, entry.ts) == exp -def test_hist_clear_cmd(hist, xonsh_builtins, capsys, tmpdir): +def test_hist_clear_cmd(hist, xession, capsys, tmpdir): """Verify that the CLI history clear command works.""" - xonsh_builtins.__xonsh__.env.update({"XONSH_DATA_DIR": str(tmpdir)}) - xonsh_builtins.__xonsh__.history = hist - xonsh_builtins.__xonsh__.env["HISTCONTROL"] = set() + xession.env.update({"XONSH_DATA_DIR": str(tmpdir)}) + xession.history = hist + xession.env["HISTCONTROL"] = set() for ts, cmd in enumerate(CMDS): # populate the shell history hist.append({"inp": cmd, "rtn": 0, "ts": (ts + 1, ts + 1.5)}) - assert len(xonsh_builtins.__xonsh__.history) == 6 + assert len(xession.history) == 6 history_main(["clear"]) out, err = capsys.readouterr() assert err.rstrip() == "History cleared" - assert len(xonsh_builtins.__xonsh__.history) == 0 + assert len(xession.history) == 0 -def test_hist_off_cmd(hist, xonsh_builtins, capsys, tmpdir): +def test_hist_off_cmd(hist, xession, capsys, tmpdir): """Verify that the CLI history off command works.""" - xonsh_builtins.__xonsh__.env.update({"XONSH_DATA_DIR": str(tmpdir)}) - xonsh_builtins.__xonsh__.history = hist - xonsh_builtins.__xonsh__.env["HISTCONTROL"] = set() + xession.env.update({"XONSH_DATA_DIR": str(tmpdir)}) + xession.history = hist + xession.env["HISTCONTROL"] = set() for ts, cmd in enumerate(CMDS): # populate the shell history hist.append({"inp": cmd, "rtn": 0, "ts": (ts + 1, ts + 1.5)}) - assert len(xonsh_builtins.__xonsh__.history) == 6 + assert len(xession.history) == 6 history_main(["off"]) out, err = capsys.readouterr() assert err.rstrip() == "History off" - assert len(xonsh_builtins.__xonsh__.history) == 0 + assert len(xession.history) == 0 for ts, cmd in enumerate(CMDS): # attempt to populate the shell history hist.append({"inp": cmd, "rtn": 0, "ts": (ts + 1, ts + 1.5)}) - assert len(xonsh_builtins.__xonsh__.history) == 0 + assert len(xession.history) == 0 -def test_hist_on_cmd(hist, xonsh_builtins, capsys, tmpdir): +def test_hist_on_cmd(hist, xession, capsys, tmpdir): """Verify that the CLI history on command works.""" - xonsh_builtins.__xonsh__.env.update({"XONSH_DATA_DIR": str(tmpdir)}) - xonsh_builtins.__xonsh__.history = hist - xonsh_builtins.__xonsh__.env["HISTCONTROL"] = set() + xession.env.update({"XONSH_DATA_DIR": str(tmpdir)}) + xession.history = hist + xession.env["HISTCONTROL"] = set() for ts, cmd in enumerate(CMDS): # populate the shell history hist.append({"inp": cmd, "rtn": 0, "ts": (ts + 1, ts + 1.5)}) - assert len(xonsh_builtins.__xonsh__.history) == 6 + assert len(xession.history) == 6 history_main(["off"]) history_main(["on"]) out, err = capsys.readouterr() assert err.rstrip().endswith("History on") - assert len(xonsh_builtins.__xonsh__.history) == 0 + assert len(xession.history) == 0 for ts, cmd in enumerate(CMDS): # populate the shell history hist.append({"inp": cmd, "rtn": 0, "ts": (ts + 1, ts + 1.5)}) - assert len(xonsh_builtins.__xonsh__.history) == 6 + assert len(xession.history) == 6 -def test_hist_store_cwd(hist, xonsh_builtins): +def test_hist_store_cwd(hist, xession): hist.save_cwd = True hist.append({"inp": "# saving with cwd", "rtn": 0, "out": "yes", "cwd": "/tmp"}) hist.save_cwd = False @@ -304,4 +304,4 @@ def test_hist_store_cwd(hist, xonsh_builtins): cmds = [i for i in hist.all_items()] assert cmds[0]["cwd"] == "/tmp" - assert cmds[1]["cwd"] is None \ No newline at end of file + assert cmds[1]["cwd"] is None diff --git a/tests/test_imphooks.py b/tests/test_imphooks.py index 225adb36b..c192767bc 100644 --- a/tests/test_imphooks.py +++ b/tests/test_imphooks.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- """Testing xonsh import hooks""" import os -import builtins from importlib import import_module import pytest @@ -9,17 +8,17 @@ import pytest from xonsh import imphooks from xonsh.execer import Execer from xonsh.environ import Env -from xonsh.built_ins import unload_builtins +from xonsh.built_ins import XSH imphooks.install_import_hooks() @pytest.fixture(autouse=True) -def imp_env(xonsh_builtins): +def imp_env(xession): Execer(unload=False) - builtins.__xonsh__.env = Env({"PATH": [], "PATHEXT": []}) + xession.env = Env({"PATH": [], "PATHEXT": []}) yield - unload_builtins() + XSH.unload() def test_import(): diff --git a/tests/test_integrations.py b/tests/test_integrations.py index fb125d28b..65df0f36a 100644 --- a/tests/test_integrations.py +++ b/tests/test_integrations.py @@ -506,6 +506,10 @@ first ), ] +if not ON_WINDOWS: + ALL_PLATFORMS = tuple(ALL_PLATFORMS) + tuple(UNIX_TESTS) + + @skip_if_no_xonsh @pytest.mark.parametrize("case", ALL_PLATFORMS) def test_script(case): @@ -517,12 +521,6 @@ def test_script(case): assert exp_out == out assert exp_rtn == rtn -@skip_if_no_xonsh -@skip_if_on_windows -@pytest.mark.parametrize("case", UNIX_TESTS) -def test_unix_tests(case): - test_script(case) - ALL_PLATFORMS_STDERR = [ # test redirecting a function alias @@ -557,7 +555,11 @@ def test_script_stderr(case): ("pwd", None, lambda: os.getcwd() + "\n"), ("echo WORKING", None, "WORKING\n"), ("ls -f", lambda out: out.splitlines().sort(), os.listdir().sort()), - ("$FOO='foo' $BAR=2 xonsh -c r'echo -n $FOO$BAR'", None, "foo2",), + ( + "$FOO='foo' $BAR=2 xonsh -c r'echo -n $FOO$BAR'", + None, + "foo2", + ), ], ) def test_single_command_no_windows(cmd, fmt, exp): @@ -685,7 +687,9 @@ def test_xonsh_no_close_fds(): @skip_if_no_xonsh @pytest.mark.parametrize( "cmd, fmt, exp", - [("cat tttt | wc", lambda x: x > "", True),], # noqa E231 (black removes space) + [ + ("cat tttt | wc", lambda x: x > "", True), + ], # noqa E231 (black removes space) ) def test_pipe_between_subprocs(cmd, fmt, exp): "verify pipe between subprocesses doesn't throw an exception" diff --git a/tests/test_jupyter_kernel.py b/tests/test_jupyter_kernel.py index 375e20b01..a4792290d 100644 --- a/tests/test_jupyter_kernel.py +++ b/tests/test_jupyter_kernel.py @@ -9,6 +9,7 @@ from tests.test_ptk_completer import EXPANSION_CASES XonshKernel = None + @pytest.fixture(autouse=True) def setup(monkeypatch): global XonshKernel @@ -17,15 +18,17 @@ def setup(monkeypatch): monkeypatch.setitem(sys.modules, "zmq.eventloop", MagicMock()) monkeypatch.setitem(sys.modules, "zmq.error", MagicMock()) import xonsh.jupyter_kernel + XonshKernel = xonsh.jupyter_kernel.XonshKernel -@pytest.mark.parametrize( - "code, index, expected_args", - EXPANSION_CASES -) +@pytest.mark.parametrize("code, index, expected_args", EXPANSION_CASES) def test_completion_alias_expansion( - code, index, expected_args, monkeypatch, xonsh_builtins, + code, + index, + expected_args, + monkeypatch, + xession, ): xonsh_completer_mock = MagicMock(spec=Completer) xonsh_completer_mock.complete.return_value = set(), 0 @@ -33,12 +36,15 @@ def test_completion_alias_expansion( kernel = MagicMock() kernel.completer = xonsh_completer_mock - monkeypatch.setattr("builtins.aliases", Aliases(gb=["git branch"])) - monkeypatch.setattr(xonsh_builtins.__xonsh__.shell, "ctx", None, raising=False) + monkeypatch.setattr(xession, "aliases", Aliases(gb=["git branch"])) + monkeypatch.setattr(xession.shell, "ctx", None, raising=False) XonshKernel.do_complete(kernel, code, index) mock_call = xonsh_completer_mock.complete.call_args args, kwargs = mock_call expected_args["self"] = None expected_args["ctx"] = None - assert signature(Completer.complete).bind(None, *args, **kwargs).arguments == expected_args + assert ( + signature(Completer.complete).bind(None, *args, **kwargs).arguments + == expected_args + ) diff --git a/tests/test_lexer.py b/tests/test_lexer.py index 71b53725e..7a1772a59 100644 --- a/tests/test_lexer.py +++ b/tests/test_lexer.py @@ -462,18 +462,21 @@ def test_lexer_split(s, exp): assert exp == obs -@pytest.mark.parametrize("s", ( - "()", # sanity - "(", - ")", - "))", - "'string\nliteral", - "'''string\nliteral", - "string\nliteral'", - "\"", - "'", - "\"\"\"", -)) +@pytest.mark.parametrize( + "s", + ( + "()", # sanity + "(", + ")", + "))", + "'string\nliteral", + "'''string\nliteral", + "string\nliteral'", + '"', + "'", + '"""', + ), +) def test_tolerant_lexer(s): lexer = Lexer(tolerant=True) lexer.input(s) diff --git a/tests/test_main.py b/tests/test_main.py index a692f8e6b..2e32a741c 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -20,59 +20,55 @@ def Shell(*args, **kwargs): @pytest.fixture -def shell(xonsh_builtins, monkeypatch): +def shell(xession, monkeypatch): """Xonsh Shell Mock""" - if hasattr(builtins, "__xonsh__"): - builtins.__xonsh__.unlink_builtins() - del builtins.__xonsh__ - for xarg in dir(builtins): - if "__xonsh_" in xarg: - delattr(builtins, xarg) gc.collect() Shell.shell_type_aliases = {"rl": "readline"} monkeypatch.setattr(xonsh.main, "Shell", Shell) -def test_premain_no_arg(shell, monkeypatch): +def test_premain_no_arg(shell, monkeypatch, xession): monkeypatch.setattr(sys.stdin, "isatty", lambda: True) xonsh.main.premain([]) - assert builtins.__xonsh__.env.get("XONSH_LOGIN") + assert xession.env.get("XONSH_LOGIN") -def test_premain_interactive(shell): +def test_premain_interactive(shell, xession): xonsh.main.premain(["-i"]) - assert builtins.__xonsh__.env.get("XONSH_INTERACTIVE") + assert xession.env.get("XONSH_INTERACTIVE") -def test_premain_login_command(shell): +def test_premain_login_command(shell, xession): xonsh.main.premain(["-l", "-c", 'echo "hi"']) - assert builtins.__xonsh__.env.get("XONSH_LOGIN") + assert xession.env.get("XONSH_LOGIN") -def test_premain_login(shell): +def test_premain_login(shell, xession): xonsh.main.premain(["-l"]) - assert builtins.__xonsh__.env.get("XONSH_LOGIN") + assert xession.env.get("XONSH_LOGIN") -def test_premain_D(shell): +def test_premain_D(shell, xession): xonsh.main.premain(["-DTEST1=1616", "-DTEST2=LOL"]) - assert builtins.__xonsh__.env.get("TEST1") == "1616" - assert builtins.__xonsh__.env.get("TEST2") == "LOL" + assert xession.env.get("TEST1") == "1616" + assert xession.env.get("TEST2") == "LOL" -def test_premain_custom_rc(shell, tmpdir, monkeypatch): +def test_premain_custom_rc(shell, tmpdir, monkeypatch, xession): monkeypatch.setattr(sys.stdin, "isatty", lambda: True) monkeypatch.setitem(os.environ, "XONSH_CACHE_SCRIPTS", "False") f = tmpdir.join("wakkawakka") f.write("print('hi')") args = xonsh.main.premain(["--rc", f.strpath]) assert args.mode == XonshMode.interactive - assert f.strpath in builtins.__xonsh__.env.get("XONSHRC") + assert f.strpath in xession.env.get("XONSHRC") + @pytest.mark.skipif( - ON_WINDOWS and sys.version[:3] == "3.8", reason="weird failure on py38+windows", -) -def test_rc_with_modules(shell, tmpdir, monkeypatch, capsys): + ON_WINDOWS and sys.version[:3] == "3.8", + reason="weird failure on py38+windows", +) +def test_rc_with_modules(shell, tmpdir, monkeypatch, capsys, xession): """Test that an RC file can load modules inside the same folder it is located in.""" monkeypatch.setattr(sys.stdin, "isatty", lambda: True) @@ -84,11 +80,9 @@ def test_rc_with_modules(shell, tmpdir, monkeypatch, capsys): rc.write("from my_python_module import *\nfrom my_xonsh_module import *") xonsh.main.premain(["--rc", rc.strpath]) - assert rc.strpath in builtins.__xonsh__.env.get("XONSHRC") + assert rc.strpath in xession.env.get("XONSHRC") assert ( - builtins.__xonsh__.env.get("LOADED_RC_FILES")[ - builtins.__xonsh__.env.get("XONSHRC").index(rc.strpath) - ] + xession.env.get("LOADED_RC_FILES")[xession.env.get("XONSHRC").index(rc.strpath)] is True ) @@ -130,7 +124,10 @@ def test_rcdir_empty(shell, tmpdir, monkeypatch, capsys): rcdir = tmpdir.join("rc.d") rcdir.mkdir() + rc = tmpdir.join("rc.xsh") + rc.write_binary(b"") monkeypatch.setattr(sys.stdin, "isatty", lambda: True) + monkeypatch.setitem(os.environ, "XONSHRC", str(rc)) monkeypatch.setitem(os.environ, "XONSHRC_DIR", str(rcdir)) xonsh.main.premain([]) @@ -241,7 +238,7 @@ def test_script_startup(shell, tmpdir, monkeypatch, capsys, args, expected): assert xargs.file is not None -def test_rcdir_ignored_with_rc(shell, tmpdir, monkeypatch, capsys): +def test_rcdir_ignored_with_rc(shell, tmpdir, monkeypatch, capsys, xession): """Test that --rc suppresses loading XONSHRC_DIRs""" rcdir = tmpdir.join("rc.d") @@ -255,11 +252,11 @@ def test_rcdir_ignored_with_rc(shell, tmpdir, monkeypatch, capsys): stdout, stderr = capsys.readouterr() assert "RCDIR" not in stdout assert "RCFILE" in stdout - assert not builtins.__xonsh__.env.get("XONSHRC_DIR") + assert not xession.env.get("XONSHRC_DIR") @pytest.mark.skipif(ON_WINDOWS, reason="See https://github.com/xonsh/xonsh/issues/3936") -def test_rc_with_modified_path(shell, tmpdir, monkeypatch, capsys): +def test_rc_with_modified_path(shell, tmpdir, monkeypatch, capsys, xession): """Test that an RC file can edit the sys.path variable without losing those values.""" monkeypatch.setattr(sys.stdin, "isatty", lambda: True) @@ -269,11 +266,9 @@ def test_rc_with_modified_path(shell, tmpdir, monkeypatch, capsys): rc.write(f"import sys\nsys.path.append('{tmpdir.strpath}')\nprint('Hello, World!')") xonsh.main.premain(["--rc", rc.strpath]) - assert rc.strpath in builtins.__xonsh__.env.get("XONSHRC") + assert rc.strpath in xession.env.get("XONSHRC") assert ( - builtins.__xonsh__.env.get("LOADED_RC_FILES")[ - builtins.__xonsh__.env.get("XONSHRC").index(rc.strpath) - ] + xession.env.get("LOADED_RC_FILES")[xession.env.get("XONSHRC").index(rc.strpath)] is True ) @@ -285,7 +280,7 @@ def test_rc_with_modified_path(shell, tmpdir, monkeypatch, capsys): assert tmpdir.strpath in sys.path -def test_rc_with_failing_module(shell, tmpdir, monkeypatch, capsys): +def test_rc_with_failing_module(shell, tmpdir, monkeypatch, capsys, xession): """Test that an RC file which imports a module that throws an exception .""" monkeypatch.setattr(sys.stdin, "isatty", lambda: True) @@ -296,11 +291,9 @@ def test_rc_with_failing_module(shell, tmpdir, monkeypatch, capsys): rc.write("from my_failing_module import *") xonsh.main.premain(["--rc", rc.strpath]) - assert rc.strpath in builtins.__xonsh__.env.get("XONSHRC") + assert rc.strpath in xession.env.get("XONSHRC") assert ( - builtins.__xonsh__.env.get("LOADED_RC_FILES")[ - builtins.__xonsh__.env.get("XONSHRC").index(rc.strpath) - ] + xession.env.get("LOADED_RC_FILES")[xession.env.get("XONSHRC").index(rc.strpath)] is False ) @@ -317,12 +310,12 @@ def test_no_rc_with_script(shell, tmpdir): assert not (args.mode == XonshMode.interactive) -def test_force_interactive_rc_with_script(shell, tmpdir): +def test_force_interactive_rc_with_script(shell, tmpdir, xession): xonsh.main.premain(["-i", "tests/sample.xsh"]) - assert builtins.__xonsh__.env.get("XONSH_INTERACTIVE") + assert xession.env.get("XONSH_INTERACTIVE") -def test_force_interactive_custom_rc_with_script(shell, tmpdir, monkeypatch): +def test_force_interactive_custom_rc_with_script(shell, tmpdir, monkeypatch, xession): """Calling a custom RC file on a script-call with the interactive flag should run interactively """ @@ -331,7 +324,7 @@ def test_force_interactive_custom_rc_with_script(shell, tmpdir, monkeypatch): f.write("print('hi')") args = xonsh.main.premain(["-i", "--rc", f.strpath, "tests/sample.xsh"]) assert args.mode == XonshMode.interactive - assert f.strpath in builtins.__xonsh__.env.get("XONSHRC") + assert f.strpath in xession.env.get("XONSHRC") def test_custom_rc_with_script(shell, tmpdir): @@ -344,23 +337,23 @@ def test_custom_rc_with_script(shell, tmpdir): assert not (args.mode == XonshMode.interactive) -def test_premain_no_rc(shell, tmpdir): +def test_premain_no_rc(shell, tmpdir, xession): xonsh.main.premain(["--no-rc", "-i"]) - assert not builtins.__xonsh__.env.get("XONSHRC") - assert not builtins.__xonsh__.env.get("XONSHRC_DIR") + assert not xession.env.get("XONSHRC") + assert not xession.env.get("XONSHRC_DIR") @pytest.mark.parametrize( "arg", ["", "-i", "-vERSION", "-hAALP", "TTTT", "-TT", "--TTT"] ) -def test_premain_with_file_argument(arg, shell): +def test_premain_with_file_argument(arg, shell, xession): xonsh.main.premain(["tests/sample.xsh", arg]) - assert not (builtins.__xonsh__.env.get("XONSH_INTERACTIVE")) + assert not (xession.env.get("XONSH_INTERACTIVE")) -def test_premain_interactive__with_file_argument(shell): +def test_premain_interactive__with_file_argument(shell, xession): xonsh.main.premain(["-i", "tests/sample.xsh"]) - assert builtins.__xonsh__.env.get("XONSH_INTERACTIVE") + assert xession.env.get("XONSH_INTERACTIVE") @pytest.mark.parametrize("case", ["----", "--hep", "-TT", "--TTTT"]) diff --git a/tests/test_man.py b/tests/test_man.py index 093395b2e..154664e13 100644 --- a/tests/test_man.py +++ b/tests/test_man.py @@ -5,18 +5,24 @@ from xonsh.completers.man import complete_from_man from tools import skip_if_on_windows -from xonsh.parsers.completion_context import CompletionContext, CommandContext, CommandArg +from xonsh.parsers.completion_context import ( + CompletionContext, + CommandContext, + CommandArg, +) @skip_if_on_windows -def test_man_completion(monkeypatch, tmpdir, xonsh_builtins): +def test_man_completion(monkeypatch, tmpdir, xession): tempdir = tmpdir.mkdir("test_man") monkeypatch.setitem( os.environ, "MANPATH", os.path.dirname(os.path.abspath(__file__)) ) - xonsh_builtins.__xonsh__.env.update({"XONSH_DATA_DIR": str(tempdir)}) - completions = complete_from_man(CompletionContext( - CommandContext(args=(CommandArg("yes"),), arg_index=1, prefix="--") - )) + xession.env.update({"XONSH_DATA_DIR": str(tempdir)}) + completions = complete_from_man( + CompletionContext( + CommandContext(args=(CommandArg("yes"),), arg_index=1, prefix="--") + ) + ) assert "--version" in completions assert "--help" in completions diff --git a/tests/test_parser.py b/tests/test_parser.py index 9b1b5486a..7e7915aea 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -1,15 +1,13 @@ # -*- coding: utf-8 -*- """Tests the xonsh parser.""" import ast -import builtins -import logging import textwrap import itertools -import traceback import pytest from xonsh.ast import AST, With, Pass, Str, Call +from xonsh.built_ins import XSH from xonsh.parser import Parser from xonsh.parsers.fstring_adaptor import FStringAdaptor @@ -45,7 +43,7 @@ def check_stmts(inp, run=True, mode="exec", debug_level=0): def check_xonsh_ast(xenv, inp, run=True, mode="eval", debug_level=0, return_obs=False): - builtins.__xonsh__.env = xenv + XSH.env = xenv obs = PARSER.parse(inp, debug_level=debug_level) if obs is None: return # comment only @@ -169,7 +167,7 @@ def test_fstring_adaptor(inp, exp): assert isinstance(joined_str_node, ast.JoinedStr) node = ast.Expression(body=joined_str_node) code = compile(node, "", mode="eval") - builtins.__xonsh__.env = {"HOME": "/foo/bar", "FOO": "HO", "BAR": "ME"} + XSH.env = {"HOME": "/foo/bar", "FOO": "HO", "BAR": "ME"} obs = eval(code) assert exp == obs diff --git a/tests/test_path_completers.py b/tests/test_path_completers.py index 1d096ce00..190340e6a 100644 --- a/tests/test_path_completers.py +++ b/tests/test_path_completers.py @@ -5,7 +5,7 @@ import xonsh.completers.path as xcp @pytest.fixture(autouse=True) -def xonsh_execer_autouse(xonsh_builtins, xonsh_execer): +def xonsh_execer_autouse(xession, xonsh_execer): return xonsh_execer @@ -14,8 +14,8 @@ def test_pattern_need_quotes(): xcp.PATTERN_NEED_QUOTES.match("") -def test_complete_path(xonsh_builtins, completion_context_parse): - xonsh_builtins.__xonsh__.env = { +def test_complete_path(xession, completion_context_parse): + xession.env = { "CASE_SENSITIVE_COMPLETIONS": False, "GLOB_SORTED": True, "SUBSEQUENCE_PATH_COMPLETION": False, @@ -27,8 +27,8 @@ def test_complete_path(xonsh_builtins, completion_context_parse): @patch("xonsh.completers.path._add_cdpaths") -def test_cd_path_no_cd(mock_add_cdpaths, xonsh_builtins, completion_context_parse): - xonsh_builtins.__xonsh__.env = { +def test_cd_path_no_cd(mock_add_cdpaths, xession, completion_context_parse): + xession.env = { "CASE_SENSITIVE_COMPLETIONS": False, "GLOB_SORTED": True, "SUBSEQUENCE_PATH_COMPLETION": False, @@ -41,8 +41,10 @@ def test_cd_path_no_cd(mock_add_cdpaths, xonsh_builtins, completion_context_pars @pytest.mark.parametrize("quote", ('"', "'")) -def test_complete_path_when_prefix_is_raw_path_string(quote, xonsh_builtins, completion_context_parse): - xonsh_builtins.__xonsh__.env = { +def test_complete_path_when_prefix_is_raw_path_string( + quote, xession, completion_context_parse +): + xession.env = { "CASE_SENSITIVE_COMPLETIONS": True, "GLOB_SORTED": True, "SUBSEQUENCE_PATH_COMPLETION": False, diff --git a/tests/test_pipelines.py b/tests/test_pipelines.py index 923a71d32..ac4adcec2 100644 --- a/tests/test_pipelines.py +++ b/tests/test_pipelines.py @@ -4,41 +4,67 @@ Tests for command pipelines. import os import pytest -import builtins from xonsh.platform import ON_WINDOWS from xonsh.procs.pipelines import CommandPipeline from tests.tools import skip_if_on_windows, skip_if_on_unix +from xonsh.built_ins import XSH @pytest.fixture(autouse=True) def patched_events(monkeypatch, xonsh_events, xonsh_execer): + from xonsh.jobs import tasks + + tasks.clear() # needed for ci tests - monkeypatch.setattr('builtins.events', xonsh_events, raising=False) - monkeypatch.setitem(builtins.__xonsh__.env, 'RAISE_SUBPROC_ERROR', False) # for the failing `grep` commands + monkeypatch.setitem( + XSH.env, "RAISE_SUBPROC_ERROR", False + ) # for the failing `grep` commands if ON_WINDOWS: - monkeypatch.setattr('builtins.aliases', { - "echo": "cmd /c echo".split(), - "grep": "cmd /c findstr".split(), - }, raising=False) + monkeypatch.setattr( + XSH, + "aliases", + { + "echo": "cmd /c echo".split(), + "grep": "cmd /c findstr".split(), + }, + raising=False, + ) -@pytest.mark.parametrize("cmdline, stdout, stderr", ( +@pytest.mark.parametrize( + "cmdline, stdout, stderr", + ( ("!(echo hi)", "hi\n", ""), ("!(echo hi o>e)", "", "hi\n"), - - pytest.param("![echo hi]", "hi\n", "", marks=pytest.mark.xfail( - ON_WINDOWS, reason="ConsoleParallelReader doesn't work without a real console")), - pytest.param("![echo hi o>e]", "", "hi\n", marks=pytest.mark.xfail( - ON_WINDOWS, reason="stderr isn't captured in ![] on windows")), - - pytest.param(r"!(echo 'hi\nho')", "hi\nho\n", "", marks=skip_if_on_windows), # won't work with cmd + pytest.param( + "![echo hi]", + "hi\n", + "", + marks=pytest.mark.xfail( + ON_WINDOWS, + reason="ConsoleParallelReader doesn't work without a real console", + ), + ), + pytest.param( + "![echo hi o>e]", + "", + "hi\n", + marks=pytest.mark.xfail( + ON_WINDOWS, reason="stderr isn't captured in ![] on windows" + ), + ), + pytest.param( + r"!(echo 'hi\nho')", "hi\nho\n", "", marks=skip_if_on_windows + ), # won't work with cmd # for some reason cmd's echo adds an extra space: - pytest.param(r"!(cmd /c 'echo hi && echo ho')", "hi \nho\n", "", marks=skip_if_on_unix), - + pytest.param( + r"!(cmd /c 'echo hi && echo ho')", "hi \nho\n", "", marks=skip_if_on_unix + ), ("!(echo hi | grep h)", "hi\n", ""), ("!(echo hi | grep x)", "", ""), -)) + ), +) def test_command_pipeline_capture(cmdline, stdout, stderr, xonsh_execer): pipeline: CommandPipeline = xonsh_execer.eval(cmdline) assert pipeline.out == stdout @@ -47,12 +73,15 @@ def test_command_pipeline_capture(cmdline, stdout, stderr, xonsh_execer): assert pipeline.raw_err == stderr.replace("\n", os.linesep).encode() -@pytest.mark.parametrize("cmdline, output", ( +@pytest.mark.parametrize( + "cmdline, output", + ( ("echo hi", "hi\n"), ("echo hi | grep h", "hi\n"), ("echo hi | grep x", ""), pytest.param("echo -n hi", "hi", marks=skip_if_on_windows), -)) + ), +) def test_simple_capture(cmdline, output, xonsh_execer): assert xonsh_execer.eval(f"$({cmdline})") == output @@ -61,19 +90,22 @@ def test_raw_substitution(xonsh_execer): assert xonsh_execer.eval("$(echo @(b'bytes!'))") == "bytes!\n" -@pytest.mark.parametrize("cmdline, result", ( +@pytest.mark.parametrize( + "cmdline, result", + ( ("bool(!(echo 1))", True), ("bool(!(nocommand))", False), ("int(!(echo 1))", 0), ("int(!(nocommand))", 1), ("hash(!(echo 1))", 0), ("hash(!(nocommand))", 1), - ("str(!(echo 1))", '1\n'), - ("str(!(nocommand))", ''), + ("str(!(echo 1))", "1\n"), + ("str(!(nocommand))", ""), ("!(echo 1) == 0", True), ("!(nocommand) == 1", True), pytest.param("!(echo -n str) == 'str'", True, marks=skip_if_on_windows), ("!(nocommand) == ''", True), -)) + ), +) def test_casting(cmdline, result, xonsh_execer): assert xonsh_execer.eval(f"{cmdline}") == result diff --git a/tests/test_ptk_completer.py b/tests/test_ptk_completer.py index 428821f53..a490d6127 100644 --- a/tests/test_ptk_completer.py +++ b/tests/test_ptk_completer.py @@ -24,9 +24,7 @@ from xonsh.ptk_shell.completer import PromptToolkitCompleter ("x", 5, PTKCompletion("x", -5, "x")), ], ) -def test_rich_completion( - completion, lprefix, ptk_completion, monkeypatch, xonsh_builtins -): +def test_rich_completion(completion, lprefix, ptk_completion, monkeypatch, xession): xonsh_completer_mock = MagicMock() xonsh_completer_mock.complete.return_value = {completion}, lprefix @@ -39,7 +37,7 @@ def test_rich_completion( document_mock.current_line = "" document_mock.cursor_position_col = 0 - monkeypatch.setattr("builtins.aliases", Aliases()) + monkeypatch.setattr(xession, "aliases", Aliases()) completions = list(ptk_completer.get_completions(document_mock, MagicMock())) if isinstance(completion, RichCompletion) and not ptk_completion: @@ -57,7 +55,8 @@ def test_rich_completion( EXPANSION_CASES = ( ( - "sanity", 6, + "sanity", + 6, dict( prefix="sanity", line="sanity", @@ -68,7 +67,8 @@ EXPANSION_CASES = ( ), ), ( - "gb ", 3, + "gb ", + 3, dict( prefix="", line="git branch ", @@ -79,7 +79,8 @@ EXPANSION_CASES = ( ), ), ( - "gb ", 1, + "gb ", + 1, dict( prefix="g", line="gb ", @@ -90,7 +91,8 @@ EXPANSION_CASES = ( ), ), ( - "gb", 0, + "gb", + 0, dict( prefix="", line="gb", @@ -101,7 +103,8 @@ EXPANSION_CASES = ( ), ), ( - " gb ", 0, + " gb ", + 0, dict( prefix="", line=" gb ", # the PTK completer `lstrip`s the line @@ -112,7 +115,8 @@ EXPANSION_CASES = ( ), ), ( - "gb --", 5, + "gb --", + 5, dict( prefix="--", line="git branch --", @@ -123,7 +127,8 @@ EXPANSION_CASES = ( ), ), ( - "nice\ngb --", 10, + "nice\ngb --", + 10, dict( prefix="--", line="git branch --", @@ -134,7 +139,8 @@ EXPANSION_CASES = ( ), ), ( - "nice\n gb --", 11, + "nice\n gb --", + 11, dict( prefix="--", line=" git branch --", @@ -145,7 +151,8 @@ EXPANSION_CASES = ( ), ), ( - "gb -- wow", 5, + "gb -- wow", + 5, dict( prefix="--", line="git branch -- wow", @@ -156,7 +163,8 @@ EXPANSION_CASES = ( ), ), ( - "gb --wow", 5, + "gb --wow", + 5, dict( prefix="--", line="git branch --wow", @@ -168,13 +176,9 @@ EXPANSION_CASES = ( ), ) -@pytest.mark.parametrize( - "code, index, expected_args", - EXPANSION_CASES -) -def test_alias_expansion( - code, index, expected_args, monkeypatch, xonsh_builtins -): + +@pytest.mark.parametrize("code, index, expected_args", EXPANSION_CASES) +def test_alias_expansion(code, index, expected_args, monkeypatch, xession): xonsh_completer_mock = MagicMock(spec=Completer) xonsh_completer_mock.complete.return_value = set(), 0 @@ -182,11 +186,14 @@ def test_alias_expansion( ptk_completer.reserve_space = lambda: None ptk_completer.suggestion_completion = lambda _, __: None - monkeypatch.setattr("builtins.aliases", Aliases(gb=["git branch"])) + monkeypatch.setattr(xession, "aliases", Aliases(gb=["git branch"])) list(ptk_completer.get_completions(Document(code, index), MagicMock())) mock_call = xonsh_completer_mock.complete.call_args args, kwargs = mock_call expected_args["self"] = None expected_args["ctx"] = None - assert signature(Completer.complete).bind(None, *args, **kwargs).arguments == expected_args + assert ( + signature(Completer.complete).bind(None, *args, **kwargs).arguments + == expected_args + ) diff --git a/tests/test_ptk_highlight.py b/tests/test_ptk_highlight.py index 5ddff91a4..a150ade6e 100644 --- a/tests/test_ptk_highlight.py +++ b/tests/test_ptk_highlight.py @@ -2,7 +2,6 @@ """Test XonshLexer for pygments""" import gc -import builtins import pytest from pygments.token import ( @@ -19,7 +18,7 @@ from pygments.token import ( from tools import skip_if_on_windows from xonsh.platform import ON_WINDOWS -from xonsh.built_ins import load_builtins, unload_builtins +from xonsh.built_ins import XSH from xonsh.pyghooks import XonshLexer, Color, XonshStyle, on_lscolors_change from xonsh.environ import LsColors from xonsh.events import events, EventManager @@ -27,13 +26,13 @@ from tools import DummyShell @pytest.fixture(autouse=True) -def load_command_cache(xonsh_builtins): +def load_command_cache(xession): gc.collect() - unload_builtins() - load_builtins() + XSH.unload() + XSH.load() if ON_WINDOWS: for key in ("cd", "bash"): - builtins.aliases[key] = lambda *args, **kwargs: None + xession.aliases[key] = lambda *args, **kwargs: None def check_token(code, tokens): @@ -149,18 +148,16 @@ def events_fxt(): @pytest.fixture -def xonsh_builtins_ls_colors(xonsh_builtins, events_fxt): - x = xonsh_builtins.__xonsh__ - xonsh_builtins.__xonsh__.shell = DummyShell() # because load_command_cache zaps it. - xonsh_builtins.__xonsh__.shell.shell_type = "prompt_toolkit" +def xonsh_builtins_ls_colors(xession, events_fxt): + xession.shell = DummyShell() # because load_command_cache zaps it. + xession.shell.shell_type = "prompt_toolkit" lsc = LsColors(LsColors.default_settings) - xonsh_builtins.__xonsh__.env["LS_COLORS"] = lsc # establish LS_COLORS before style. - xonsh_builtins.__xonsh__.shell.shell.styler = XonshStyle() # default style + xession.env["LS_COLORS"] = lsc # establish LS_COLORS before style. + xession.shell.shell.styler = XonshStyle() # default style events.on_lscolors_change(on_lscolors_change) - yield xonsh_builtins - xonsh_builtins.__xonsh__ = x + yield xession @skip_if_on_windows @@ -176,7 +173,7 @@ def test_path(tmpdir, xonsh_builtins_ls_colors): ) check_token("cd X={}".format(test_dir), [(Color.BOLD_BLUE, test_dir)]) - with builtins.__xonsh__.env.swap(AUTO_CD=True): + with xonsh_builtins_ls_colors.env.swap(AUTO_CD=True): check_token(test_dir, [(Name.Constant, test_dir)]) @@ -184,7 +181,7 @@ def test_path(tmpdir, xonsh_builtins_ls_colors): def test_color_on_lscolors_change(tmpdir, xonsh_builtins_ls_colors): """Verify colorizer returns Token.Text if file type not defined in LS_COLORS""" - lsc = xonsh_builtins_ls_colors.__xonsh__.env["LS_COLORS"] + lsc = xonsh_builtins_ls_colors.env["LS_COLORS"] test_dir = str(tmpdir.mkdir("xonsh-test-highlight-path")) lsc["di"] = ("GREEN",) diff --git a/tests/test_ptk_multiline.py b/tests/test_ptk_multiline.py index 63091eb9e..7f25ac6d8 100644 --- a/tests/test_ptk_multiline.py +++ b/tests/test_ptk_multiline.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- """Tests sample inputs to PTK multiline and checks parser response""" -import builtins from collections import namedtuple from unittest.mock import MagicMock, patch @@ -10,19 +9,14 @@ from prompt_toolkit.document import Document from prompt_toolkit.buffer import Buffer from xonsh.tools import ON_WINDOWS -from xonsh.built_ins import XonshSession - -from tools import DummyEnv Context = namedtuple("Context", ["indent", "buffer", "accept", "cli", "cr"]) -@pytest.fixture(scope="module") -def ctx(): +@pytest.fixture +def ctx(xession): """Context in which the ptk multiline functionality will be tested.""" - builtins.__xonsh__ = XonshSession() - builtins.__xonsh__.env = DummyEnv() - builtins.__xonsh__.env["INDENT"] = " " + xession.env["INDENT"] = " " from xonsh.ptk_shell.key_bindings import carriage_return ptk_buffer = Buffer() @@ -35,8 +29,6 @@ def ctx(): cli=cli, cr=carriage_return, ) - del builtins.__xonsh__.env - del builtins.__xonsh__ def test_colon_indent(ctx): diff --git a/tests/test_pyghooks.py b/tests/test_pyghooks.py index 3a6f2dfa7..3de18d146 100644 --- a/tests/test_pyghooks.py +++ b/tests/test_pyghooks.py @@ -23,17 +23,17 @@ from xonsh.environ import LsColors @pytest.fixture -def xonsh_builtins_LS_COLORS(xonsh_builtins): +def xs_LS_COLORS(xession): """Xonsh environment including LS_COLORS""" - e = xonsh_builtins.__xonsh__.env + e = xession.env lsc = LsColors(LsColors.default_settings) - xonsh_builtins.__xonsh__.env["LS_COLORS"] = lsc - xonsh_builtins.__xonsh__.shell.shell_type = "prompt_toolkit" - xonsh_builtins.__xonsh__.shell.shell.styler = XonshStyle() # default style + xession.env["LS_COLORS"] = lsc + xession.shell.shell_type = "prompt_toolkit" + xession.shell.shell.styler = XonshStyle() # default style - yield xonsh_builtins + yield xession - xonsh_builtins.__xonsh__.env = e + xession.env = e DEFAULT_STYLES = { @@ -138,9 +138,7 @@ def test_code_by_name(name, exp): ), ], ) -def test_color_token_by_name( - in_tuple, exp_ct, exp_ansi_colors, xonsh_builtins_LS_COLORS -): +def test_color_token_by_name(in_tuple, exp_ct, exp_ansi_colors, xs_LS_COLORS): from xonsh.pyghooks import XonshStyle, color_token_by_name xs = XonshStyle() @@ -151,13 +149,11 @@ def test_color_token_by_name( assert ansi_colors == exp_ansi_colors, "color token mapped to correct color string" -def test_XonshStyle_init_file_color_tokens(xonsh_builtins_LS_COLORS): +def test_XonshStyle_init_file_color_tokens(xs_LS_COLORS): xs = XonshStyle() assert xs.styles assert type(file_color_tokens) is dict - assert set(file_color_tokens.keys()) == set( - xonsh_builtins_LS_COLORS.__xonsh__.env["LS_COLORS"].keys() - ) + assert set(file_color_tokens.keys()) == set(xs_LS_COLORS.env["LS_COLORS"].keys()) # parameterized tests for file colorization @@ -283,9 +279,10 @@ def colorizable_files(): @pytest.mark.parametrize( - "key,file_path", [(key, file_path) for key, file_path in _cf.items() if file_path], + "key,file_path", + [(key, file_path) for key, file_path in _cf.items() if file_path], ) -def test_colorize_file(key, file_path, colorizable_files, xonsh_builtins_LS_COLORS): +def test_colorize_file(key, file_path, colorizable_files, xs_LS_COLORS): """test proper file codes with symlinks colored normally""" ffp = colorizable_files + "/" + file_path stat_result = os.lstat(ffp) @@ -295,13 +292,12 @@ def test_colorize_file(key, file_path, colorizable_files, xonsh_builtins_LS_COLO @pytest.mark.parametrize( - "key,file_path", [(key, file_path) for key, file_path in _cf.items() if file_path], + "key,file_path", + [(key, file_path) for key, file_path in _cf.items() if file_path], ) -def test_colorize_file_symlink( - key, file_path, colorizable_files, xonsh_builtins_LS_COLORS -): +def test_colorize_file_symlink(key, file_path, colorizable_files, xs_LS_COLORS): """test proper file codes with symlinks colored target.""" - xonsh_builtins_LS_COLORS.__xonsh__.env["LS_COLORS"]["ln"] = "target" + xs_LS_COLORS.env["LS_COLORS"]["ln"] = "target" ffp = colorizable_files + "/" + file_path + "_symlink" stat_result = os.lstat(ffp) assert stat.S_ISLNK(stat_result.st_mode) @@ -325,7 +321,7 @@ def test_colorize_file_symlink( import xonsh.lazyimps -def test_colorize_file_ca(xonsh_builtins_LS_COLORS, monkeypatch): +def test_colorize_file_ca(xs_LS_COLORS, monkeypatch): def mock_os_listxattr(*args, **kwards): return ["security.capability"] diff --git a/tests/test_python_completers.py b/tests/test_python_completers.py index 807532f03..23fe0e4c0 100644 --- a/tests/test_python_completers.py +++ b/tests/test_python_completers.py @@ -1,13 +1,23 @@ import pytest from tests.tools import skip_if_pre_3_8 -from xonsh.completers.python import python_signature_complete, complete_import, complete_python -from xonsh.parsers.completion_context import CommandArg, CommandContext, CompletionContext, CompletionContextParser, PythonContext +from xonsh.completers.python import ( + python_signature_complete, + complete_import, + complete_python, +) +from xonsh.parsers.completion_context import ( + CommandArg, + CommandContext, + CompletionContext, + CompletionContextParser, + PythonContext, +) @pytest.fixture(autouse=True) -def xonsh_execer_autouse(xonsh_builtins, xonsh_execer, monkeypatch): - monkeypatch.setitem(xonsh_builtins.__xonsh__.env, "COMPLETIONS_BRACKETS", True) +def xonsh_execer_autouse(xession, xonsh_execer, monkeypatch): + monkeypatch.setitem(xession.env, "COMPLETIONS_BRACKETS", True) return xonsh_execer @@ -55,15 +65,20 @@ def test_complete_python_signatures(line, end, exp): assert exp == obs -@pytest.mark.parametrize("code, exp", ( - ("x = su", "sum"), - ("imp", "import"), - ("{}.g", "{}.get("), - # no signature for native builtins under 3.7: - pytest.param("''.split(ma", "maxsplit=", marks=skip_if_pre_3_8), -)) +@pytest.mark.parametrize( + "code, exp", + ( + ("x = su", "sum"), + ("imp", "import"), + ("{}.g", "{}.get("), + # no signature for native builtins under 3.7: + pytest.param("''.split(ma", "maxsplit=", marks=skip_if_pre_3_8), + ), +) def test_complete_python(code, exp): - res = complete_python(CompletionContext(python=PythonContext(code, len(code), ctx={}))) + res = complete_python( + CompletionContext(python=PythonContext(code, len(code), ctx={})) + ) assert res and len(res) == 2 comps, _ = res assert exp in comps @@ -71,31 +86,73 @@ def test_complete_python(code, exp): def test_complete_python_ctx(): class A: - def wow(): + def wow(self): pass a = A() - res = complete_python(CompletionContext(python=PythonContext("a.w", 2, ctx=locals()))) + res = complete_python( + CompletionContext(python=PythonContext("a.w", 2, ctx=locals())) + ) assert res and len(res) == 2 comps, _ = res assert "a.wow(" in comps -@pytest.mark.parametrize("command, exp", ( - (CommandContext(args=(CommandArg("import"),), arg_index=1, prefix="pathli"), {"pathlib"}), - (CommandContext(args=(CommandArg("from"),), arg_index=1, prefix="pathli"), {"pathlib "}), - (CommandContext(args=(CommandArg("import"),), arg_index=1, prefix="os.pa"), {"os.path"}), - (CommandContext(args=(CommandArg("from"), CommandArg("x"),), arg_index=2), {"import"}), - (CommandContext(args=( - CommandArg("import"), CommandArg("os,"), - ), arg_index=2, prefix="pathli"), {"pathlib"}), - (CommandContext(args=( - CommandArg("from"), CommandArg("pathlib"), CommandArg("import"), - ), arg_index=3, prefix="PurePa"), {"PurePath"}), -)) +@pytest.mark.parametrize( + "command, exp", + ( + ( + CommandContext(args=(CommandArg("import"),), arg_index=1, prefix="pathli"), + {"pathlib"}, + ), + ( + CommandContext(args=(CommandArg("from"),), arg_index=1, prefix="pathli"), + {"pathlib "}, + ), + ( + CommandContext(args=(CommandArg("import"),), arg_index=1, prefix="os.pa"), + {"os.path"}, + ), + ( + CommandContext( + args=( + CommandArg("from"), + CommandArg("x"), + ), + arg_index=2, + ), + {"import"}, + ), + ( + CommandContext( + args=( + CommandArg("import"), + CommandArg("os,"), + ), + arg_index=2, + prefix="pathli", + ), + {"pathlib"}, + ), + ( + CommandContext( + args=( + CommandArg("from"), + CommandArg("pathlib"), + CommandArg("import"), + ), + arg_index=3, + prefix="PurePa", + ), + {"PurePath"}, + ), + ), +) def test_complete_import(command, exp): - result = complete_import(CompletionContext(command, - python=PythonContext("", 0) # `complete_import` needs this - )) + result = complete_import( + CompletionContext( + command, python=PythonContext("", 0) # `complete_import` needs this + ) + ) assert result == exp diff --git a/tests/test_shell.py b/tests/test_shell.py index bffceddc1..147c5e393 100644 --- a/tests/test_shell.py +++ b/tests/test_shell.py @@ -9,61 +9,85 @@ from xonsh.history.sqlite import SqliteHistory from xonsh.history.dummy import DummyHistory -def test_shell_with_json_history(xonsh_builtins, xonsh_execer, tmpdir_factory): +def test_shell_with_json_history(xession, xonsh_execer, tmpdir_factory): """ Check that shell successfully load JSON history from file. """ tempdir = str(tmpdir_factory.mktemp("history")) - history_file = os.path.join(tempdir, 'history.json') + history_file = os.path.join(tempdir, "history.json") h = JsonHistory(filename=history_file) - h.append({"inp": "echo Hello world 1\n", "rtn": 0, "ts": [1615887820.7329783, 1615887820.7513437]}) - h.append({"inp": "echo Hello world 2\n", "rtn": 0, "ts": [1615887820.7329783, 1615887820.7513437]}) + h.append( + { + "inp": "echo Hello world 1\n", + "rtn": 0, + "ts": [1615887820.7329783, 1615887820.7513437], + } + ) + h.append( + { + "inp": "echo Hello world 2\n", + "rtn": 0, + "ts": [1615887820.7329783, 1615887820.7513437], + } + ) h.flush() - xonsh_builtins.__xonsh__.env = Env( + xession.env = Env( XONSH_DATA_DIR=tempdir, XONSH_INTERACTIVE=True, - XONSH_HISTORY_BACKEND='json', + XONSH_HISTORY_BACKEND="json", XONSH_HISTORY_FILE=history_file, # XONSH_DEBUG=1 # to show errors ) - Shell(xonsh_execer, shell_type='none') + Shell(xonsh_execer, shell_type="none") - assert len([i for i in xonsh_builtins.__xonsh__.history.all_items()]) == 2 + assert len([i for i in xession.history.all_items()]) == 2 -def test_shell_with_sqlite_history(xonsh_builtins, xonsh_execer, tmpdir_factory): +def test_shell_with_sqlite_history(xession, xonsh_execer, tmpdir_factory): """ Check that shell successfully load SQLite history from file. """ tempdir = str(tmpdir_factory.mktemp("history")) - history_file = os.path.join(tempdir, 'history.db') + history_file = os.path.join(tempdir, "history.db") h = SqliteHistory(filename=history_file) - h.append({"inp": "echo Hello world 1\n", "rtn": 0, "ts": [1615887820.7329783, 1615887820.7513437]}) - h.append({"inp": "echo Hello world 2\n", "rtn": 0, "ts": [1615887820.7329783, 1615887820.7513437]}) + h.append( + { + "inp": "echo Hello world 1\n", + "rtn": 0, + "ts": [1615887820.7329783, 1615887820.7513437], + } + ) + h.append( + { + "inp": "echo Hello world 2\n", + "rtn": 0, + "ts": [1615887820.7329783, 1615887820.7513437], + } + ) h.flush() - xonsh_builtins.__xonsh__.env = Env( + xession.env = Env( XONSH_DATA_DIR=tempdir, XONSH_INTERACTIVE=True, - XONSH_HISTORY_BACKEND='sqlite', + XONSH_HISTORY_BACKEND="sqlite", XONSH_HISTORY_FILE=history_file, # XONSH_DEBUG=1 # to show errors ) - Shell(xonsh_execer, shell_type='none') + Shell(xonsh_execer, shell_type="none") - assert len([i for i in xonsh_builtins.__xonsh__.history.all_items()]) == 2 + assert len([i for i in xession.history.all_items()]) == 2 -def test_shell_with_dummy_history_in_not_interactive(xonsh_builtins, xonsh_execer): +def test_shell_with_dummy_history_in_not_interactive(xession, xonsh_execer): """ Check that shell use Dummy history in not interactive mode. """ - xonsh_builtins.__xonsh__.env = Env(XONSH_INTERACTIVE=False) - xonsh_builtins.__xonsh__.history = None - Shell(xonsh_execer, shell_type='none') - assert isinstance(xonsh_builtins.__xonsh__.history, DummyHistory) + xession.env = Env(XONSH_INTERACTIVE=False) + xession.history = None + Shell(xonsh_execer, shell_type="none") + assert isinstance(xession.history, DummyHistory) diff --git a/tests/test_tools.py b/tests/test_tools.py index 08540b12a..f2c6e801e 100644 --- a/tests/test_tools.py +++ b/tests/test_tools.py @@ -32,7 +32,6 @@ from xonsh.tools import ( env_path_to_str, escape_windows_cmd_string, executables_in, - expand_case_matching, expand_path, find_next_break, is_bool, @@ -66,7 +65,6 @@ from xonsh.tools import ( is_nonstring_seq_of_strings, pathsep_to_upper_seq, seq_to_upper_pathsep, - expandvars, is_int_as_str, is_slice_as_str, ensure_timestamp, @@ -89,6 +87,8 @@ from xonsh.tools import ( to_completion_mode, is_completions_display_value, to_completions_display_value, + expand_case_matching, + expandvars, ) from xonsh.environ import Env @@ -934,8 +934,8 @@ def expand(path): (b"~/../", "~/../"), ], ) -def test_env_path_getitem(inp, exp, xonsh_builtins, env): - xonsh_builtins.__xonsh__.env = env +def test_env_path_getitem(inp, exp, xession, env): + xession.env = env obs = EnvPath(inp)[0] # call to __getitem__ if env.get("EXPAND_ENV_VARS"): assert expand(exp) == obs @@ -957,9 +957,9 @@ def test_env_path_getitem(inp, exp, xonsh_builtins, env): ), ], ) -def test_env_path_multipath(inp, exp, xonsh_builtins, env): +def test_env_path_multipath(inp, exp, xession, env): # cases that involve path-separated strings - xonsh_builtins.__xonsh__.env = env + xession.env = env if env == TOOLS_ENV: obs = [i for i in EnvPath(inp)] assert [expand(i) for i in exp] == obs @@ -982,8 +982,8 @@ def test_env_path_multipath(inp, exp, xonsh_builtins, env): (["/home/wakka", pathlib.Path("~/"), "~/"], ["/home/wakka", "~", "~/"]), ], ) -def test_env_path_with_pathlib_path_objects(inp, exp, xonsh_builtins): - xonsh_builtins.__xonsh__.env = TOOLS_ENV +def test_env_path_with_pathlib_path_objects(inp, exp, xession): + xession.env = TOOLS_ENV # iterate over EnvPath to acquire all expanded paths obs = [i for i in EnvPath(inp)] assert [expand(i) for i in exp] == obs @@ -1474,7 +1474,7 @@ def test_partial_string(leaders, prefix, quote): assert obs == exp -def test_executables_in(xonsh_builtins): +def test_executables_in(xession): expected = set() types = ("file", "directory", "brokensymlink") if ON_WINDOWS: @@ -1507,7 +1507,7 @@ def test_executables_in(xonsh_builtins): if executable and not _type == "brokensymlink": os.chmod(path, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) if ON_WINDOWS: - xonsh_builtins.__xonsh__.env = PATHEXT_ENV + xession.env = PATHEXT_ENV result = set(executables_in(test_path)) else: result = set(executables_in(test_path)) @@ -1562,12 +1562,12 @@ def test_expand_case_matching(inp, exp): (b"${'unk'}${'foo'}bar", "${'unk'}barbar"), ], ) -def test_expandvars(inp, exp, xonsh_builtins): +def test_expandvars(inp, exp, xession): """Tweaked for xonsh cases from CPython `test_genericpath.py`""" env = Env( {"foo": "bar", "spam": "eggs", "a_bool": True, "an_int": 42, "none": None} ) - xonsh_builtins.__xonsh__.env = env + xession.env = env assert expandvars(inp) == exp @@ -1589,8 +1589,8 @@ def test_expandvars(inp, exp, xonsh_builtins): ), ], ) -def test_ensure_timestamp(inp, fmt, exp, xonsh_builtins): - xonsh_builtins.__xonsh__.env["XONSH_DATETIME_FORMAT"] = "%Y-%m-%d %H:%M" +def test_ensure_timestamp(inp, fmt, exp, xession): + xession.env["XONSH_DATETIME_FORMAT"] = "%Y-%m-%d %H:%M" obs = ensure_timestamp(inp, fmt) assert exp == obs @@ -1607,14 +1607,14 @@ def test_ensure_timestamp(inp, fmt, exp, xonsh_builtins): ("~/$foo", False, "/$foo"), ], ) -def test_expand_path(expand_user, inp, expand_env_vars, exp_end, xonsh_builtins): +def test_expand_path(expand_user, inp, expand_env_vars, exp_end, xession): if os.sep != "/": inp = inp.replace("/", os.sep) exp_end = exp_end.replace("/", os.sep) env = Env({"foo": "bar", "a_bool": True, "an_int": 42, "none": None}) env["EXPAND_ENV_VARS"] = expand_env_vars - xonsh_builtins.__xonsh__.env = env + xession.env = env path = expand_path(inp, expand_user=expand_user) @@ -1728,7 +1728,7 @@ def test_deprecated_past_expiry_raises_assertion_error(expired_version): @skip_if_on_windows -def test_iglobpath_no_dotfiles(xonsh_builtins): +def test_iglobpath_no_dotfiles(xession): d = os.path.dirname(__file__) g = d + "/*" files = list(iglobpath(g, include_dotfiles=False)) @@ -1736,7 +1736,7 @@ def test_iglobpath_no_dotfiles(xonsh_builtins): @skip_if_on_windows -def test_iglobpath_dotfiles(xonsh_builtins): +def test_iglobpath_dotfiles(xession): d = os.path.dirname(__file__) g = d + "/*" files = list(iglobpath(g, include_dotfiles=True)) @@ -1744,7 +1744,7 @@ def test_iglobpath_dotfiles(xonsh_builtins): @skip_if_on_windows -def test_iglobpath_no_dotfiles_recursive(xonsh_builtins): +def test_iglobpath_no_dotfiles_recursive(xession): d = os.path.dirname(__file__) g = d + "/**" files = list(iglobpath(g, include_dotfiles=False)) @@ -1752,14 +1752,14 @@ def test_iglobpath_no_dotfiles_recursive(xonsh_builtins): @skip_if_on_windows -def test_iglobpath_dotfiles_recursive(xonsh_builtins): +def test_iglobpath_dotfiles_recursive(xession): d = os.path.dirname(__file__) g = d + "/**" files = list(iglobpath(g, include_dotfiles=True)) assert d + "/bin/.someotherdotfile" in files -def test_iglobpath_empty_str(monkeypatch, xonsh_builtins): +def test_iglobpath_empty_str(monkeypatch, xession): # makes sure that iglobpath works, even when os.scandir() and os.listdir() # fail to return valid results, like an empty filename def mockscandir(path): @@ -1812,7 +1812,11 @@ def test_all_permutations(): {"Literal.String.Single": "#ff0000"}, {"Token.Literal.String.Single": "#ff0000"}, ), # short str key - ("test4", {"RED": "#ff0000"}, {"Token.Color.RED": "#ff0000"},), # color + ( + "test4", + {"RED": "#ff0000"}, + {"Token.Color.RED": "#ff0000"}, + ), # color ], ) def test_register_custom_style(name, styles, refrules): @@ -1855,7 +1859,15 @@ def test_to_completion_mode(val, exp): assert to_completion_mode(val) == exp -@pytest.mark.parametrize("val", ["de", "defa_ult", "men_", "menu_",]) +@pytest.mark.parametrize( + "val", + [ + "de", + "defa_ult", + "men_", + "menu_", + ], +) def test_to_completion_mode_fail(val): with pytest.warns(RuntimeWarning): obs = to_completion_mode(val) @@ -1884,14 +1896,14 @@ def test_is_completions_display_value(val, exp): (False, "none"), ("false", "none"), ("single", "single"), - ("readline", "single"), + ("readline", "readline"), # todo: check this ("multi", "multi"), (True, "multi"), ("TRUE", "multi"), ], ) def test_to_completions_display_value(val, exp): - to_completions_display_value(val) == exp + assert to_completions_display_value(val) == exp @pytest.mark.parametrize("val", [1, "", "argle"]) diff --git a/tests/test_vox.py b/tests/test_vox.py index ae326d7d7..923e291b9 100644 --- a/tests/test_vox.py +++ b/tests/test_vox.py @@ -13,20 +13,20 @@ from xonsh.platform import ON_WINDOWS @skip_if_on_msys @skip_if_on_conda -def test_crud(xonsh_builtins, tmpdir): +def test_crud(xession, tmpdir): """ Creates a virtual environment, gets it, enumerates it, and then deletes it. """ - xonsh_builtins.__xonsh__.env["VIRTUALENV_HOME"] = str(tmpdir) + xession.env["VIRTUALENV_HOME"] = str(tmpdir) last_event = None - @xonsh_builtins.events.vox_on_create + @xession.builtins.events.vox_on_create def create(name, **_): nonlocal last_event last_event = "create", name - @xonsh_builtins.events.vox_on_delete + @xession.builtins.events.vox_on_delete def delete(name, **_): nonlocal last_event last_event = "delete", name @@ -51,22 +51,22 @@ def test_crud(xonsh_builtins, tmpdir): @skip_if_on_msys @skip_if_on_conda -def test_activate(xonsh_builtins, tmpdir): +def test_activate(xession, tmpdir): """ Creates a virtual environment, gets it, enumerates it, and then deletes it. """ - xonsh_builtins.__xonsh__.env["VIRTUALENV_HOME"] = str(tmpdir) + xession.env["VIRTUALENV_HOME"] = str(tmpdir) # I consider the case that the user doesn't have a PATH set to be unreasonable - xonsh_builtins.__xonsh__.env.setdefault("PATH", []) + xession.env.setdefault("PATH", []) last_event = None - @xonsh_builtins.events.vox_on_activate + @xession.builtins.events.vox_on_activate def activate(name, **_): nonlocal last_event last_event = "activate", name - @xonsh_builtins.events.vox_on_deactivate + @xession.builtins.events.vox_on_deactivate def deactivate(name, **_): nonlocal last_event last_event = "deactivate", name @@ -74,30 +74,30 @@ def test_activate(xonsh_builtins, tmpdir): vox = Vox() vox.create("spam") vox.activate("spam") - assert xonsh_builtins.__xonsh__.env["VIRTUAL_ENV"] == vox["spam"].env + assert xession.env["VIRTUAL_ENV"] == vox["spam"].env assert last_event == ("activate", "spam") vox.deactivate() - assert "VIRTUAL_ENV" not in xonsh_builtins.__xonsh__.env + assert "VIRTUAL_ENV" not in xession.env assert last_event == ("deactivate", "spam") @skip_if_on_msys @skip_if_on_conda -def test_activate_non_vox_venv(xonsh_builtins, tmpdir): +def test_activate_non_vox_venv(xession, tmpdir): """ Create a virtual environment using Python's built-in venv module (not in VIRTUALENV_HOME) and verify that vox can activate it correctly. """ - xonsh_builtins.__xonsh__.env.setdefault("PATH", []) + xession.env.setdefault("PATH", []) last_event = None - @xonsh_builtins.events.vox_on_activate + @xession.builtins.events.vox_on_activate def activate(name, path, **_): nonlocal last_event last_event = "activate", name, path - @xonsh_builtins.events.vox_on_deactivate + @xession.builtins.events.vox_on_deactivate def deactivate(name, path, **_): nonlocal last_event last_event = "deactivate", name, path @@ -109,7 +109,7 @@ def test_activate_non_vox_venv(xonsh_builtins, tmpdir): vox.activate(venv_dirname) vxv = vox[venv_dirname] - env = xonsh_builtins.__xonsh__.env + env = xession.env assert os.path.isabs(vxv.bin) assert env["PATH"][0] == vxv.bin assert os.path.isabs(vxv.env) @@ -132,34 +132,34 @@ def test_activate_non_vox_venv(xonsh_builtins, tmpdir): @skip_if_on_msys @skip_if_on_conda -def test_path(xonsh_builtins, tmpdir): +def test_path(xession, tmpdir): """ Test to make sure Vox properly activates and deactivates by examining $PATH """ - xonsh_builtins.__xonsh__.env["VIRTUALENV_HOME"] = str(tmpdir) + xession.env["VIRTUALENV_HOME"] = str(tmpdir) # I consider the case that the user doesn't have a PATH set to be unreasonable - xonsh_builtins.__xonsh__.env.setdefault("PATH", []) + xession.env.setdefault("PATH", []) - oldpath = list(xonsh_builtins.__xonsh__.env["PATH"]) + oldpath = list(xession.env["PATH"]) vox = Vox() vox.create("eggs") vox.activate("eggs") - assert oldpath != xonsh_builtins.__xonsh__.env["PATH"] + assert oldpath != xession.env["PATH"] vox.deactivate() - assert oldpath == xonsh_builtins.__xonsh__.env["PATH"] + assert oldpath == xession.env["PATH"] @skip_if_on_msys @skip_if_on_conda -def test_crud_subdir(xonsh_builtins, tmpdir): +def test_crud_subdir(xession, tmpdir): """ Creates a virtual environment, gets it, enumerates it, and then deletes it. """ - xonsh_builtins.__xonsh__.env["VIRTUALENV_HOME"] = str(tmpdir) + xession.env["VIRTUALENV_HOME"] = str(tmpdir) vox = Vox() vox.create("spam/eggs") @@ -188,7 +188,7 @@ else: @skip_if_on_msys @skip_if_on_conda - def test_crud_path(xonsh_builtins, tmpdir): + def test_crud_path(xession, tmpdir): """ Creates a virtual environment, gets it, enumerates it, and then deletes it. """ @@ -209,11 +209,11 @@ else: @skip_if_on_msys @skip_if_on_conda -def test_reserved_names(xonsh_builtins, tmpdir): +def test_reserved_names(xession, tmpdir): """ Tests that reserved words are disallowed. """ - xonsh_builtins.__xonsh__.env["VIRTUALENV_HOME"] = str(tmpdir) + xession.env["VIRTUALENV_HOME"] = str(tmpdir) vox = Vox() with pytest.raises(ValueError): @@ -231,7 +231,7 @@ def test_reserved_names(xonsh_builtins, tmpdir): @skip_if_on_msys @skip_if_on_conda -def test_autovox(xonsh_builtins, tmpdir): +def test_autovox(xession, tmpdir): """ Tests that autovox works """ @@ -239,7 +239,7 @@ def test_autovox(xonsh_builtins, tmpdir): import xonsh.dirstack # Set up an isolated venv home - xonsh_builtins.__xonsh__.env["VIRTUALENV_HOME"] = str(tmpdir) + xession.env["VIRTUALENV_HOME"] = str(tmpdir) # Makes sure that event handlers are registered import xontrib.autovox @@ -247,13 +247,13 @@ def test_autovox(xonsh_builtins, tmpdir): importlib.reload(xontrib.autovox) # Set up enough environment for xonsh to function - xonsh_builtins.__xonsh__.env["PWD"] = os.getcwd() - xonsh_builtins.__xonsh__.env["DIRSTACK_SIZE"] = 10 - xonsh_builtins.__xonsh__.env["PATH"] = [] + xession.env["PWD"] = os.getcwd() + xession.env["DIRSTACK_SIZE"] = 10 + xession.env["PATH"] = [] - xonsh_builtins.__xonsh__.env["XONSH_SHOW_TRACEBACK"] = True + xession.env["XONSH_SHOW_TRACEBACK"] = True - @xonsh_builtins.events.autovox_policy + @xession.builtins.events.autovox_policy def policy(path, **_): print("Checking", repr(path), vox.active()) if str(path) == str(tmpdir): @@ -261,16 +261,16 @@ def test_autovox(xonsh_builtins, tmpdir): vox = Vox() - print(xonsh_builtins.__xonsh__.env["PWD"]) + print(xession.env["PWD"]) xonsh.dirstack.pushd([str(tmpdir)]) - print(xonsh_builtins.__xonsh__.env["PWD"]) + print(xession.env["PWD"]) assert vox.active() is None xonsh.dirstack.popd([]) - print(xonsh_builtins.__xonsh__.env["PWD"]) + print(xession.env["PWD"]) vox.create("myenv") xonsh.dirstack.pushd([str(tmpdir)]) - print(xonsh_builtins.__xonsh__.env["PWD"]) + print(xession.env["PWD"]) assert vox.active() == "myenv" xonsh.dirstack.popd([]) - print(xonsh_builtins.__xonsh__.env["PWD"]) + print(xession.env["PWD"]) diff --git a/tests/test_xonfig.py b/tests/test_xonfig.py index cdcbfc062..8110c2343 100644 --- a/tests/test_xonfig.py +++ b/tests/test_xonfig.py @@ -30,7 +30,15 @@ def test_xonfg_help(capsys, xonsh_builtins): @pytest.mark.parametrize( - "args", [([]), (["info",]),], # NOQA E231 + "args", + [ + ([]), + ( + [ + "info", + ] + ), + ], # NOQA E231 ) def test_xonfig_info(args, xonsh_builtins): """info works, and reports no jupyter if none in environment""" @@ -53,8 +61,8 @@ def strip_sep(path: str) -> str: @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. + 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. diff --git a/tests/test_xonsh.xsh b/tests/test_xonsh.xsh index 850c349b0..a22807f10 100644 --- a/tests/test_xonsh.xsh +++ b/tests/test_xonsh.xsh @@ -1,6 +1,3 @@ -import builtins - - def test_simple(): assert 1 + 1 == 2 @@ -13,12 +10,13 @@ def test_envionment(): def test_xonsh_party(): - orig = builtins.__xonsh__.env.get('XONSH_INTERACTIVE') - builtins.__xonsh__.env['XONSH_INTERACTIVE'] = False + from xonsh.built_ins import XSH + orig = XSH.env.get('XONSH_INTERACTIVE') + XSH.env['XONSH_INTERACTIVE'] = False try: x = 'xonsh' y = 'party' out = $(echo @(x + '-' + y)).strip() assert out == 'xonsh-party', 'Out really was <' + out + '>, sorry.' finally: - builtins.__xonsh__.env['XONSH_INTERACTIVE'] = orig + XSH.env['XONSH_INTERACTIVE'] = orig diff --git a/tests/test_xoreutils.py b/tests/test_xoreutils.py index 8ca5cdd4d..65ecde442 100644 --- a/tests/test_xoreutils.py +++ b/tests/test_xoreutils.py @@ -107,11 +107,11 @@ def test_boottime(): @pytest.fixture -def cat_env_fixture(xonsh_builtins): - with xonsh_builtins.__xonsh__.env.swap( +def cat_env_fixture(xession): + with xession.env.swap( XONSH_ENCODING=DEFAULT_ENCODING, XONSH_ENCODING_ERRORS="surrogateescape" ): - yield xonsh_builtins + yield xession class CatLimitedBuffer(io.BytesIO): diff --git a/tests/tools.py b/tests/tools.py index 06c61683c..58d45967d 100644 --- a/tests/tools.py +++ b/tests/tools.py @@ -4,7 +4,6 @@ from __future__ import unicode_literals, print_function import os import sys import ast -import builtins import platform import subprocess import contextlib @@ -13,6 +12,7 @@ from collections.abc import MutableMapping import pytest +from xonsh.built_ins import XSH from xonsh.environ import Env from xonsh.base_shell import BaseShell @@ -84,14 +84,6 @@ class DummyShell: return self._shell -class DummyCommandsCache: - def locate_binary(self, name): - return os.path.join(os.path.dirname(__file__), "bin", name) - - def predict_threadable(self, cmd): - return True - - class DummyHistory: last_cmd_rtn = 0 @@ -168,12 +160,12 @@ class DummyEnv(MutableMapping): def check_exec(input, **kwargs): - builtins.__xonsh__.execer.exec(input, **kwargs) + XSH.execer.exec(input, **kwargs) return True def check_eval(input): - builtins.__xonsh__.env = Env( + XSH.env = Env( { "AUTO_CD": False, "XONSH_ENCODING": "utf-8", @@ -182,13 +174,13 @@ def check_eval(input): } ) if ON_WINDOWS: - builtins.__xonsh__.env["PATHEXT"] = [".COM", ".EXE", ".BAT", ".CMD"] - builtins.__xonsh__.execer.eval(input) + XSH.env["PATHEXT"] = [".COM", ".EXE", ".BAT", ".CMD"] + XSH.execer.eval(input) return True def check_parse(input): - tree = builtins.__xonsh__.execer.parse(input, ctx=None) + tree = XSH.execer.parse(input, ctx=None) return tree @@ -204,22 +196,34 @@ def nodes_equal(x, y): type(y), ) if isinstance(x, (ast.Expr, ast.FunctionDef, ast.ClassDef)): - assert x.lineno == y.lineno, ( - "Ast nodes do not have the same line number : %s != %s" - % (x.lineno, y.lineno,) + assert ( + x.lineno == y.lineno + ), "Ast nodes do not have the same line number : %s != %s" % ( + x.lineno, + y.lineno, ) - assert x.col_offset == y.col_offset, ( - "Ast nodes do not have the same column offset number : %s != %s" - % (x.col_offset, y.col_offset) + assert ( + x.col_offset == y.col_offset + ), "Ast nodes do not have the same column offset number : %s != %s" % ( + x.col_offset, + y.col_offset, ) for (xname, xval), (yname, yval) in zip(ast.iter_fields(x), ast.iter_fields(y)): - assert xname == yname, ( - "Ast nodes fields differ : %s (of type %s) != %s (of type %s)" - % (xname, type(xval), yname, type(yval)) + assert ( + xname == yname + ), "Ast nodes fields differ : %s (of type %s) != %s (of type %s)" % ( + xname, + type(xval), + yname, + type(yval), ) - assert type(xval) == type(yval), ( - "Ast nodes fields differ : %s (of type %s) != %s (of type %s)" - % (xname, type(xval), yname, type(yval)) + assert type(xval) == type( + yval + ), "Ast nodes fields differ : %s (of type %s) != %s (of type %s)" % ( + xname, + type(xval), + yname, + type(yval), ) for xchild, ychild in zip(ast.iter_child_nodes(x), ast.iter_child_nodes(y)): assert nodes_equal(xchild, ychild), "Ast node children differs" diff --git a/tests/xontribs/test_abbrevs.py b/tests/xontribs/test_abbrevs.py index e56c4663a..e9e585890 100644 --- a/tests/xontribs/test_abbrevs.py +++ b/tests/xontribs/test_abbrevs.py @@ -6,7 +6,6 @@ import sys from prompt_toolkit.buffer import Buffer from pytest import fixture, mark from xonsh.xontribs import find_xontrib -import builtins @fixture @@ -43,11 +42,13 @@ ps_special_expand = ( ], ) def test_gets_expanded(abbr, val, expanded, cur, abbrevs_xontrib, _buffer): - builtins.abbrevs[abbr] = val - from xontrib.abbrevs import expand_abbrev + from xontrib import abbrevs + abbrevs.abbrevs[abbr] = val + + abbrev = abbrevs.Abbreviation() buf = _buffer(abbr) - expand_abbrev(buf) + abbrev.expand(buf) assert buf.text == expanded if cur is not None: assert buf.cursor_position == cur diff --git a/tests/xontribs/test_jedi.py b/tests/xontribs/test_jedi.py index 66788be3f..0681e7fb8 100644 --- a/tests/xontribs/test_jedi.py +++ b/tests/xontribs/test_jedi.py @@ -1,7 +1,6 @@ """Tests for the Jedi completer xontrib""" import sys import pytest -import builtins import importlib from unittest.mock import MagicMock, call @@ -23,14 +22,14 @@ def jedi_mock(monkeypatch): @pytest.fixture -def completer_mock(monkeypatch): +def completer_mock(monkeypatch, xession): completer_mock = MagicMock() # so that args will be passed def comp(args): completer_mock(args) - monkeypatch.setitem(builtins.aliases, "completer", comp) + monkeypatch.setitem(xession.aliases, "completer", comp) yield completer_mock @@ -42,11 +41,11 @@ def jedi_xontrib(monkeypatch, source_path, jedi_mock, completer_mock): del sys.modules[spec.name] -def test_completer_added(jedi_xontrib): +def test_completer_added(jedi_xontrib, xession): 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 + assert "python" not in xession.completers + assert "python_mode" not in xession.completers + assert "jedi_python" in xession.completers @pytest.mark.parametrize( @@ -56,7 +55,7 @@ def test_completer_added(jedi_xontrib): ], ) @pytest.mark.parametrize("version", ["new", "old"]) -def test_jedi_api(jedi_xontrib, jedi_mock, version, context): +def test_jedi_api(jedi_xontrib, jedi_mock, version, context, xession): if version == "old": jedi_mock.__version__ = "0.15.0" jedi_mock.Interpreter().completions.return_value = [] @@ -64,7 +63,7 @@ def test_jedi_api(jedi_xontrib, jedi_mock, version, context): jedi_xontrib.complete_jedi(context) - extra_namespace = {"__xonsh__": builtins.__xonsh__} + extra_namespace = {"__xonsh__": xession} try: extra_namespace["_"] = _ except NameError: @@ -109,12 +108,16 @@ def test_multiline(jedi_xontrib, jedi_mock, monkeypatch): "int(x=None, /) -> int", ("instance", "instance int"), ), - RichCompletion("xx", display="xx", description="instance int", prefix_len=1), + RichCompletion( + "xx", display="xx", description="instance int", prefix_len=1 + ), ), ( # from jedi when code is 'xx=3\nx' ("statement", "xx", "x", None, ("instance", "instance int")), - RichCompletion("xx", display="xx", description="instance int", prefix_len=1), + RichCompletion( + "xx", display="xx", description="instance int", prefix_len=1 + ), ), ( # from jedi when code is 'x.' and x=3 @@ -139,18 +142,28 @@ def test_multiline(jedi_xontrib, jedi_mock, monkeypatch): ( # from '(3).from_bytes(byt' ("param", "bytes=", "es=", None, ("instance", "instance Sequence")), - RichCompletion("bytes=", display="bytes=", description="instance Sequence", prefix_len=3), + RichCompletion( + "bytes=", + display="bytes=", + description="instance Sequence", + prefix_len=3, + ), ), ( # from 'x.from_bytes(byt' when x=3 ("param", "bytes=", "es=", None, None), - RichCompletion("bytes=", display="bytes=", description="param", prefix_len=3), + RichCompletion( + "bytes=", display="bytes=", description="param", prefix_len=3 + ), ), ( # from 'import colle' ("module", "collections", "ctions", None, ("module", "module collections")), RichCompletion( - "collections", display="collections", description="module collections", prefix_len=5 + "collections", + display="collections", + description="module collections", + prefix_len=5, ), ), ( @@ -163,7 +176,10 @@ def test_multiline(jedi_xontrib, jedi_mock, monkeypatch): ("class", "class NameError"), ), RichCompletion( - "NameError", display="NameError", description="NameError(*args: object)", prefix_len=7 + "NameError", + display="NameError", + description="NameError(*args: object)", + prefix_len=7, ), ), ( @@ -174,12 +190,16 @@ def test_multiline(jedi_xontrib, jedi_mock, monkeypatch): ( # from 'open("/etc/pass' ("path", 'passwd"', 'wd"', None, None), - RichCompletion('passwd"', display='passwd"', description="path", prefix_len=4), + RichCompletion( + 'passwd"', display='passwd"', description="path", prefix_len=4 + ), ), ( # from 'cla' ("keyword", "class", "ss", None, None), - RichCompletion("class", display="class", description="keyword", prefix_len=3), + RichCompletion( + "class", display="class", description="keyword", prefix_len=3 + ), ), ], ) @@ -218,10 +238,15 @@ def test_rich_completions(jedi_xontrib, jedi_mock, completion, rich_completion): def test_special_tokens(jedi_xontrib): - assert jedi_xontrib.complete_jedi(CompletionContext(python=PythonContext("", 0))) \ - .issuperset(jedi_xontrib.XONSH_SPECIAL_TOKENS) - assert jedi_xontrib.complete_jedi(CompletionContext(python=PythonContext( "@", 1))) == {"@", "@(", "@$("} - assert jedi_xontrib.complete_jedi(CompletionContext(python=PythonContext("$", 1))) == {"$[", "${", "$("} + assert jedi_xontrib.complete_jedi( + CompletionContext(python=PythonContext("", 0)) + ).issuperset(jedi_xontrib.XONSH_SPECIAL_TOKENS) + assert jedi_xontrib.complete_jedi( + CompletionContext(python=PythonContext("@", 1)) + ) == {"@", "@(", "@$("} + assert jedi_xontrib.complete_jedi( + CompletionContext(python=PythonContext("$", 1)) + ) == {"$[", "${", "$("} @skip_if_on_darwin @@ -230,4 +255,6 @@ def test_no_command_path_completion(jedi_xontrib, completion_context_parse): assert jedi_xontrib.complete_jedi(completion_context_parse("./", 2)) is None assert jedi_xontrib.complete_jedi(completion_context_parse("./e", 3)) is None assert jedi_xontrib.complete_jedi(completion_context_parse("/usr/bin/", 9)) is None - assert jedi_xontrib.complete_jedi(completion_context_parse("/usr/bin/e", 10)) is None + assert ( + jedi_xontrib.complete_jedi(completion_context_parse("/usr/bin/e", 10)) is None + ) diff --git a/xonsh/aliases.py b/xonsh/aliases.py index 29e6d22fc..a8d8a593d 100644 --- a/xonsh/aliases.py +++ b/xonsh/aliases.py @@ -5,9 +5,9 @@ import re import sys import inspect import argparse -import builtins import collections.abc as cabc +from xonsh.built_ins import XSH from xonsh.lazyasd import lazyobject from xonsh.dirstack import cd, pushd, popd, dirs, _get_cwd from xonsh.environ import locate_binary, make_args_env @@ -94,7 +94,7 @@ class Aliases(cabc.MutableMapping): if callable(value): return partial_eval_alias(value, acc_args=acc_args) else: - expand_path = builtins.__xonsh__.expand_path + expand_path = XSH.expand_path token, *rest = map(expand_path, value) if token in seen_tokens or token not in self._raw: # ^ Making sure things like `egrep=egrep --color=auto` works, @@ -115,7 +115,7 @@ class Aliases(cabc.MutableMapping): The command won't be expanded if the cursor's inside/behind it. """ word = (line.split(maxsplit=1) or [""])[0] - if word in builtins.aliases and isinstance(self.get(word), cabc.Sequence): # type: ignore + if word in XSH.aliases and isinstance(self.get(word), cabc.Sequence): # type: ignore word_idx = line.find(word) word_edge = word_idx + len(word) if cursor_index > word_edge: @@ -139,7 +139,7 @@ class Aliases(cabc.MutableMapping): self._raw[key] = ExecAlias(val, filename=f) elif isexpression(val): # expansion substitution - lexer = builtins.__xonsh__.execer.parser.lexer + lexer = XSH.execer.parser.lexer self._raw[key] = list(map(strip_simple_quotes, lexer.split(val))) else: # need to exec alias @@ -204,14 +204,14 @@ class ExecAlias: def __call__( self, args, stdin=None, stdout=None, stderr=None, spec=None, stack=None ): - execer = builtins.__xonsh__.execer + execer = XSH.execer frame = stack[0][0] # execute as though we are at the call site alias_args = {"args": args} for i, a in enumerate(args): alias_args[f"arg{i}"] = a - with builtins.__xonsh__.env.swap(alias_args): + with XSH.env.swap(alias_args): execer.exec( self.src, glbs=frame.f_globals, @@ -357,14 +357,14 @@ def xonsh_exit(args, stdin=None): if not clean_jobs(): # Do not exit if jobs not cleaned up return None, None - builtins.__xonsh__.exit = True + XSH.exit = True print() # gimme a newline return None, None def xonsh_reset(args, stdin=None): """Clears __xonsh__.ctx""" - builtins.__xonsh__.ctx.clear() + XSH.ctx.clear() @lazyobject @@ -496,7 +496,7 @@ def _SOURCE_FOREIGN_PARSER(): def source_foreign(args, stdin=None, stdout=None, stderr=None): """Sources a file written in a foreign shell language.""" - env = builtins.__xonsh__.env + env = XSH.env ns = _SOURCE_FOREIGN_PARSER.parse_args(args) ns.suppress_skip_message = ( env.get("FOREIGN_ALIASES_SUPPRESS_SKIP_MESSAGE") @@ -547,7 +547,7 @@ def source_foreign(args, stdin=None, stdout=None, stderr=None): if k not in fsenv: env.pop(k, None) # Update aliases - baliases = builtins.aliases + baliases = XSH.aliases for k, v in fsaliases.items(): if k in baliases and v == baliases[k]: continue # no change from original @@ -572,7 +572,7 @@ def source_alias(args, stdin=None): If sourced file isn't found in cwd, search for file along $PATH to source instead. """ - env = builtins.__xonsh__.env + env = XSH.env encoding = env.get("XONSH_ENCODING") errors = env.get("XONSH_ENCODING_ERRORS") for i, fname in enumerate(args): @@ -599,11 +599,11 @@ def source_alias(args, stdin=None): src = fp.read() if not src.endswith("\n"): src += "\n" - ctx = builtins.__xonsh__.ctx + ctx = XSH.ctx updates = {"__file__": fpath, "__name__": os.path.abspath(fpath)} with env.swap(**make_args_env(args[i + 1 :])), swap_values(ctx, updates): try: - builtins.execx(src, "exec", ctx, filename=fpath) + XSH.builtins.execx(src, "exec", ctx, filename=fpath) except Exception: print_color( "{RED}You may be attempting to source non-xonsh file! " @@ -633,7 +633,7 @@ def source_cmd(args, stdin=None): args.append("--envcmd=set") args.append("--seterrpostcmd=if errorlevel 1 exit 1") args.append("--use-tmpfile=1") - with builtins.__xonsh__.env.swap(PROMPT="$P$G"): + with XSH.env.swap(PROMPT="$P$G"): return source_foreign(args, stdin=stdin) @@ -690,7 +690,7 @@ def xexec(args, stdin=None): denv = {} if not args.clean: - denv = builtins.__xonsh__.env.detype() + denv = XSH.env.detype() try: os.execvpe(command, args.command, denv) diff --git a/xonsh/ansi_colors.py b/xonsh/ansi_colors.py index 7ee7b61dd..1139d4df1 100644 --- a/xonsh/ansi_colors.py +++ b/xonsh/ansi_colors.py @@ -2,9 +2,9 @@ import re import sys import warnings -import builtins import typing as tp +from xonsh.built_ins import XSH from xonsh.platform import HAS_PYGMENTS from xonsh.lazyasd import LazyDict, lazyobject from xonsh.color_tools import ( @@ -49,7 +49,7 @@ def _ensure_color_map(style="default", cmap=None): except Exception: msg = "Could not find color style {0!r}, using default." print(msg.format(style), file=sys.stderr) - builtins.__xonsh__.env["XONSH_COLOR_STYLE"] = "default" + XSH.env["XONSH_COLOR_STYLE"] = "default" cmap = ANSI_STYLES["default"] return cmap @@ -163,7 +163,7 @@ def ansi_partial_color_format(template, style="default", cmap=None, hide=False): def _ansi_partial_color_format_main(template, style="default", cmap=None, hide=False): cmap = _ensure_color_map(style=style, cmap=cmap) - overrides = builtins.__xonsh__.env["XONSH_STYLE_OVERRIDES"] + overrides = XSH.env["XONSH_STYLE_OVERRIDES"] if overrides: cmap.update(_style_dict_to_ansi(overrides)) esc = ("\001" if hide else "") + "\033[" diff --git a/xonsh/ast.py b/xonsh/ast.py index 751c663d5..9b0e97e85 100644 --- a/xonsh/ast.py +++ b/xonsh/ast.py @@ -3,7 +3,6 @@ # These are imported into our module namespace for the benefit of parser.py. # pylint: disable=unused-import import sys -import builtins from ast import ( Module, Num, @@ -109,6 +108,7 @@ from ast import Ellipsis as EllipsisNode import textwrap import itertools +from xonsh.built_ins import XSH from xonsh.tools import subproc_toks, find_next_break, get_logical_line from ast import ( @@ -314,8 +314,8 @@ def isexpression(node, ctx=None, *args, **kwargs): # parse string to AST if isinstance(node, str): node = node if node.endswith("\n") else node + "\n" - ctx = builtins.__xonsh__.ctx if ctx is None else ctx - node = builtins.__xonsh__.execer.parse(node, ctx, *args, **kwargs) + ctx = XSH.ctx if ctx is None else ctx + node = XSH.execer.parse(node, ctx, *args, **kwargs) # determin if expresission-like enough if isinstance(node, (Expr, Expression)): isexpr = True diff --git a/xonsh/base_shell.py b/xonsh/base_shell.py index 9a89b194b..bd41d2c86 100644 --- a/xonsh/base_shell.py +++ b/xonsh/base_shell.py @@ -4,8 +4,8 @@ import io import os import sys import time -import builtins +from xonsh.built_ins import XSH from xonsh.tools import ( XonshError, print_exception, @@ -66,7 +66,7 @@ class _TeeStdBuf(io.RawIOBase): """ self.stdbuf = stdbuf self.membuf = membuf - env = builtins.__xonsh__.env + env = XSH.env self.encoding = env.get("XONSH_ENCODING") if encoding is None else encoding self.errors = env.get("XONSH_ENCODING_ERRORS") if errors is None else errors self.prestd = prestd @@ -268,7 +268,7 @@ class Tee: write_through=write_through, ) self.stdout = _TeeStd("stdout", self.memory) - env = builtins.__xonsh__.env + env = XSH.env prestderr = format_std_prepost(env.get("XONSH_STDERR_PREFIX")) poststderr = format_std_prepost(env.get("XONSH_STDERR_POSTFIX")) self.stderr = _TeeStd( @@ -324,7 +324,7 @@ class BaseShell(object): if HAS_PYGMENTS: from xonsh.pyghooks import XonshStyle - env = builtins.__xonsh__.env + env = XSH.env self._styler = XonshStyle(env.get("XONSH_COLOR_STYLE")) else: self._styler = None @@ -367,8 +367,8 @@ class BaseShell(object): events.on_precommand.fire(cmd=src) - env = builtins.__xonsh__.env - hist = builtins.__xonsh__.history # pylint: disable=no-member + env = XSH.env + hist = XSH.history # pylint: disable=no-member ts1 = None enc = env.get("XONSH_ENCODING") err = env.get("XONSH_ENCODING_ERRORS") @@ -406,7 +406,7 @@ class BaseShell(object): print(os.linesep, end="") tee.close() self._fix_cwd() - if builtins.__xonsh__.exit: # pylint: disable=no-member + if XSH.exit: # pylint: disable=no-member return True def _append_history(self, tee_out=None, **info): @@ -415,7 +415,7 @@ class BaseShell(object): This also handles on_postcommand because this is the place where all the information is available. """ - hist = builtins.__xonsh__.history # pylint: disable=no-member + hist = XSH.history # pylint: disable=no-member info["rtn"] = hist.last_cmd_rtn if hist is not None else None tee_out = tee_out or None last_out = hist.last_cmd_out if hist is not None else None @@ -436,7 +436,7 @@ class BaseShell(object): def _fix_cwd(self): """Check if the cwd changed out from under us.""" - env = builtins.__xonsh__.env + env = XSH.env try: cwd = os.getcwd() except (FileNotFoundError, OSError): @@ -523,7 +523,7 @@ class BaseShell(object): def settitle(self): """Sets terminal title.""" - env = builtins.__xonsh__.env # pylint: disable=no-member + env = XSH.env # pylint: disable=no-member term = env.get("TERM", None) # Shells running in emacs sets TERM to "dumb" or "eterm-color". # Do not set title for these to avoid garbled prompt. @@ -557,7 +557,7 @@ class BaseShell(object): print_exception() self.mlprompt = " " return self.mlprompt - env = builtins.__xonsh__.env # pylint: disable=no-member + env = XSH.env # pylint: disable=no-member p = env.get("PROMPT") try: p = self.prompt_formatter(p) @@ -570,7 +570,7 @@ class BaseShell(object): """Formats the colors in a string. ``BaseShell``'s default implementation of this method uses colors based on ANSI color codes. """ - style = builtins.__xonsh__.env.get("XONSH_COLOR_STYLE") + style = XSH.env.get("XONSH_COLOR_STYLE") return ansi_partial_color_format(string, hide=hide, style=style) def print_color(self, string, hide=False, **kwargs): @@ -583,7 +583,7 @@ class BaseShell(object): s = self.format_color(string, hide=hide) elif HAS_PYGMENTS: # assume this is a list of (Token, str) tuples and format it - env = builtins.__xonsh__.env + env = XSH.env self.styler.style_name = env.get("XONSH_COLOR_STYLE") style_proxy = pyghooks.xonsh_style_proxy(self.styler) formatter = pyghooks.XonshTerminal256Formatter(style=style_proxy) diff --git a/xonsh/built_ins.py b/xonsh/built_ins.py index 32de64409..c9df01b33 100644 --- a/xonsh/built_ins.py +++ b/xonsh/built_ins.py @@ -18,11 +18,9 @@ import itertools import contextlib import collections.abc as cabc -from xonsh.ast import AST -from xonsh.lazyasd import LazyObject, lazyobject +from ast import AST +from xonsh.lazyasd import lazyobject from xonsh.inspectors import Inspector -from xonsh.aliases import Aliases, make_default_aliases -from xonsh.environ import Env, default_env from xonsh.platform import ON_POSIX, ON_WINDOWS from xonsh.tools import ( expand_path, @@ -31,14 +29,8 @@ from xonsh.tools import ( XonshCalledProcessError, print_color, ) -from xonsh.commands_cache import CommandsCache -from xonsh.events import events -import xonsh.procs.specs -import xonsh.completers.init - -BUILTINS_LOADED = False -INSPECTOR = LazyObject(Inspector, globals(), "INSPECTOR") +INSPECTOR = Inspector() warnings.filterwarnings("once", category=DeprecationWarning) @@ -136,9 +128,9 @@ def regexsearch(s): def globsearch(s): - csc = builtins.__xonsh__.env.get("CASE_SENSITIVE_COMPLETIONS") - glob_sorted = builtins.__xonsh__.env.get("GLOB_SORTED") - dotglob = builtins.__xonsh__.env.get("DOTGLOB") + csc = XSH.env.get("CASE_SENSITIVE_COMPLETIONS") + glob_sorted = XSH.env.get("GLOB_SORTED") + dotglob = XSH.env.get("DOTGLOB") return globpath( s, ignore_case=(not csc), @@ -168,6 +160,9 @@ def subproc_captured_stdout(*cmds, envs=None): """Runs a subprocess, capturing the output. Returns the stdout that was produced as a str. """ + + import xonsh.procs.specs + return xonsh.procs.specs.run_subproc(cmds, captured="stdout", envs=envs) @@ -177,12 +172,14 @@ def subproc_captured_inject(*cmds, envs=None): The string is split using xonsh's lexer, rather than Python's str.split() or shlex.split(). """ + import xonsh.procs.specs + o = xonsh.procs.specs.run_subproc(cmds, captured="object", envs=envs) o.end() toks = [] for line in o: line = line.rstrip(os.linesep) - toks.extend(builtins.__xonsh__.execer.parser.lexer.split(line)) + toks.extend(XSH.execer.parser.lexer.split(line)) return toks @@ -191,6 +188,8 @@ def subproc_captured_object(*cmds, envs=None): Runs a subprocess, capturing the output. Returns an instance of CommandPipeline representing the completed command. """ + import xonsh.procs.specs + return xonsh.procs.specs.run_subproc(cmds, captured="object", envs=envs) @@ -198,6 +197,8 @@ def subproc_captured_hiddenobject(*cmds, envs=None): """Runs a subprocess, capturing the output. Returns an instance of HiddenCommandPipeline representing the completed command. """ + import xonsh.procs.specs + return xonsh.procs.specs.run_subproc(cmds, captured="hiddenobject", envs=envs) @@ -205,6 +206,8 @@ def subproc_uncaptured(*cmds, envs=None): """Runs a subprocess, without capturing the output. Returns the stdout that was produced as a str. """ + import xonsh.procs.specs + return xonsh.procs.specs.run_subproc(cmds, captured=False, envs=envs) @@ -252,16 +255,16 @@ def list_of_list_of_strs_outer_product(x): for los in itertools.product(*lolos): s = "".join(los) if "*" in s: - rtn.extend(builtins.__xonsh__.glob(s)) + rtn.extend(XSH.glob(s)) else: - rtn.append(builtins.__xonsh__.expand_path(s)) + rtn.append(XSH.expand_path(s)) return rtn def eval_fstring_field(field): """Evaluates the argument in Xonsh context.""" - res = __xonsh__.execer.eval( - field[0].strip(), glbs=globals(), locs=builtins.__xonsh__.ctx, filename=field[1] + res = XSH.execer.eval( + field[0].strip(), glbs=globals(), locs=XSH.ctx, filename=field[1] ) return res @@ -327,7 +330,7 @@ def convert_macro_arg(raw_arg, kind, glbs, locs, *, name="", macroname=" tp.Dict[str, tp.Any]: """Update the cmds_cache variable in background without slowing down parseLexer""" - env = builtins.__xonsh__.env # type: ignore + env = XSH.env # type: ignore allcmds = {} for path in reversed(paths): @@ -330,7 +330,7 @@ class CommandsCache(cabc.Mapping): """ # alias stuff if not os.path.isabs(cmd0) and os.sep not in cmd0: - alss = getattr(builtins, "aliases", dict()) + alss = getattr(XSH, "aliases", dict()) if cmd0 in alss: return self.default_predictor_alias(cmd0) @@ -347,7 +347,7 @@ class CommandsCache(cabc.Mapping): 10 # this limit is se to handle infinite loops in aliases definition ) first_args = [] # contains in reverse order args passed to the aliased command - alss = getattr(builtins, "aliases", dict()) + alss = getattr(XSH, "aliases", dict()) while cmd0 in alss: alias_name = alss[cmd0] if isinstance(alias_name, (str, bytes)) or not isinstance( @@ -507,7 +507,7 @@ def predict_env(args): if args[i] and args[i][0] != "-" and "=" not in args[i]: # args[i] is the command and the following is its arguments # so args[i:] is used to predict if the command is threadable - return builtins.__xonsh__.commands_cache.predict_threadable(args[i:]) + return XSH.commands_cache.predict_threadable(args[i:]) return True diff --git a/xonsh/completer.py b/xonsh/completer.py index 8077cc77a..23b4a16af 100644 --- a/xonsh/completer.py +++ b/xonsh/completer.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- """A (tab-)completer for xonsh.""" -import builtins import typing as tp import collections.abc as cabc @@ -11,6 +10,7 @@ from xonsh.completers.tools import ( apply_lprefix, is_exclusive_completer, ) +from xonsh.built_ins import XSH from xonsh.parsers.completion_context import CompletionContext, CompletionContextParser from xonsh.tools import print_exception @@ -80,7 +80,7 @@ class Completer(object): def complete_from_context(self, completion_context, old_completer_args=None): lprefix = 0 completions = set() - for func in builtins.__xonsh__.completers.values(): + for func in XSH.completers.values(): try: if is_contextual_completer(func): if completion_context is None: diff --git a/xonsh/completers/_aliases.py b/xonsh/completers/_aliases.py index adf113c38..9e3a5ca3d 100644 --- a/xonsh/completers/_aliases.py +++ b/xonsh/completers/_aliases.py @@ -1,8 +1,8 @@ import argparse as ap -import builtins import xonsh.cli_utils as xcli import xonsh.lazyasd as xl +from xonsh.built_ins import XSH from xonsh.completers.completer import ( list_completers, remove_completer, @@ -60,7 +60,7 @@ def _register_completer(name: str, func: str, pos="start", stack=None): """ err = None func_name = func - xsh = builtins.__xonsh__ # type: ignore + xsh = XSH if name in xsh.completers: err = f"The name {name} is already a registered completer function." else: diff --git a/xonsh/completers/bash.py b/xonsh/completers/bash.py index d7d6806b2..3acec9b48 100644 --- a/xonsh/completers/bash.py +++ b/xonsh/completers/bash.py @@ -1,5 +1,4 @@ """Xonsh hooks into bash completions.""" -import builtins import xonsh.tools as xt import xonsh.platform as xp @@ -7,13 +6,14 @@ from xonsh.completers.path import _quote_paths from xonsh.completers.bash_completion import bash_completions from xonsh.completers.tools import contextual_command_completer, RichCompletion from xonsh.parsers.completion_context import CommandContext +from xonsh.built_ins import XSH @contextual_command_completer def complete_from_bash(context: CommandContext): """Completes based on results from BASH completion.""" - env = builtins.__xonsh__.env.detype() # type: ignore - paths = builtins.__xonsh__.env.get("BASH_COMPLETIONS", ()) # type: ignore + env = XSH.env.detype() # type: ignore + paths = XSH.env.get("BASH_COMPLETIONS", ()) # type: ignore command = xp.bash_command() args = [arg.value for arg in context.args] prefix = context.prefix # without the quotes diff --git a/xonsh/completers/commands.py b/xonsh/completers/commands.py index 17838d03c..bdeba2da3 100644 --- a/xonsh/completers/commands.py +++ b/xonsh/completers/commands.py @@ -1,5 +1,4 @@ import os -import builtins import typing as tp import xonsh.tools as xt @@ -13,6 +12,8 @@ from xonsh.completers.tools import ( non_exclusive_completer, ) from xonsh.parsers.completion_context import CompletionContext, CommandContext +from xonsh.built_ins import XSH + SKIP_TOKENS = {"sudo", "time", "timeit", "which", "showcmd", "man"} END_PROC_TOKENS = ("|", ";", "&&") # includes || @@ -26,7 +27,7 @@ def complete_command(command: CommandContext): cmd = command.prefix out: tp.Set[Completion] = { RichCompletion(s, append_space=True) - for s in builtins.__xonsh__.commands_cache # type: ignore + for s in XSH.commands_cache # type: ignore if get_filter_function()(s, cmd) } if xp.ON_WINDOWS: @@ -66,7 +67,7 @@ def complete_skipper(command_context: CommandContext): # completing the command after a SKIP_TOKEN return complete_command(skipped_command_context) - completer: Completer = builtins.__xonsh__.shell.shell.completer # type: ignore + completer: Completer = XSH.shell.shell.completer # type: ignore return completer.complete_from_context(CompletionContext(skipped_command_context)) diff --git a/xonsh/completers/completer.py b/xonsh/completers/completer.py index d89aa08a2..92ff05989 100644 --- a/xonsh/completers/completer.py +++ b/xonsh/completers/completer.py @@ -1,15 +1,8 @@ -import builtins import collections from xonsh.parsers.completion_context import CommandContext +from xonsh.built_ins import XSH from xonsh.completers.tools import contextual_command_completer_for, justify -import xonsh.lazyasd as xla - - -@xla.lazyobject -def xsh_session(): - """return current xonshSession instance.""" - return builtins.__xonsh__ # type: ignore @contextual_command_completer_for("completer") @@ -24,7 +17,7 @@ def complete_completer(command: CommandContext): curix = command.arg_index - compnames = set(xsh_session.completers.keys()) + compnames = set(XSH.completers.keys()) if curix == 1: possible = {"list", "help", "add", "remove"} elif curix == 2: @@ -39,7 +32,7 @@ def complete_completer(command: CommandContext): if command.args[1].value != "add": raise StopIteration if curix == 3: - possible = {i for i, j in xsh_session.ctx.items() if callable(j)} + possible = {i for i, j in XSH.ctx.items() if callable(j)} elif curix == 4: possible = ( {"start", "end"} @@ -55,16 +48,16 @@ def add_one_completer(name, func, loc="end"): new = collections.OrderedDict() if loc == "start": new[name] = func - for (k, v) in xsh_session.completers.items(): + for (k, v) in XSH.completers.items(): new[k] = v elif loc == "end": - for (k, v) in xsh_session.completers.items(): + for (k, v) in XSH.completers.items(): new[k] = v new[name] = func else: direction, rel = loc[0], loc[1:] found = False - for (k, v) in xsh_session.completers.items(): + for (k, v) in XSH.completers.items(): if rel == k and direction == "<": new[name] = func found = True @@ -74,14 +67,14 @@ def add_one_completer(name, func, loc="end"): found = True if not found: new[name] = func - xsh_session.completers.clear() - xsh_session.completers.update(new) + XSH.completers.clear() + XSH.completers.update(new) def list_completers(): """List the active completers""" o = "Registered Completer Functions: \n" - _comp = xsh_session.completers + _comp = XSH.completers ml = max((len(i) for i in _comp), default=0) _strs = [] for c in _comp: @@ -104,10 +97,10 @@ def remove_completer(name: str): completers in order) """ err = None - if name not in xsh_session.completers: + if name not in XSH.completers: err = f"The name {name} is not a registered completer function." if err is None: - del xsh_session.completers[name] + del XSH.completers[name] return else: return None, err + "\n", 1 diff --git a/xonsh/completers/environment.py b/xonsh/completers/environment.py index 9e0732695..d6a334c44 100644 --- a/xonsh/completers/environment.py +++ b/xonsh/completers/environment.py @@ -1,5 +1,4 @@ -import builtins - +from xonsh.built_ins import XSH from xonsh.parsers.completion_context import CompletionContext from xonsh.completers.tools import ( contextual_completer, @@ -25,6 +24,6 @@ def complete_environment_vars(context: CompletionContext): key = prefix[dollar_location + 1 :] lprefix = len(key) + 1 filter_func = get_filter_function() - env_names = builtins.__xonsh__.env # type: ignore + env_names = XSH.env return {"$" + k for k in env_names if filter_func(k, key)}, lprefix diff --git a/xonsh/completers/man.py b/xonsh/completers/man.py index bef97b223..cb440d100 100644 --- a/xonsh/completers/man.py +++ b/xonsh/completers/man.py @@ -1,12 +1,11 @@ import os import re import pickle -import builtins import subprocess import typing as tp from xonsh.parsers.completion_context import CommandContext - +from xonsh.built_ins import XSH import xonsh.lazyasd as xl from xonsh.completers.tools import get_filter_function, contextual_command_completer @@ -33,7 +32,7 @@ def complete_from_man(context: CommandContext): """ global OPTIONS, OPTIONS_PATH if OPTIONS is None: - datadir: str = builtins.__xonsh__.env["XONSH_DATA_DIR"] # type: ignore + datadir: str = XSH.env["XONSH_DATA_DIR"] # type: ignore OPTIONS_PATH = os.path.join(datadir, "man_completions_cache") try: with open(OPTIONS_PATH, "rb") as f: diff --git a/xonsh/completers/path.py b/xonsh/completers/path.py index 292669ee7..fd14b60be 100644 --- a/xonsh/completers/path.py +++ b/xonsh/completers/path.py @@ -2,7 +2,8 @@ import os import re import ast import glob -import builtins + +from xonsh.built_ins import XSH from xonsh.parsers.completion_context import CommandContext import xonsh.tools as xt @@ -26,7 +27,7 @@ def PATTERN_NEED_QUOTES(): def cd_in_command(line): """Returns True if "cd" is a token in the line, False otherwise.""" - lexer = builtins.__xonsh__.execer.parser.lexer + lexer = XSH.execer.parser.lexer lexer.reset() lexer.input(line) have_cd = False @@ -80,7 +81,7 @@ def _path_from_partial_string(inp, pos=None): except (SyntaxError, ValueError): return None if isinstance(val, bytes): - env = builtins.__xonsh__.env + env = XSH.env val = val.decode( encoding=env.get("XONSH_ENCODING"), errors=env.get("XONSH_ENCODING_ERRORS") ) @@ -102,7 +103,7 @@ def _normpath(p): p = os.path.join(os.curdir, p) if trailing_slash: p = os.path.join(p, "") - if xp.ON_WINDOWS and builtins.__xonsh__.env.get("FORCE_POSIX_PATHS"): + if xp.ON_WINDOWS and XSH.env.get("FORCE_POSIX_PATHS"): p = p.replace(os.sep, os.altsep) return p @@ -118,7 +119,7 @@ def _startswithnorm(x, start, startlow=None): def _dots(prefix): - complete_dots = builtins.__xonsh__.env.get("COMPLETE_DOTS", "matching").lower() + complete_dots = XSH.env.get("COMPLETE_DOTS", "matching").lower() if complete_dots == "never": return () slash = xt.get_sep() @@ -137,7 +138,7 @@ def _dots(prefix): def _add_cdpaths(paths, prefix): """Completes current prefix using CDPATH""" - env = builtins.__xonsh__.env + env = XSH.env csc = env.get("CASE_SENSITIVE_COMPLETIONS") glob_sorted = env.get("GLOB_SORTED") for cdp in env.get("CDPATH"): @@ -159,7 +160,7 @@ def _quote_to_use(x): def _is_directory_in_cdpath(path): - env = builtins.__xonsh__.env + env = XSH.env for cdp in env.get("CDPATH"): if os.path.isdir(os.path.join(cdp, path)): return True @@ -167,7 +168,7 @@ def _is_directory_in_cdpath(path): def _quote_paths(paths, start, end, append_end=True, cdpath=False): - expand_path = builtins.__xonsh__.expand_path + expand_path = XSH.expand_path out = set() space = " " backslash = "\\" @@ -274,7 +275,7 @@ def _subsequence_match_iter(ref, typed): def _expand_one(sofar, nextone, csc): out = set() - glob_sorted = builtins.__xonsh__.env.get("GLOB_SORTED") + glob_sorted = XSH.env.get("GLOB_SORTED") for i in sofar: _glob = os.path.join(_joinpath(i), "*") if i is not None else "*" for j in xt.iglobpath(_glob, sort_result=glob_sorted): @@ -305,7 +306,7 @@ def _complete_path_raw(prefix, line, start, end, ctx, cdpath=True, filtfunc=None append_end = False tilde = "~" paths = set() - env = builtins.__xonsh__.env + env = XSH.env csc = env.get("CASE_SENSITIVE_COMPLETIONS") glob_sorted = env.get("GLOB_SORTED") prefix = glob.escape(prefix) diff --git a/xonsh/completers/python.py b/xonsh/completers/python.py index 5a0571a20..2a304b64d 100644 --- a/xonsh/completers/python.py +++ b/xonsh/completers/python.py @@ -10,6 +10,7 @@ from xonsh.parsers.completion_context import CompletionContext, PythonContext import xonsh.tools as xt import xonsh.lazyasd as xl +from xonsh.built_ins import XSH from xonsh.completers.tools import ( CompleterResult, @@ -145,7 +146,7 @@ def complete_python(context: CompletionContext) -> CompleterResult: # this can be a command (i.e. not a subexpression) first = context.command.args[0].value ctx = context.python.ctx or {} - if first in builtins.__xonsh__.commands_cache and first not in ctx: # type: ignore + if first in XSH.commands_cache and first not in ctx: # type: ignore # this is a known command, so it won't be python code return None @@ -206,7 +207,7 @@ def _safe_eval(expr, ctx): a (None, None) tuple. """ _ctx = None - xonsh_safe_eval = builtins.__xonsh__.execer.eval + xonsh_safe_eval = XSH.execer.eval try: val = xonsh_safe_eval(expr, ctx, ctx, transform=False) _ctx = ctx @@ -245,7 +246,7 @@ def attr_complete(prefix, ctx, filter_func): if _val_ is None and _ctx_ is None: continue a = getattr(val, opt) - if builtins.__xonsh__.env["COMPLETIONS_BRACKETS"]: + if XSH.env["COMPLETIONS_BRACKETS"]: if callable(a): rpl = opt + "(" elif isinstance(a, (cabc.Sequence, cabc.Mapping)): diff --git a/xonsh/completers/tools.py b/xonsh/completers/tools.py index bdd817a12..e36d34c7e 100644 --- a/xonsh/completers/tools.py +++ b/xonsh/completers/tools.py @@ -1,9 +1,9 @@ """Xonsh completer tools.""" -import builtins import textwrap import typing as tp from functools import wraps +from xonsh.built_ins import XSH from xonsh.parsers.completion_context import CompletionContext, CommandContext @@ -20,7 +20,7 @@ def get_filter_function(): Return an appropriate filtering function for completions, given the valid of $CASE_SENSITIVE_COMPLETIONS """ - csc = builtins.__xonsh__.env.get("CASE_SENSITIVE_COMPLETIONS") + csc = XSH.env.get("CASE_SENSITIVE_COMPLETIONS") if csc: return _filter_normal else: diff --git a/xonsh/contexts.py b/xonsh/contexts.py index 217c7fcd7..be0ddc7e0 100644 --- a/xonsh/contexts.py +++ b/xonsh/contexts.py @@ -1,9 +1,10 @@ """Context management tools for xonsh.""" import sys import textwrap -import builtins from collections.abc import Mapping +from xonsh.built_ins import XSH + class Block(object): """This is a context manager for obtaining a block of lines without actually @@ -28,7 +29,9 @@ class Block(object): def __enter__(self): if not hasattr(self, "macro_block"): - raise XonshError(self.__class__.__name__ + " must be entered as a macro!") + raise XSH.builtins.XonshError( + self.__class__.__name__ + " must be entered as a macro!" + ) self.lines = self.macro_block.splitlines() self.glbs = self.macro_globals if self.macro_locals is not self.macro_globals: @@ -93,7 +96,7 @@ class Functor(Block): fstr = fstr.format(name=name, sig=sig, body=body, rtn=rtn) glbs = self.glbs locs = self.locs - execer = builtins.__xonsh__.execer + execer = XSH.execer execer.exec(fstr, glbs=glbs, locs=locs) if locs is not None and name in locs: func = locs[name] diff --git a/xonsh/dirstack.py b/xonsh/dirstack.py index a52b4b2ab..fa1d9b06d 100644 --- a/xonsh/dirstack.py +++ b/xonsh/dirstack.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """Directory stack and associated utilities for the xonsh shell.""" import argparse -import builtins import glob import os import subprocess import typing as tp +from xonsh.built_ins import XSH from xonsh.events import events from xonsh.lazyasd import lazyobject from xonsh.platform import ON_WINDOWS @@ -145,7 +145,7 @@ def _get_cwd(): def _change_working_directory(newdir, follow_symlinks=False): - env = builtins.__xonsh__.env + env = XSH.env old = env["PWD"] new = os.path.join(old, newdir) @@ -180,10 +180,10 @@ def _try_cdpath(apath): # a second $ cd xonsh has no effects, to move in the nested xonsh # in bash a full $ cd ./xonsh is needed. # In xonsh a relative folder is always preferred. - env = builtins.__xonsh__.env + env = XSH.env cdpaths = env.get("CDPATH") for cdp in cdpaths: - globber = builtins.__xonsh__.expand_path(os.path.join(cdp, apath)) + globber = XSH.expand_path(os.path.join(cdp, apath)) for cdpath_prefixed_path in glob.iglob(globber): return cdpath_prefixed_path return apath @@ -195,7 +195,7 @@ def cd(args, stdin=None): If no directory is specified (i.e. if `args` is None) then this changes to the current user's home directory. """ - env = builtins.__xonsh__.env + env = XSH.env oldpwd = env.get("OLDPWD", None) cwd = env["PWD"] @@ -307,7 +307,7 @@ def pushd(args, stdin=None): except SystemExit: return None, None, 1 - env = builtins.__xonsh__.env + env = XSH.env pwd = env["PWD"] @@ -406,7 +406,7 @@ def popd(args, stdin=None): except SystemExit: return None, None, 1 - env = builtins.__xonsh__.env + env = XSH.env if env.get("PUSHD_MINUS"): BACKWARD = "-" @@ -454,7 +454,7 @@ def popd(args, stdin=None): if new_pwd is not None: e = None if args.cd: - env = builtins.__xonsh__.env + env = XSH.env pwd = env["PWD"] _change_working_directory(new_pwd) @@ -515,7 +515,7 @@ def dirs(args, stdin=None): except SystemExit: return None, None - env = builtins.__xonsh__.env + env = XSH.env dirstack = [os.path.expanduser(env["PWD"])] + DIRSTACK if env.get("PUSHD_MINUS"): diff --git a/xonsh/dumb_shell.py b/xonsh/dumb_shell.py index 9e4f8da18..840a050b0 100644 --- a/xonsh/dumb_shell.py +++ b/xonsh/dumb_shell.py @@ -1,6 +1,6 @@ """A dumb shell for when $TERM == 'dumb', which usually happens in emacs.""" -import builtins +from xonsh.built_ins import XSH from xonsh.readline_shell import ReadlineShell @@ -8,5 +8,5 @@ class DumbShell(ReadlineShell): """A dumb shell for when $TERM == 'dumb', which usually happens in emacs.""" def __init__(self, *args, **kwargs): - builtins.__xonsh__.env["XONSH_COLOR_STYLE"] = "emacs" + XSH.env["XONSH_COLOR_STYLE"] = "emacs" super().__init__(*args, **kwargs) diff --git a/xonsh/environ.py b/xonsh/environ.py index 6d210cc52..811722627 100644 --- a/xonsh/environ.py +++ b/xonsh/environ.py @@ -7,7 +7,6 @@ import pprint import textwrap import locale import glob -import builtins import warnings import contextlib import collections.abc as cabc @@ -29,7 +28,7 @@ from xonsh.platform import ( ON_CYGWIN, os_environ, ) - +from xonsh.built_ins import XSH from xonsh.tools import ( always_true, always_false, @@ -193,12 +192,8 @@ def to_debug(x): execer's debug level. """ val = to_bool_or_int(x) - if ( - hasattr(builtins, "__xonsh__") - and hasattr(builtins.__xonsh__, "execer") - and builtins.__xonsh__.execer is not None - ): - builtins.__xonsh__.execer.debug_level = val + if XSH.execer is not None: + XSH.execer.debug_level = val return val @@ -427,7 +422,7 @@ class LsColors(cabc.MutableMapping): @property def style_name(self): """Current XONSH_COLOR_STYLE value""" - env = getattr(builtins.__xonsh__, "env", {}) + env = getattr(XSH, "env", {}) env_style_name = env.get("XONSH_COLOR_STYLE", "default") if self._style_name is None or self._style_name != env_style_name: self._style_name = env_style_name @@ -479,8 +474,8 @@ class LsColors(cabc.MutableMapping): if filename is not None: cmd.append(filename) # get env - if hasattr(builtins, "__xonsh__") and hasattr(builtins.__xonsh__, "env"): - denv = builtins.__xonsh__.env.detype() + if XSH.env: + denv = XSH.env.detype() else: denv = None # run dircolors @@ -519,7 +514,7 @@ def ensure_ls_colors_in_env(spec=None, **kwargs): environment. This fires exactly once upon the first time the ls command is called. """ - env = builtins.__xonsh__.env + env = XSH.env if "LS_COLORS" not in env._d: # this adds it to the env too default_lscolors(env) @@ -2148,7 +2143,7 @@ def _yield_executables(directory, name): def locate_binary(name): """Locates an executable on the file system.""" - return builtins.__xonsh__.commands_cache.locate_binary(name) + return XSH.commands_cache.locate_binary(name) def xonshrc_context( diff --git a/xonsh/events.py b/xonsh/events.py index ce5b14610..9f1e783ff 100644 --- a/xonsh/events.py +++ b/xonsh/events.py @@ -1,17 +1,17 @@ """ Events for xonsh. -In all likelihood, you want builtins.events +In all likelihood, you want xonsh.built_ins.XSH.events The best way to "declare" an event is something like:: events.doc('on_spam', "Comes with eggs") """ import abc -import builtins import collections.abc import inspect +from xonsh.built_ins import XSH from xonsh.tools import print_exception @@ -22,8 +22,8 @@ def has_kwargs(func): def debug_level(): - if hasattr(builtins, "__xonsh__") and hasattr(builtins.__xonsh__, "env"): - return builtins.__xonsh__.env.get("XONSH_DEBUG") + if XSH.env: + return XSH.env.get("XONSH_DEBUG") # FIXME: Under py.test, return 1(?) else: return 0 # Optimize for speed, not guaranteed correctness diff --git a/xonsh/execer.py b/xonsh/execer.py index e9f07565a..674a2bf3e 100644 --- a/xonsh/execer.py +++ b/xonsh/execer.py @@ -16,7 +16,7 @@ from xonsh.tools import ( balanced_parens, starting_whitespace, ) -from xonsh.built_ins import load_builtins, unload_builtins +from xonsh.built_ins import XSH class Execer(object): @@ -43,7 +43,7 @@ class Execer(object): unload : bool, optional Whether or not to unload xonsh builtins upon deletion. xonsh_ctx : dict or None, optional - Xonsh xontext to load as builtins.__xonsh__.ctx + Xonsh xontext to load as xonsh.built_ins.XSH.ctx scriptcache : bool, optional Whether or not to use a precompiled bytecode cache when execing code, default: True. @@ -60,11 +60,11 @@ class Execer(object): self.scriptcache = scriptcache self.cacheall = cacheall self.ctxtransformer = CtxAwareTransformer(self.parser) - load_builtins(execer=self, ctx=xonsh_ctx) + XSH.load(execer=self, ctx=xonsh_ctx) def __del__(self): if self.unload: - unload_builtins() + XSH.unload() def parse(self, input, ctx, mode="exec", filename=None, transform=True): """Parses xonsh code in a context-aware fashion. For context-free diff --git a/xonsh/foreign_shells.py b/xonsh/foreign_shells.py index eeefd0a15..481217663 100644 --- a/xonsh/foreign_shells.py +++ b/xonsh/foreign_shells.py @@ -6,12 +6,12 @@ import json import shlex import sys import tempfile -import builtins import subprocess import warnings import functools import collections.abc as cabc +from xonsh.built_ins import XSH from xonsh.lazyasd import lazyobject from xonsh.tools import to_bool, ensure_string from xonsh.platform import ON_WINDOWS, ON_CYGWIN, ON_MSYS @@ -275,8 +275,8 @@ def foreign_shell_data( tmpfile.write(command.encode("utf8")) tmpfile.close() cmd.append(tmpfile.name) - if currenv is None and hasattr(builtins.__xonsh__, "env"): - currenv = builtins.__xonsh__.env.detype() + if currenv is None and XSH.env: + currenv = XSH.env.detype() elif currenv is not None: currenv = dict(currenv) try: @@ -472,7 +472,7 @@ class ForeignShellBaseAlias(object): args, streaming = self._is_streaming(args) input = self.INPUT.format(args=" ".join(args), **self._input_kwargs()) cmd = [self.shell] + list(self.extra_args) + ["-c", input] - env = builtins.__xonsh__.env + env = XSH.env denv = env.detype() if streaming: subprocess.check_call(cmd, env=denv) @@ -699,15 +699,15 @@ def load_foreign_aliases(shells): A dictionary of the merged aliases. """ aliases = {} - xonsh_aliases = builtins.aliases + xonsh_aliases = XSH.aliases for shell in shells: shell = ensure_shell(shell) _, shaliases = foreign_shell_data(**shell) - if not builtins.__xonsh__.env.get("FOREIGN_ALIASES_OVERRIDE"): + if not XSH.env.get("FOREIGN_ALIASES_OVERRIDE"): shaliases = {} if shaliases is None else shaliases for alias in set(shaliases) & set(xonsh_aliases): del shaliases[alias] - if builtins.__xonsh__.env.get("XONSH_DEBUG") > 1: + if XSH.env.get("XONSH_DEBUG") > 1: print( "aliases: ignoring alias {!r} of shell {!r} " "which tries to override xonsh alias." diff --git a/xonsh/history/json.py b/xonsh/history/json.py index c3b90aa03..e2fc22a43 100644 --- a/xonsh/history/json.py +++ b/xonsh/history/json.py @@ -3,11 +3,12 @@ import os import sys import time -import builtins import collections import threading import collections.abc as cabc +from xonsh.built_ins import XSH + try: import ujson as json except ImportError: @@ -90,7 +91,7 @@ def _xhj_gc_bytes_to_rmfiles(hsize, files): def _xhj_get_data_dir(): dir = xt.expanduser_abs_path( - os.path.join(builtins.__xonsh__.env.get("XONSH_DATA_DIR"), "history_json") + os.path.join(XSH.env.get("XONSH_DATA_DIR"), "history_json") ) if not os.path.exists(dir): os.makedirs(dir) @@ -103,9 +104,7 @@ def _xhj_get_history_files(sort=True, newest_first=False): """ data_dirs = [ _xhj_get_data_dir(), - builtins.__xonsh__.env.get( - "XONSH_DATA_DIR" - ), # backwards compatibility, remove in the future + XSH.env.get("XONSH_DATA_DIR"), # backwards compatibility, remove in the future ] files = [] @@ -118,14 +117,14 @@ def _xhj_get_history_files(sort=True, newest_first=False): if f.startswith("xonsh-") and f.endswith(".json") ] except OSError: - if builtins.__xonsh__.env.get("XONSH_DEBUG"): + if XSH.env.get("XONSH_DEBUG"): xt.print_exception( f"Could not collect xonsh history json files from {data_dir}" ) if sort: files.sort(key=lambda x: os.path.getmtime(x), reverse=newest_first) - custom_history_file = builtins.__xonsh__.env.get("XONSH_HISTORY_FILE", None) + custom_history_file = XSH.env.get("XONSH_HISTORY_FILE", None) if custom_history_file: custom_history_file = xt.expanduser_abs_path(custom_history_file) if custom_history_file not in files: @@ -157,7 +156,7 @@ class JsonHistoryGC(threading.Thread): def run(self): while self.wait_for_shell: time.sleep(0.01) - env = builtins.__xonsh__.env # pylint: disable=no-member + env = XSH.env # pylint: disable=no-member xonsh_debug = env.get("XONSH_DEBUG", 0) if self.size is None: hsize, units = env.get("XONSH_HISTORY_SIZE") @@ -169,7 +168,7 @@ class JsonHistoryGC(threading.Thread): raise ValueError("Units type {0!r} not understood".format(units)) size_over, rm_files = rmfiles_fn(hsize, files) - hist = getattr(builtins.__xonsh__, "history", None) + hist = getattr(XSH, "history", None) if hist is not None: # remember last gc pass history size hist.hist_size = size_over + hsize hist.hist_units = units @@ -201,7 +200,7 @@ class JsonHistoryGC(threading.Thread): This is sorted by the last closed time. Returns a list of (file_size, timestamp, number of cmds, file name) tuples. """ - env = getattr(getattr(builtins, "__xonsh__", None), "env", None) + env = XSH.env if env is None: return [] @@ -283,7 +282,7 @@ class JsonHistoryFlusher(threading.Thread): def dump(self): """Write the cached history to external storage.""" - opts = builtins.__xonsh__.env.get("HISTCONTROL", "") + opts = XSH.env.get("HISTCONTROL", "") last_inp = None cmds = [] for cmd in self.buffer: @@ -305,9 +304,11 @@ class JsonHistoryFlusher(threading.Thread): load_hist_len = len(hist["cmds"]) hist["cmds"].extend(cmds) if self.at_exit: - hist["ts"][1] = time.time() # apply end time + # todo: check why this is here. + if "ts" in hist: + hist["ts"][1] = time.time() # apply end time hist["locked"] = False - if not builtins.__xonsh__.env.get("XONSH_STORE_STDOUT", False): + if not XSH.env.get("XONSH_STORE_STDOUT", False): [cmd.pop("out") for cmd in hist["cmds"][load_hist_len:] if "out" in cmd] with open(self.filename, "w", newline="\n") as f: xlj.ljdump(hist, f, sort_keys=True) @@ -445,7 +446,7 @@ class JsonHistory(History): self.save_cwd = ( save_cwd if save_cwd is not None - else builtins.__xonsh__.env.get("XONSH_HISTORY_SAVE_CWD", True) + else XSH.env.get("XONSH_HISTORY_SAVE_CWD", True) ) def __len__(self): @@ -472,7 +473,7 @@ class JsonHistory(History): if not self.remember_history: return - opts = builtins.__xonsh__.env.get("HISTCONTROL", "") + opts = XSH.env.get("HISTCONTROL", "") skipped_by_ignore_space = "ignorespace" in opts and cmd.get("spc") if skipped_by_ignore_space: return None @@ -553,7 +554,7 @@ class JsonHistory(History): commands = json_file.load()["cmds"] except (json.decoder.JSONDecodeError, ValueError): # file is corrupted somehow - if builtins.__xonsh__.env.get("XONSH_DEBUG") > 0: + if XSH.env.get("XONSH_DEBUG") > 0: msg = "xonsh history file {0!r} is not valid JSON" print(msg.format(f), file=sys.stderr) continue @@ -572,7 +573,7 @@ class JsonHistory(History): data["length"] = len(self) data["buffersize"] = self.buffersize data["bufferlength"] = len(self.buffer) - envs = builtins.__xonsh__.env + envs = XSH.env data["gc options"] = envs.get("XONSH_HISTORY_SIZE") data["gc_last_size"] = f"{(self.hist_size, self.hist_units)}" return data diff --git a/xonsh/history/main.py b/xonsh/history/main.py index d2c76ce73..6658c6409 100644 --- a/xonsh/history/main.py +++ b/xonsh/history/main.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- """Main entry points of the xonsh history.""" import argparse -import builtins import datetime import functools import json @@ -9,6 +8,7 @@ import os import sys import threading +from xonsh.built_ins import XSH from xonsh.history.base import History from xonsh.history.dummy import DummyHistory from xonsh.history.json import JsonHistory @@ -22,7 +22,7 @@ HISTORY_BACKENDS = {"dummy": DummyHistory, "json": JsonHistory, "sqlite": Sqlite def construct_history(**kwargs): """Construct the history backend object.""" - env = builtins.__xonsh__.env + env = XSH.env backend = env.get("XONSH_HISTORY_BACKEND") if isinstance(backend, str) and backend in HISTORY_BACKENDS: kls_history = HISTORY_BACKENDS[backend] @@ -42,14 +42,14 @@ def construct_history(**kwargs): def _xh_session_parser(hist=None, newest_first=False, **kwargs): """Returns history items of current session.""" if hist is None: - hist = builtins.__xonsh__.history + hist = XSH.history return hist.items() def _xh_all_parser(hist=None, newest_first=False, **kwargs): """Returns all history items.""" if hist is None: - hist = builtins.__xonsh__.history + hist = XSH.history return hist.all_items(newest_first=newest_first) @@ -356,7 +356,7 @@ def _xh_create_parser(): help="makes the gc non-blocking, and thus return sooner", ) - hist = builtins.__xonsh__.history + hist = XSH.history if isinstance(hist, JsonHistory): # add actions belong only to JsonHistory diff = subp.add_parser("diff", help="diff two xonsh history files") @@ -408,7 +408,7 @@ def history_main( args=None, stdin=None, stdout=None, stderr=None, spec=None, stack=None ): """This is the history command entry point.""" - hist = builtins.__xonsh__.history + hist = XSH.history ns = _xh_parse_args(args) if not ns or not ns.action: return diff --git a/xonsh/history/sqlite.py b/xonsh/history/sqlite.py index 18e45e389..62c752238 100644 --- a/xonsh/history/sqlite.py +++ b/xonsh/history/sqlite.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- """Implements the xonsh history backend via sqlite3.""" -import builtins import collections import json import os @@ -9,6 +8,7 @@ import sys import threading import time +from xonsh.built_ins import XSH from xonsh.history.base import History import xonsh.tools as xt @@ -18,7 +18,7 @@ XH_SQLITE_CREATED_SQL_TBL = "CREATED_SQL_TABLE" def _xh_sqlite_get_file_name(): - envs = builtins.__xonsh__.env + envs = XSH.env file_name = envs.get("XONSH_HISTORY_SQLITE_FILE") if not file_name: data_dir = envs.get("XONSH_DATA_DIR") @@ -235,7 +235,7 @@ class SqliteHistoryGC(threading.Thread): if self.size is not None: hsize, units = xt.to_history_tuple(self.size) else: - envs = builtins.__xonsh__.env + envs = XSH.env hsize, units = envs.get("XONSH_HISTORY_SIZE") if units != "commands": print( @@ -267,7 +267,7 @@ class SqliteHistory(History): self.save_cwd = ( save_cwd if save_cwd is not None - else builtins.__xonsh__.env.get("XONSH_HISTORY_SAVE_CWD", True) + else XSH.env.get("XONSH_HISTORY_SAVE_CWD", True) ) if not os.path.exists(self.filename): @@ -285,7 +285,7 @@ class SqliteHistory(History): def append(self, cmd): if not self.remember_history: return - envs = builtins.__xonsh__.env + envs = XSH.env inp = cmd["inp"].rstrip() self.inps.append(inp) self.outs.append(cmd.get("out")) @@ -342,7 +342,7 @@ class SqliteHistory(History): sessionid=self.sessionid, filename=self.filename ) data["all items"] = xh_sqlite_get_count(filename=self.filename) - envs = builtins.__xonsh__.env + envs = XSH.env data["gc options"] = envs.get("XONSH_HISTORY_SIZE") return data diff --git a/xonsh/imphooks.py b/xonsh/imphooks.py index 1648327a7..d1496acae 100644 --- a/xonsh/imphooks.py +++ b/xonsh/imphooks.py @@ -3,7 +3,6 @@ This module registers the hooks it defines when it is imported. """ -import builtins import contextlib import importlib import os @@ -13,6 +12,7 @@ import types from importlib.abc import MetaPathFinder, SourceLoader, Loader from importlib.machinery import ModuleSpec +from xonsh.built_ins import XSH from xonsh.events import events from xonsh.execer import Execer from xonsh.lazyasd import lazyobject @@ -57,12 +57,8 @@ class XonshImportHook(MetaPathFinder, SourceLoader): @property def execer(self): - if ( - hasattr(builtins, "__xonsh__") - and hasattr(builtins.__xonsh__, "execer") - and builtins.__xonsh__.execer is not None - ): - execer = builtins.__xonsh__.execer + if XSH.execer is not None: + execer = XSH.execer if self._execer is not None: self._execer = None elif self._execer is None: diff --git a/xonsh/jobs.py b/xonsh/jobs.py index f47b84db6..6ac4de41a 100644 --- a/xonsh/jobs.py +++ b/xonsh/jobs.py @@ -5,18 +5,18 @@ import sys import time import ctypes import signal -import builtins import argparse import subprocess import collections import typing as tp +from xonsh.built_ins import XSH from xonsh.lazyasd import LazyObject from xonsh.platform import FD_STDERR, ON_DARWIN, ON_WINDOWS, ON_CYGWIN, ON_MSYS, LIBC from xonsh.tools import unthreadable - -tasks = LazyObject(collections.deque, globals(), "tasks") +# there is not much cost initing deque +tasks: tp.Deque[int] = collections.deque() # Track time stamp of last exit command, so that two consecutive attempts to # exit can kill all jobs and exit. _last_exit_time: tp.Optional[float] = None @@ -259,7 +259,7 @@ def get_next_task(): def get_task(tid): - return builtins.__xonsh__.all_jobs[tid] + return XSH.all_jobs[tid] def _clear_dead_jobs(): @@ -270,13 +270,13 @@ def _clear_dead_jobs(): to_remove.add(tid) for job in to_remove: tasks.remove(job) - del builtins.__xonsh__.all_jobs[job] + del XSH.all_jobs[job] def print_one_job(num, outfile=sys.stdout): """Print a line describing job number ``num``.""" try: - job = builtins.__xonsh__.all_jobs[num] + job = XSH.all_jobs[num] except KeyError: return pos = "+" if tasks[0] == num else "-" if tasks[1] == num else " " @@ -292,7 +292,7 @@ def get_next_job_number(): """Get the lowest available unique job number (for the next job created).""" _clear_dead_jobs() i = 1 - while i in builtins.__xonsh__.all_jobs: + while i in XSH.all_jobs: i += 1 return i @@ -303,8 +303,8 @@ def add_job(info): info["started"] = time.time() info["status"] = "running" tasks.appendleft(num) - builtins.__xonsh__.all_jobs[num] = info - if info["bg"] and builtins.__xonsh__.env.get("XONSH_INTERACTIVE"): + XSH.all_jobs[num] = info + if info["bg"] and XSH.env.get("XONSH_INTERACTIVE"): print_one_job(num) @@ -317,12 +317,12 @@ def clean_jobs(): warning if any exist, and return False. Otherwise, return True. """ jobs_clean = True - if builtins.__xonsh__.env["XONSH_INTERACTIVE"]: + if XSH.env["XONSH_INTERACTIVE"]: _clear_dead_jobs() - if builtins.__xonsh__.all_jobs: + if XSH.all_jobs: global _last_exit_time - hist = builtins.__xonsh__.history + hist = XSH.history if hist is not None and len(hist.tss) > 0: last_cmd_start = hist.tss[-1][0] else: @@ -335,12 +335,12 @@ def clean_jobs(): # unfinished jobs in this case. kill_all_jobs() else: - if len(builtins.__xonsh__.all_jobs) > 1: + if len(XSH.all_jobs) > 1: msg = "there are unfinished jobs" else: msg = "there is an unfinished job" - if builtins.__xonsh__.env["SHELL_TYPE"] != "prompt_toolkit": + if XSH.env["SHELL_TYPE"] != "prompt_toolkit": # The Ctrl+D binding for prompt_toolkit already inserts a # newline print() @@ -365,7 +365,7 @@ def kill_all_jobs(): Send SIGKILL to all child processes (called when exiting xonsh). """ _clear_dead_jobs() - for job in builtins.__xonsh__.all_jobs.values(): + for job in XSH.all_jobs.values(): _kill(job) @@ -402,7 +402,7 @@ def resume_job(args, wording): except (ValueError, IndexError): return "", "Invalid job: {}\n".format(args[0]) - if tid not in builtins.__xonsh__.all_jobs: + if tid not in XSH.all_jobs: return "", "Invalid job: {}\n".format(args[0]) else: return "", "{} expects 0 or 1 arguments, not {}\n".format(wording, len(args)) @@ -414,7 +414,7 @@ def resume_job(args, wording): job = get_task(tid) job["bg"] = False job["status"] = "running" - if builtins.__xonsh__.env.get("XONSH_INTERACTIVE"): + if XSH.env.get("XONSH_INTERACTIVE"): print_one_job(tid) pipeline = job["pipeline"] pipeline.resume(job) @@ -492,7 +492,7 @@ def disown(args, stdin=None): except KeyError: return "", f"'{tid}' is not a valid job ID" - auto_cont = builtins.__xonsh__.env.get("AUTO_CONTINUE", False) + auto_cont = XSH.env.get("AUTO_CONTINUE", False) if auto_cont or pargs.force_auto_continue: _continue(current_task) elif current_task["status"] == "stopped": @@ -504,7 +504,7 @@ def disown(args, stdin=None): # Stop tracking this task tasks.remove(tid) - del builtins.__xonsh__.all_jobs[tid] + del XSH.all_jobs[tid] messages.append(f"Removed job {tid} ({current_task['status']})") if messages: diff --git a/xonsh/jupyter_kernel.py b/xonsh/jupyter_kernel.py index 2779d9e08..efa02028b 100644 --- a/xonsh/jupyter_kernel.py +++ b/xonsh/jupyter_kernel.py @@ -7,7 +7,6 @@ import uuid import errno import hashlib import datetime -import builtins import threading from pprint import pformat from argparse import ArgumentParser @@ -18,6 +17,7 @@ from zmq.eventloop import ioloop, zmqstream from zmq.error import ZMQError from xonsh import __version__ as version +from xonsh.built_ins import XSH from xonsh.main import setup from xonsh.completer import Completer from xonsh.commands_cache import predict_true @@ -362,8 +362,8 @@ class XonshKernel: "payload": [], "user_expressions": {}, } - shell = builtins.__xonsh__.shell - hist = builtins.__xonsh__.history + shell = XSH.shell + hist = XSH.history try: shell.default(code, self, parent_header) interrupted = False @@ -420,7 +420,7 @@ class XonshKernel: def do_complete(self, code: str, pos: int): """Get completions.""" - shell = builtins.__xonsh__.shell # type: ignore + shell = XSH.shell # type: ignore line_start = code.rfind("\n", 0, pos) + 1 line_stop = code.find("\n", pos) if line_stop == -1: @@ -429,7 +429,7 @@ class XonshKernel: line_stop += 1 line = code[line_start:line_stop] endidx = pos - line_start - line_ex: str = builtins.aliases.expand_alias(line, endidx) # type: ignore + line_ex: str = XSH.aliases.expand_alias(line, endidx) # type: ignore begidx = line[:endidx].rfind(" ") + 1 if line[:endidx].rfind(" ") >= 0 else 0 prefix = line[begidx:endidx] @@ -492,11 +492,11 @@ if __name__ == "__main__": xontribs=["coreutils"], threadable_predictors={"git": predict_true, "man": predict_true}, ) - if builtins.__xonsh__.commands_cache.is_only_functional_alias("cat"): # type:ignore + if XSH.commands_cache.is_only_functional_alias("cat"): # type:ignore # this is needed if the underlying system doesn't have cat # we supply our own, because we can - builtins.aliases["cat"] = "xonsh-cat" # type:ignore - builtins.__xonsh__.env["PAGER"] = "xonsh-cat" # type:ignore - shell = builtins.__xonsh__.shell # type:ignore + XSH.aliases["cat"] = "xonsh-cat" # type:ignore + XSH.env["PAGER"] = "xonsh-cat" # type:ignore + shell = XSH.shell # type:ignore kernel = shell.kernel = XonshKernel() kernel.start() diff --git a/xonsh/jupyter_shell.py b/xonsh/jupyter_shell.py index 922befa56..3707e3d2a 100644 --- a/xonsh/jupyter_shell.py +++ b/xonsh/jupyter_shell.py @@ -1,9 +1,9 @@ """An interactive shell for the Jupyter kernel.""" import io import sys -import builtins from xonsh.base_shell import BaseShell +from xonsh.built_ins import XSH class StdJupyterRedirectBuf(io.RawIOBase): @@ -61,13 +61,13 @@ class StdJupyterRedirect(io.TextIOBase): @property def encoding(self): """The encoding of the stream""" - env = builtins.__xonsh__.env + env = XSH.env return getattr(self.std, "encoding", env.get("XONSH_ENCODING")) @property def errors(self): """The encoding errors of the stream""" - env = builtins.__xonsh__.env + env = XSH.env return getattr(self.std, "errors", env.get("XONSH_ENCODING_ERRORS")) @property diff --git a/xonsh/main.py b/xonsh/main.py index ce2a54c9f..dcc195c07 100644 --- a/xonsh/main.py +++ b/xonsh/main.py @@ -25,7 +25,7 @@ from xonsh.lazyimps import pygments, pyghooks from xonsh.imphooks import install_import_hooks from xonsh.events import events from xonsh.environ import xonshrc_context, make_args_env -from xonsh.built_ins import XonshSession, load_builtins +from xonsh.built_ins import XSH import xonsh.procs.pipelines as xpp @@ -251,7 +251,7 @@ def _pprint_displayhook(value): if isinstance(value, xpp.HiddenCommandPipeline): builtins._ = value return - env = builtins.__xonsh__.env + env = XSH.env printed_val = None if env.get("PRETTY_PRINT_RESULTS"): printed_val = pretty(value) @@ -294,7 +294,7 @@ def start_services(shell_kwargs, args, pre_env=None): events.on_timingprobe.fire(name="post_execer_init") # load rc files login = shell_kwargs.get("login", True) - env = builtins.__xonsh__.env + env = XSH.env for k, v in pre_env.items(): env[k] = v @@ -325,7 +325,7 @@ def start_services(shell_kwargs, args, pre_env=None): ) events.on_post_rc.fire() # create shell - builtins.__xonsh__.shell = Shell(execer=execer, **shell_kwargs) + XSH.shell = Shell(execer=execer, **shell_kwargs) ctx["__name__"] = "__main__" return env @@ -334,7 +334,6 @@ def premain(argv=None): """Setup for main xonsh entry point. Returns parsed arguments.""" if argv is None: argv = sys.argv[1:] - builtins.__xonsh__ = XonshSession() setup_timings(argv) setproctitle = get_setproctitle() if setproctitle is not None: @@ -349,7 +348,7 @@ def premain(argv=None): "login": False, "scriptcache": args.scriptcache, "cacheall": args.cacheall, - "ctx": builtins.__xonsh__.ctx, + "ctx": XSH.ctx, } if args.login or sys.argv[0].startswith("-"): args.login = True @@ -455,9 +454,9 @@ def main_xonsh(args): signal.signal(signal.SIGTTOU, func_sig_ttin_ttou) events.on_post_init.fire() - env = builtins.__xonsh__.env - shell = builtins.__xonsh__.shell - history = builtins.__xonsh__.history + env = XSH.env + shell = XSH.shell + history = XSH.history exit_code = 0 if shell and not env["XONSH_INTERACTIVE"]: @@ -513,7 +512,7 @@ def main_xonsh(args): def postmain(args=None): """Teardown for main xonsh entry point, accepts parsed arguments.""" - builtins.__xonsh__.shell = None + XSH.shell = None @contextlib.contextmanager @@ -523,7 +522,7 @@ def main_context(argv=None): up the shell. """ args = premain(argv) - yield builtins.__xonsh__.shell + yield XSH.shell postmain(args) @@ -568,13 +567,13 @@ def setup( # setup xonsh ctx and execer if not hasattr(builtins, "__xonsh__"): execer = Execer(xonsh_ctx=ctx) - builtins.__xonsh__ = XonshSession(ctx=ctx, execer=execer) - load_builtins(ctx=ctx, execer=execer) - builtins.__xonsh__.shell = Shell(execer, ctx=ctx, shell_type=shell_type) - builtins.__xonsh__.env.update(env) + XSH.load( + ctx=ctx, execer=execer, shell=Shell(execer, ctx=ctx, shell_type=shell_type) + ) + XSH.env.update(env) install_import_hooks() - builtins.aliases.update(aliases) + XSH.aliases.update(aliases) if xontribs: xontribs_load(xontribs) - tp = builtins.__xonsh__.commands_cache.threadable_predictors + tp = XSH.commands_cache.threadable_predictors tp.update(threadable_predictors) diff --git a/xonsh/platform.py b/xonsh/platform.py index c93728b22..ec60ea0b8 100644 --- a/xonsh/platform.py +++ b/xonsh/platform.py @@ -7,7 +7,6 @@ import sys import ctypes # noqa import signal import pathlib -import builtins import platform import functools import subprocess @@ -203,7 +202,9 @@ def ptk_below_max_supported(): @functools.lru_cache(1) def best_shell_type(): - if builtins.__xonsh__.env.get("TERM", "") == "dumb": + from xonsh.built_ins import XSH + + if XSH.env.get("TERM", "") == "dumb": return "dumb" if has_prompt_toolkit(): return "prompt_toolkit" @@ -357,8 +358,10 @@ def windows_bash_command(): """Determines the command for Bash on windows.""" # Check that bash is on path otherwise try the default directory # used by Git for windows + from xonsh.built_ins import XSH + wbc = "bash" - cmd_cache = builtins.__xonsh__.commands_cache + cmd_cache = XSH.commands_cache bash_on_path = cmd_cache.lazy_locate_binary("bash", ignore_alias=True) if bash_on_path: try: diff --git a/xonsh/procs/pipelines.py b/xonsh/procs/pipelines.py index 351252d21..2b73502de 100644 --- a/xonsh/procs/pipelines.py +++ b/xonsh/procs/pipelines.py @@ -5,7 +5,6 @@ import io import sys import time import signal -import builtins import threading import subprocess @@ -13,6 +12,7 @@ import xonsh.lazyasd as xl import xonsh.tools as xt import xonsh.platform as xp import xonsh.jobs as xj +from xonsh.built_ins import XSH from xonsh.procs.readers import NonBlockingFDReader, ConsoleParallelReader, safe_fdclose @@ -83,7 +83,7 @@ def update_fg_process_group(pipeline_group, background): return False if not xp.ON_POSIX: return False - env = builtins.__xonsh__.env + env = XSH.env if not env.get("XONSH_INTERACTIVE"): return False return xj.give_terminal_to(pipeline_group) @@ -224,7 +224,7 @@ class CommandPipeline: proc = self.proc if proc is None: return - timeout = builtins.__xonsh__.env.get("XONSH_PROC_FREQUENCY") + timeout = XSH.env.get("XONSH_PROC_FREQUENCY") # get the correct stdout stdout = proc.stdout if ( @@ -347,7 +347,7 @@ class CommandPipeline: yields each line. This may optionally accept lines (in bytes) to iterate over, in which case it does not call iterraw(). """ - env = builtins.__xonsh__.env + env = XSH.env enc = env.get("XONSH_ENCODING") err = env.get("XONSH_ENCODING_ERRORS") lines = self.lines @@ -387,7 +387,7 @@ class CommandPipeline: """Streams lines to sys.stderr and the errors attribute.""" if not lines: return - env = builtins.__xonsh__.env + env = XSH.env enc = env.get("XONSH_ENCODING") err = env.get("XONSH_ENCODING_ERRORS") b = b"".join(lines) @@ -411,7 +411,7 @@ class CommandPipeline: # do some munging of the line before we save it to the attr b = b.replace(b"\r\n", b"\n").replace(b"\r", b"\n") b = RE_HIDE_ESCAPE.sub(b"", b) - env = builtins.__xonsh__.env + env = XSH.env s = b.decode( encoding=env.get("XONSH_ENCODING"), errors=env.get("XONSH_ENCODING_ERRORS") ) @@ -426,7 +426,7 @@ class CommandPipeline: if not b: return "" if isinstance(b, bytes): - env = builtins.__xonsh__.env + env = XSH.env s = b.decode( encoding=env.get("XONSH_ENCODING"), errors=env.get("XONSH_ENCODING_ERRORS"), @@ -478,12 +478,12 @@ class CommandPipeline: return if xj.give_terminal_to(pgid): # if gave term succeed self.term_pgid = pgid - if builtins.__xonsh__.shell is not None: + if XSH.shell is not None: # restoring sanity could probably be called whenever we return # control to the shell. But it only seems to matter after a # ^Z event. This *has* to be called after we give the terminal # back to the shell. - builtins.__xonsh__.shell.shell.restore_tty_sanity() + XSH.shell.shell.restore_tty_sanity() def resume(self, job, tee_output=True): self.ended = False @@ -580,7 +580,7 @@ class CommandPipeline: def _apply_to_history(self): """Applies the results to the current history object.""" - hist = builtins.__xonsh__.history + hist = XSH.history if hist is not None: hist.last_cmd_rtn = 1 if self.proc is None else self.proc.returncode @@ -588,11 +588,7 @@ class CommandPipeline: """Raises a subprocess error, if we are supposed to.""" spec = self.spec rtn = self.returncode - if ( - rtn is not None - and rtn != 0 - and builtins.__xonsh__.env.get("RAISE_SUBPROC_ERROR") - ): + if rtn is not None and rtn != 0 and XSH.env.get("RAISE_SUBPROC_ERROR"): try: raise subprocess.CalledProcessError(rtn, spec.args, output=self.output) finally: @@ -724,7 +720,7 @@ class CommandPipeline: """Prefix to print in front of stderr, as bytes.""" p = self._stderr_prefix if p is None: - env = builtins.__xonsh__.env + env = XSH.env t = env.get("XONSH_STDERR_PREFIX") s = xt.format_std_prepost(t, env=env) p = s.encode( @@ -739,7 +735,7 @@ class CommandPipeline: """Postfix to print after stderr, as bytes.""" p = self._stderr_postfix if p is None: - env = builtins.__xonsh__.env + env = XSH.env t = env.get("XONSH_STDERR_POSTFIX") s = xt.format_std_prepost(t, env=env) p = s.encode( @@ -811,7 +807,7 @@ class PrevProcCloser(threading.Thread): return proc = pipeline.proc prev_end_time = None - timeout = builtins.__xonsh__.env.get("XONSH_PROC_FREQUENCY") + timeout = XSH.env.get("XONSH_PROC_FREQUENCY") sleeptime = min(timeout * 1000, 0.1) while proc.poll() is None: if not check_prev_done: diff --git a/xonsh/procs/posix.py b/xonsh/procs/posix.py index 3d17d380e..c508d2658 100644 --- a/xonsh/procs/posix.py +++ b/xonsh/procs/posix.py @@ -5,7 +5,6 @@ import sys import time import array import signal -import builtins import threading import subprocess @@ -13,6 +12,7 @@ import xonsh.lazyasd as xl import xonsh.platform as xp import xonsh.tools as xt import xonsh.lazyimps as xli +from xonsh.built_ins import XSH from xonsh.procs.readers import ( BufferedFDParallelReader, @@ -56,7 +56,7 @@ class PopenThread(threading.Thread): self.daemon = True self.lock = threading.RLock() - env = builtins.__xonsh__.env + env = XSH.env # stdin setup self.orig_stdin = stdin if stdin is None: diff --git a/xonsh/procs/proxies.py b/xonsh/procs/proxies.py index d9a5ff749..a945f535a 100644 --- a/xonsh/procs/proxies.py +++ b/xonsh/procs/proxies.py @@ -12,7 +12,6 @@ import sys import time import signal import inspect -import builtins import functools import threading import subprocess @@ -21,6 +20,7 @@ import collections.abc as cabc import xonsh.tools as xt import xonsh.platform as xp import xonsh.lazyimps as xli +from xonsh.built_ins import XSH from xonsh.procs.readers import safe_fdclose @@ -409,7 +409,7 @@ class ProcProxyThread(threading.Thread): self.stdout = stdout self.stderr = stderr self.close_fds = close_fds - self.env = env or builtins.__xonsh__.env + self.env = env or XSH.env self._interrupted = False if xp.ON_WINDOWS: @@ -463,7 +463,7 @@ class ProcProxyThread(threading.Thread): if last_in_pipeline: capout = spec.captured_stdout # NOQA caperr = spec.captured_stderr # NOQA - env = builtins.__xonsh__.env + env = XSH.env enc = env.get("XONSH_ENCODING") err = env.get("XONSH_ENCODING_ERRORS") if xp.ON_WINDOWS: @@ -500,7 +500,7 @@ class ProcProxyThread(threading.Thread): sp_stderr = sys.stderr # run the function itself try: - alias_stack = builtins.__xonsh__.env.get("__ALIAS_STACK", "") + alias_stack = XSH.env.get("__ALIAS_STACK", "") if self.env.get("__ALIAS_NAME"): alias_stack += ":" + self.env["__ALIAS_NAME"] @@ -508,7 +508,7 @@ class ProcProxyThread(threading.Thread): sp_stderr ), xt.redirect_stdout(STDOUT_DISPATCHER), xt.redirect_stderr( STDERR_DISPATCHER - ), builtins.__xonsh__.env.swap( + ), XSH.env.swap( __ALIAS_STACK=alias_stack ): r = self.f(self.args, sp_stdin, sp_stdout, sp_stderr, spec, spec.stack) @@ -791,7 +791,7 @@ class ProcProxy: """ if self.f is None: return 0 - env = builtins.__xonsh__.env + env = XSH.env enc = env.get("XONSH_ENCODING") err = env.get("XONSH_ENCODING_ERRORS") spec = self._wait_and_getattr("spec") diff --git a/xonsh/procs/readers.py b/xonsh/procs/readers.py index d3a47ce37..6a4144dea 100644 --- a/xonsh/procs/readers.py +++ b/xonsh/procs/readers.py @@ -5,10 +5,10 @@ import sys import time import queue import ctypes -import builtins import threading import xonsh.lazyimps as xli +from xonsh.built_ins import XSH class QueueReader: @@ -382,7 +382,7 @@ class ConsoleParallelReader(QueueReader): timeout : float, optional The queue reading timeout. """ - timeout = timeout or builtins.__xonsh__.env.get("XONSH_PROC_FREQUENCY") + timeout = timeout or XSH.env.get("XONSH_PROC_FREQUENCY") super().__init__(fd, timeout=timeout) self._buffer = buffer # this cannot be public if buffer is None: diff --git a/xonsh/procs/specs.py b/xonsh/procs/specs.py index 49bbec06c..e1dae26f1 100644 --- a/xonsh/procs/specs.py +++ b/xonsh/procs/specs.py @@ -7,10 +7,10 @@ import shlex import signal import inspect import pathlib -import builtins import subprocess import contextlib +from xonsh.built_ins import XSH import xonsh.tools as xt import xonsh.lazyasd as xl import xonsh.platform as xp @@ -101,7 +101,7 @@ def get_script_subproc_command(fname, args): # Windows can execute various filetypes directly # as given in PATHEXT _, ext = os.path.splitext(fname) - if ext.upper() in builtins.__xonsh__.env.get("PATHEXT"): + if ext.upper() in XSH.env.get("PATHEXT"): return [fname] + args # find interpreter with open(fname, "rb") as f: @@ -356,7 +356,7 @@ class SubprocSpec: self.args = list(cmd) self.alias = None self.alias_name = None - self.alias_stack = builtins.__xonsh__.env.get("__ALIAS_STACK", "").split(":") + self.alias_stack = XSH.env.get("__ALIAS_STACK", "").split(":") self.binary_loc = None self.is_proxy = False self.background = False @@ -458,8 +458,8 @@ class SubprocSpec: return p def _run_binary(self, kwargs): + bufsize = 1 try: - bufsize = 1 p = self.cls(self.cmd, bufsize=bufsize, **kwargs) except PermissionError: e = "xonsh: subprocess mode: permission denied: {0}" @@ -472,16 +472,16 @@ class SubprocSpec: ["man", cmd0.rstrip("?")], bufsize=bufsize, **kwargs ) e = "xonsh: subprocess mode: command not found: {0}".format(cmd0) - env = builtins.__xonsh__.env - sug = xt.suggest_commands(cmd0, env, builtins.aliases) + env = XSH.env + sug = xt.suggest_commands(cmd0, env, XSH.aliases) if len(sug.strip()) > 0: - e += "\n" + xt.suggest_commands(cmd0, env, builtins.aliases) + e += "\n" + xt.suggest_commands(cmd0, env, XSH.aliases) raise xt.XonshError(e) return p def prep_env(self, kwargs): """Prepares the environment to use in the subprocess.""" - with builtins.__xonsh__.env.swap(self.env) as env: + with XSH.env.swap(self.env) as env: denv = env.detype() if xp.ON_WINDOWS: # Over write prompt variable as xonsh's $PROMPT does @@ -493,7 +493,7 @@ class SubprocSpec: """Prepares the 'preexec_fn' keyword argument""" if not xp.ON_POSIX: return - if not builtins.__xonsh__.env.get("XONSH_INTERACTIVE"): + if not XSH.env.get("XONSH_INTERACTIVE"): return if pipeline_group is None or xp.ON_WSL: # If there is no pipeline group @@ -530,14 +530,14 @@ class SubprocSpec: return os.path.basename(self.binary_loc) def _pre_run_event_fire(self, name): - events = builtins.events + events = XSH.builtins.events event_name = "on_pre_spec_run_" + name if events.exists(event_name): event = getattr(events, event_name) event.fire(spec=self) def _post_run_event_fire(self, name, proc): - events = builtins.events + events = XSH.builtins.events event_name = "on_post_spec_run_" + name if events.exists(event_name): event = getattr(events, event_name) @@ -602,7 +602,7 @@ class SubprocSpec: if callable(cmd0): alias = cmd0 else: - alias = builtins.aliases.get(cmd0, None) + alias = XSH.aliases.get(cmd0, None) if alias is not None: self.alias_name = cmd0 self.alias = alias @@ -627,12 +627,12 @@ class SubprocSpec: self.alias is None and self.binary_loc is None and len(self.cmd) == 1 - and builtins.__xonsh__.env.get("AUTO_CD") + and XSH.env.get("AUTO_CD") and os.path.isdir(self.cmd[0]) ): return self.cmd.insert(0, "cd") - self.alias = builtins.aliases.get("cd", None) + self.alias = XSH.aliases.get("cd", None) def resolve_executable_commands(self): """Resolve command executables, if applicable.""" @@ -663,7 +663,7 @@ class SubprocSpec: if not callable(alias): return self.is_proxy = True - env = builtins.__xonsh__.env + env = XSH.env thable = env.get("THREAD_SUBPROCS") and getattr( alias, "__xonsh_threadable__", True ) @@ -718,7 +718,7 @@ def _safe_pipe_properties(fd, use_tty=False): def _update_last_spec(last): - env = builtins.__xonsh__.env + env = XSH.env captured = last.captured last.last_in_pipeline = True if not captured: @@ -727,7 +727,7 @@ def _update_last_spec(last): if callable_alias: pass else: - cmds_cache = builtins.__xonsh__.commands_cache + cmds_cache = XSH.commands_cache thable = ( env.get("THREAD_SUBPROCS") and cmds_cache.predict_threadable(last.args) @@ -753,9 +753,9 @@ def _update_last_spec(last): r, w = os.pipe() last.stdout = safe_open(w, "wb") last.captured_stdout = safe_open(r, "rb") - elif builtins.__xonsh__.stdout_uncaptured is not None: + elif XSH.stdout_uncaptured is not None: last.universal_newlines = True - last.stdout = builtins.__xonsh__.stdout_uncaptured + last.stdout = XSH.stdout_uncaptured last.captured_stdout = last.stdout elif xp.ON_WINDOWS and not callable_alias: last.universal_newlines = True @@ -775,8 +775,8 @@ def _update_last_spec(last): r, w = os.pipe() last.stderr = safe_open(w, "w") last.captured_stderr = safe_open(r, "r") - elif builtins.__xonsh__.stderr_uncaptured is not None: - last.stderr = builtins.__xonsh__.stderr_uncaptured + elif XSH.stderr_uncaptured is not None: + last.stderr = XSH.stderr_uncaptured last.captured_stderr = last.stderr elif xp.ON_WINDOWS and not callable_alias: last.universal_newlines = True @@ -832,12 +832,12 @@ def cmds_to_specs(cmds, captured=False, envs=None): def _should_set_title(captured=False): - env = builtins.__xonsh__.env + env = XSH.env return ( env.get("XONSH_INTERACTIVE") and not env.get("XONSH_STORE_STDOUT") and captured not in STDOUT_CAPTURE_KINDS - and builtins.__xonsh__.shell is not None + and XSH.shell is not None ) @@ -854,7 +854,7 @@ def run_subproc(cmds, captured=False, envs=None): Lastly, the captured argument affects only the last real command. """ - if builtins.__xonsh__.env.get("XONSH_TRACE_SUBPROC"): + if XSH.env.get("XONSH_TRACE_SUBPROC"): print(f"TRACE SUBPROC: {cmds}, captured={captured}", file=sys.stderr) specs = cmds_to_specs(cmds, captured=captured, envs=envs) @@ -878,7 +878,7 @@ def run_subproc(cmds, captured=False, envs=None): ) if _should_set_title(captured=captured): # set title here to get currently executing command - pause_call_resume(proc, builtins.__xonsh__.shell.settitle) + pause_call_resume(proc, XSH.shell.settitle) else: # for some reason, some programs are in a stopped state when the flow # reaches this point, hence a SIGCONT should be sent to `proc` to make diff --git a/xonsh/prompt/base.py b/xonsh/prompt/base.py index f16464f89..87f66eecf 100644 --- a/xonsh/prompt/base.py +++ b/xonsh/prompt/base.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- """Base prompt, provides PROMPT_FIELDS and prompt related functions""" -import builtins import itertools import os import re @@ -13,6 +12,7 @@ import xonsh.lazyasd as xl import xonsh.tools as xt import xonsh.platform as xp +from xonsh.built_ins import XSH from xonsh.prompt.cwd import ( _collapsed_pwd, _replace_home_cwd, @@ -43,7 +43,7 @@ class ParsedTokens(tp.NamedTuple): def process(self) -> str: """Wrapper that gets formatter-function from environment and returns final prompt.""" - processor = builtins.__xonsh__.env.get( # type: ignore + processor = XSH.env.get( # type: ignore "PROMPT_TOKENS_FORMATTER", prompt_tokens_formatter_default ) return processor(self) @@ -93,7 +93,7 @@ class PromptFormatter: self.cache.clear() if fields is None: - self.fields = builtins.__xonsh__.env.get("PROMPT_FIELDS", PROMPT_FIELDS) # type: ignore + self.fields = XSH.env.get("PROMPT_FIELDS", PROMPT_FIELDS) # type: ignore else: self.fields = fields try: @@ -124,7 +124,7 @@ class PromptFormatter: if field is None: return elif field.startswith("$"): - val = builtins.__xonsh__.env[field[1:]] + val = XSH.env[field[1:]] return _format_value(val, spec, conv) elif field in self.fields: val = self._get_field_value(field, spec=spec, conv=conv, **kwargs) @@ -226,7 +226,7 @@ def multiline_prompt(curr=""): # tail is the trailing whitespace tail = line if headlen == 0 else line.rsplit(head[-1], 1)[1] # now to construct the actual string - dots = builtins.__xonsh__.env.get("MULTILINE_PROMPT") + dots = XSH.env.get("MULTILINE_PROMPT") dots = dots() if callable(dots) else dots if dots is None or len(dots) == 0: return "" @@ -272,7 +272,7 @@ def is_template_string(template, PROMPT_FIELDS=None): return False included_names.discard(None) if PROMPT_FIELDS is None: - fmtter = builtins.__xonsh__.env.get("PROMPT_FIELDS", PROMPT_FIELDS) + fmtter = XSH.env.get("PROMPT_FIELDS", PROMPT_FIELDS) else: fmtter = PROMPT_FIELDS known_names = set(fmtter.keys()) diff --git a/xonsh/prompt/cwd.py b/xonsh/prompt/cwd.py index 56635a372..032b0e975 100644 --- a/xonsh/prompt/cwd.py +++ b/xonsh/prompt/cwd.py @@ -3,33 +3,31 @@ import os import shutil -import builtins import xonsh.tools as xt import xonsh.platform as xp +from xonsh.built_ins import XSH def _replace_home(x): if xp.ON_WINDOWS: - home = ( - builtins.__xonsh__.env["HOMEDRIVE"] + builtins.__xonsh__.env["HOMEPATH"][0] - ) + home = XSH.env["HOMEDRIVE"] + XSH.env["HOMEPATH"][0] if x.startswith(home): x = x.replace(home, "~", 1) - if builtins.__xonsh__.env.get("FORCE_POSIX_PATHS"): + if XSH.env.get("FORCE_POSIX_PATHS"): x = x.replace(os.sep, os.altsep) return x else: - home = builtins.__xonsh__.env["HOME"] + home = XSH.env["HOME"] if x.startswith(home): x = x.replace(home, "~", 1) return x def _replace_home_cwd(): - return _replace_home(builtins.__xonsh__.env["PWD"]) + return _replace_home(XSH.env["PWD"]) def _collapsed_pwd(): @@ -50,8 +48,8 @@ def _dynamically_collapsed_pwd(): environment variable DYNAMIC_CWD_WIDTH. """ original_path = _replace_home_cwd() - target_width, units = builtins.__xonsh__.env["DYNAMIC_CWD_WIDTH"] - elision_char = builtins.__xonsh__.env["DYNAMIC_CWD_ELISION_CHAR"] + target_width, units = XSH.env["DYNAMIC_CWD_WIDTH"] + elision_char = XSH.env["DYNAMIC_CWD_ELISION_CHAR"] if target_width == float("inf"): return original_path if units == "%": diff --git a/xonsh/prompt/env.py b/xonsh/prompt/env.py index 8f1a5593a..17f866eed 100644 --- a/xonsh/prompt/env.py +++ b/xonsh/prompt/env.py @@ -2,8 +2,8 @@ """Prompt formatter for virtualenv and others""" import os -import builtins +from xonsh.built_ins import XSH import xonsh.platform as xp @@ -11,9 +11,9 @@ def find_env_name(): """Finds the current environment name from $VIRTUAL_ENV or $CONDA_DEFAULT_ENV if that is set. """ - env_path = builtins.__xonsh__.env.get("VIRTUAL_ENV", "") + env_path = XSH.env.get("VIRTUAL_ENV", "") if len(env_path) == 0 and xp.ON_ANACONDA: - env_path = builtins.__xonsh__.env.get("CONDA_DEFAULT_ENV", "") + env_path = XSH.env.get("CONDA_DEFAULT_ENV", "") env_name = os.path.basename(env_path) return env_name @@ -23,15 +23,15 @@ def env_name(): ``{env_prefix}`` and ``{env_postfix}`` fields. """ env_name = find_env_name() - if builtins.__xonsh__.env.get("VIRTUAL_ENV_DISABLE_PROMPT") or not env_name: + if XSH.env.get("VIRTUAL_ENV_DISABLE_PROMPT") or not env_name: # env name prompt printing disabled, or no environment; just return return - venv_prompt = builtins.__xonsh__.env.get("VIRTUAL_ENV_PROMPT") + venv_prompt = XSH.env.get("VIRTUAL_ENV_PROMPT") if venv_prompt is not None: return venv_prompt else: - pf = builtins.__xonsh__.shell.prompt_formatter + pf = XSH.shell.prompt_formatter pre = pf._get_field_value("env_prefix") post = pf._get_field_value("env_postfix") return pre + env_name + post @@ -44,7 +44,7 @@ def vte_new_tab_cwd(): on startup. Note that this does not return a string, it simply prints and flushes the escape sequence to stdout directly. """ - env = builtins.__xonsh__.env + env = XSH.env t = "\033]7;file://{}{}\007" s = t.format(env.get("HOSTNAME"), env.get("PWD")) print(s, end="", flush=True) diff --git a/xonsh/prompt/gitstatus.py b/xonsh/prompt/gitstatus.py index 748ce6a34..b1c34665c 100644 --- a/xonsh/prompt/gitstatus.py +++ b/xonsh/prompt/gitstatus.py @@ -1,13 +1,12 @@ # -*- coding: utf-8 -*- """Informative git status prompt formatter""" -import builtins import collections import os import subprocess import xonsh.lazyasd as xl - +from xonsh.built_ins import XSH GitStatus = collections.namedtuple( "GitStatus", @@ -31,13 +30,13 @@ GitStatus = collections.namedtuple( def _check_output(*args, **kwargs): kwargs.update( dict( - env=builtins.__xonsh__.env.detype(), + env=XSH.env.detype(), stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, universal_newlines=True, ) ) - timeout = builtins.__xonsh__.env["VC_BRANCH_TIMEOUT"] + timeout = XSH.env["VC_BRANCH_TIMEOUT"] # See https://docs.python.org/3/library/subprocess.html#subprocess.Popen.communicate with subprocess.Popen(*args, **kwargs) as proc: try: @@ -86,7 +85,7 @@ def _DEFS(): def _get_def(key): - def_ = builtins.__xonsh__.env.get("XONSH_GITSTATUS_" + key) + def_ = XSH.env.get("XONSH_GITSTATUS_" + key) return def_ if def_ is not None else _DEFS[key] diff --git a/xonsh/prompt/times.py b/xonsh/prompt/times.py index 94a5620a7..eb5af8340 100644 --- a/xonsh/prompt/times.py +++ b/xonsh/prompt/times.py @@ -1,10 +1,11 @@ # -*- coding: utf-8 -*- """date & time related prompt formatter""" import time -import builtins + +from xonsh.built_ins import XSH def _localtime(): - pf = builtins.__xonsh__.env.get("PROMPT_FIELDS", {}) + pf = XSH.env.get("PROMPT_FIELDS", {}) tf = pf.get("time_format", "%H:%M:%S") return time.strftime(tf, time.localtime()) diff --git a/xonsh/prompt/vc.py b/xonsh/prompt/vc.py index 18bd51831..61d513b82 100644 --- a/xonsh/prompt/vc.py +++ b/xonsh/prompt/vc.py @@ -3,15 +3,15 @@ # pylint:disable=no-member, invalid-name import os -import sys -import queue -import builtins -import threading -import subprocess -import re import pathlib +import queue +import re +import subprocess +import sys +import threading import xonsh.tools as xt +from xonsh.built_ins import XSH from xonsh.lazyasd import LazyObject RE_REMOVE_ANSI = LazyObject( @@ -24,7 +24,7 @@ RE_REMOVE_ANSI = LazyObject( def _run_git_cmd(cmd): # create a safe detyped env dictionary and update with the additional git environment variables # when running git status commands we do not want to acquire locks running command like git status - denv = dict(builtins.__xonsh__.env.detype()) + denv = dict(XSH.env.detype()) denv.update({"GIT_OPTIONAL_LOCKS": "0"}) return subprocess.check_output(cmd, env=denv, stderr=subprocess.DEVNULL) @@ -44,7 +44,7 @@ def get_git_branch(): be determined (timeout, not in a git repo, etc.) then this returns None. """ branch = None - timeout = builtins.__xonsh__.env.get("VC_BRANCH_TIMEOUT") + timeout = XSH.env.get("VC_BRANCH_TIMEOUT") q = queue.Queue() t = threading.Thread(target=_get_git_branch, args=(q,)) @@ -60,7 +60,7 @@ def get_git_branch(): def _get_hg_root(q): - _curpwd = builtins.__xonsh__.env["PWD"] + _curpwd = XSH.env["PWD"] while True: if not os.path.isdir(_curpwd): return False @@ -82,7 +82,7 @@ def get_hg_branch(root=None): """Try to get the mercurial branch of the current directory, return None if not in a repo or subprocess.TimeoutExpired if timed out. """ - env = builtins.__xonsh__.env + env = XSH.env timeout = env["VC_BRANCH_TIMEOUT"] q = queue.Queue() t = threading.Thread(target=_get_hg_root, args=(q,)) @@ -125,7 +125,7 @@ _FIRST_BRANCH_TIMEOUT = True def _first_branch_timeout_message(): global _FIRST_BRANCH_TIMEOUT - sbtm = builtins.__xonsh__.env["SUPPRESS_BRANCH_TIMEOUT_MESSAGE"] + sbtm = XSH.env["SUPPRESS_BRANCH_TIMEOUT_MESSAGE"] if not _FIRST_BRANCH_TIMEOUT or sbtm: return _FIRST_BRANCH_TIMEOUT = False @@ -143,7 +143,7 @@ def _first_branch_timeout_message(): def _vc_has(binary): """This allows us to locate binaries after git only if necessary""" - cmds = builtins.__xonsh__.commands_cache + cmds = XSH.commands_cache if cmds.is_empty(): return bool(cmds.locate_binary(binary, ignore_alias=True)) else: @@ -187,7 +187,7 @@ def git_dirty_working_directory(): """Returns whether or not the git directory is dirty. If this could not be determined (timeout, file not found, etc.) then this returns None. """ - env = builtins.__xonsh__.env + env = XSH.env timeout = env.get("VC_BRANCH_TIMEOUT") include_untracked = env.get("VC_GIT_INCLUDE_UNTRACKED") q = queue.Queue() @@ -206,7 +206,7 @@ def hg_dirty_working_directory(): """Computes whether or not the mercurial working directory is dirty or not. If this cannot be determined, None is returned. """ - env = builtins.__xonsh__.env + env = XSH.env cwd = env["PWD"] denv = env.detype() vcbt = env["VC_BRANCH_TIMEOUT"] diff --git a/xonsh/ptk_shell/completer.py b/xonsh/ptk_shell/completer.py index d4ec9c86a..470cdaaba 100644 --- a/xonsh/ptk_shell/completer.py +++ b/xonsh/ptk_shell/completer.py @@ -1,13 +1,13 @@ # -*- coding: utf-8 -*- """Completer implementation to use with prompt_toolkit.""" import os -import builtins from prompt_toolkit.completion import Completer, Completion from prompt_toolkit.auto_suggest import AutoSuggestFromHistory from prompt_toolkit.application.current import get_app from xonsh.completers.tools import RichCompletion +from xonsh.built_ins import XSH class PromptToolkitCompleter(Completer): @@ -27,7 +27,7 @@ class PromptToolkitCompleter(Completer): def get_completions(self, document, complete_event): """Returns a generator for list of completions.""" - env = builtins.__xonsh__.env + env = XSH.env should_complete = complete_event.completion_requested or env.get( "UPDATE_COMPLETIONS_ON_KEYPRESS" ) @@ -38,7 +38,7 @@ class PromptToolkitCompleter(Completer): line = document.current_line endidx = document.cursor_position_col - line_ex = builtins.aliases.expand_alias(line, endidx) + line_ex = XSH.aliases.expand_alias(line, endidx) begidx = line[:endidx].rfind(" ") + 1 if line[:endidx].rfind(" ") >= 0 else 0 prefix = line[begidx:endidx] @@ -135,7 +135,7 @@ class PromptToolkitCompleter(Completer): if window and window.render_info: h = window.render_info.content_height - r = builtins.__xonsh__.env.get("COMPLETIONS_MENU_ROWS") + r = XSH.env.get("COMPLETIONS_MENU_ROWS") size = h + r last_h = render._last_screen.height if render._last_screen else 0 last_h = max(render._min_available_height, last_h) diff --git a/xonsh/ptk_shell/history.py b/xonsh/ptk_shell/history.py index 52ea137f1..965253ec1 100644 --- a/xonsh/ptk_shell/history.py +++ b/xonsh/ptk_shell/history.py @@ -1,9 +1,10 @@ # -*- coding: utf-8 -*- """History object for use with prompt_toolkit.""" -import builtins import prompt_toolkit.history +from xonsh.built_ins import XSH + class PromptToolkitHistory(prompt_toolkit.history.History): """History class that implements the prompt-toolkit history interface @@ -22,7 +23,7 @@ class PromptToolkitHistory(prompt_toolkit.history.History): """Loads synchronous history strings""" if not self.load_prev: return - hist = builtins.__xonsh__.history + hist = XSH.history if hist is None: return for cmd in hist.all_items(newest_first=True): diff --git a/xonsh/ptk_shell/key_bindings.py b/xonsh/ptk_shell/key_bindings.py index a4884bbcc..c295d9c09 100644 --- a/xonsh/ptk_shell/key_bindings.py +++ b/xonsh/ptk_shell/key_bindings.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- """Key bindings for prompt_toolkit xonsh shell.""" -import builtins from prompt_toolkit import search from prompt_toolkit.application.current import get_app @@ -19,6 +18,7 @@ from prompt_toolkit.key_binding.bindings.named_commands import get_by_name from xonsh.aliases import xonsh_exit from xonsh.tools import check_for_partial_string, get_line_continuation +from xonsh.built_ins import XSH from xonsh.shell import transform_command DEDENT_TOKENS = frozenset(["raise", "return", "pass", "break", "continue"]) @@ -40,7 +40,7 @@ def carriage_return(b, cli, *, autoindent=True): at_end_of_line = _is_blank(doc.current_line_after_cursor) current_line_blank = _is_blank(doc.current_line) - env = builtins.__xonsh__.env + env = XSH.env indent = env.get("INDENT") if autoindent else "" partial_string_info = check_for_partial_string(doc.text) @@ -86,9 +86,7 @@ def can_compile(src): src = transform_command(src, show_diff=False) src = src.lstrip() try: - builtins.__xonsh__.execer.compile( - src, mode="single", glbs=None, locs=builtins.__xonsh__.ctx - ) + XSH.execer.compile(src, mode="single", glbs=None, locs=XSH.ctx) rtn = True except SyntaxError: rtn = False @@ -112,7 +110,7 @@ def tab_insert_indent(): @Condition def tab_menu_complete(): """Checks whether completion mode is `menu-complete`""" - return builtins.__xonsh__.env.get("COMPLETION_MODE") == "menu-complete" + return XSH.env.get("COMPLETION_MODE") == "menu-complete" @Condition @@ -144,8 +142,7 @@ def end_of_line(): def should_confirm_completion(): """Check if completion needs confirmation""" return ( - builtins.__xonsh__.env.get("COMPLETIONS_CONFIRM") - and get_app().current_buffer.complete_state + XSH.env.get("COMPLETIONS_CONFIRM") and get_app().current_buffer.complete_state ) @@ -155,7 +152,7 @@ def ctrl_d_condition(): """Ctrl-D binding is only active when the default buffer is selected and empty. """ - if builtins.__xonsh__.env.get("IGNOREEOF"): + if XSH.env.get("IGNOREEOF"): return False else: app = get_app() @@ -167,7 +164,7 @@ def ctrl_d_condition(): @Condition def autopair_condition(): """Check if XONSH_AUTOPAIR is set""" - return builtins.__xonsh__.env.get("XONSH_AUTOPAIR", False) + return XSH.env.get("XONSH_AUTOPAIR", False) @Condition @@ -222,7 +219,7 @@ def load_xonsh_bindings() -> KeyBindingsBase: If there are only whitespaces before current cursor position insert indent instead of autocompleting. """ - env = builtins.__xonsh__.env + env = XSH.env event.cli.current_buffer.insert_text(env.get("INDENT")) @handle(Keys.Tab, filter=~tab_insert_indent & tab_menu_complete) @@ -246,7 +243,7 @@ def load_xonsh_bindings() -> KeyBindingsBase: if b.complete_state: b.complete_previous() else: - env = builtins.__xonsh__.env + env = XSH.env event.cli.current_buffer.insert_text(env.get("INDENT")) def generate_parens_handlers(left, right): diff --git a/xonsh/ptk_shell/shell.py b/xonsh/ptk_shell/shell.py index 69f887f84..df5a689e6 100644 --- a/xonsh/ptk_shell/shell.py +++ b/xonsh/ptk_shell/shell.py @@ -3,10 +3,10 @@ import os import re import sys -import builtins from functools import wraps from types import MethodType +from xonsh.built_ins import XSH from xonsh.events import events from xonsh.base_shell import BaseShell from xonsh.ptk_shell.formatter import PTKPromptFormatter @@ -198,7 +198,7 @@ class PromptToolkitShell(BaseShell): self.history = ThreadedHistory(PromptToolkitHistory()) ptk_args = {"history": self.history} - if not builtins.__xonsh__.env.get("XONSH_COPY_ON_DELETE", False): + if not XSH.env.get("XONSH_COPY_ON_DELETE", False): disable_copy_on_deletion() if HAVE_SYS_CLIPBOARD: ptk_args["clipboard"] = PyperclipClipboard() @@ -232,7 +232,7 @@ class PromptToolkitShell(BaseShell): history. """ events.on_pre_prompt_format.fire() - env = builtins.__xonsh__.env + env = XSH.env mouse_support = env.get("MOUSE_SUPPORT") auto_suggest = auto_suggest if env.get("AUTO_SUGGEST") else None refresh_interval = env.get("PROMPT_REFRESH_INTERVAL") @@ -379,7 +379,7 @@ class PromptToolkitShell(BaseShell): print(intro) auto_suggest = AutoSuggestFromHistory() self.push = self._push - while not builtins.__xonsh__.exit: + while not XSH.exit: try: line = self.singleline(auto_suggest=auto_suggest) if not line: @@ -391,13 +391,13 @@ class PromptToolkitShell(BaseShell): except (KeyboardInterrupt, SystemExit): self.reset_buffer() except EOFError: - if builtins.__xonsh__.env.get("IGNOREEOF"): + if XSH.env.get("IGNOREEOF"): print('Use "exit" to leave the shell.', file=sys.stderr) else: break def _get_prompt_tokens(self, env_name: str, prompt_name: str, **kwargs): - env = builtins.__xonsh__.env # type:ignore + env = XSH.env # type:ignore p = env.get(env_name) if not p and "default" in kwargs: @@ -449,7 +449,7 @@ class PromptToolkitShell(BaseShell): @property def bottom_toolbar_tokens(self): """Returns self._bottom_toolbar_tokens if it would yield a result""" - if builtins.__xonsh__.env.get("BOTTOM_TOOLBAR"): + if XSH.env.get("BOTTOM_TOOLBAR"): return self._bottom_toolbar_tokens def continuation_tokens(self, width, line_number, is_soft_wrap=False): @@ -457,7 +457,7 @@ class PromptToolkitShell(BaseShell): if is_soft_wrap: return "" width = width - 1 - dots = builtins.__xonsh__.env.get("MULTILINE_PROMPT") + dots = XSH.env.get("MULTILINE_PROMPT") dots = dots() if callable(dots) else dots if not dots: return "" @@ -490,7 +490,7 @@ class PromptToolkitShell(BaseShell): """ tokens = partial_color_tokenize(string) if force_string and HAS_PYGMENTS: - env = builtins.__xonsh__.env + env = XSH.env style_overrides_env = env.get("XONSH_STYLE_OVERRIDES", {}) self.styler.style_name = env.get("XONSH_COLOR_STYLE") self.styler.override(style_overrides_env) @@ -512,7 +512,7 @@ class PromptToolkitShell(BaseShell): # assume this is a list of (Token, str) tuples and just print tokens = string tokens = PygmentsTokens(tokens) - env = builtins.__xonsh__.env + env = XSH.env style_overrides_env = env.get("XONSH_STYLE_OVERRIDES", {}) if HAS_PYGMENTS: self.styler.style_name = env.get("XONSH_COLOR_STYLE") @@ -541,7 +541,7 @@ class PromptToolkitShell(BaseShell): """Returns the current color map.""" if not HAS_PYGMENTS: return DEFAULT_STYLE_DICT - env = builtins.__xonsh__.env + env = XSH.env self.styler.style_name = env.get("XONSH_COLOR_STYLE") return self.styler.styles @@ -570,7 +570,7 @@ class PromptToolkitShell(BaseShell): # sys.stdout.write('\033[9999999C\n') if not ON_POSIX: return - stty, _ = builtins.__xonsh__.commands_cache.lazyget("stty", (None, None)) + stty, _ = XSH.commands_cache.lazyget("stty", (None, None)) if stty is None: return os.system(stty + " sane") diff --git a/xonsh/ptk_shell/updator.py b/xonsh/ptk_shell/updator.py index 876d66dba..ec8470bde 100644 --- a/xonsh/ptk_shell/updator.py +++ b/xonsh/ptk_shell/updator.py @@ -1,6 +1,5 @@ """Has classes that help updating Prompt sections using Threads.""" -import builtins import concurrent.futures import threading import typing as tp @@ -8,6 +7,7 @@ import typing as tp from prompt_toolkit import PromptSession from prompt_toolkit.formatted_text import PygmentsTokens +from xonsh.built_ins import XSH from xonsh.prompt.base import ParsedTokens from xonsh.style_tools import partial_color_tokenize, style_as_faded @@ -17,7 +17,7 @@ class Executor: def __init__(self): self.thread_pool = concurrent.futures.ThreadPoolExecutor( - max_workers=builtins.__xonsh__.env["ASYNC_PROMPT_THREAD_WORKERS"] + max_workers=XSH.env["ASYNC_PROMPT_THREAD_WORKERS"] ) # the attribute, .cache is cleared between calls. @@ -129,9 +129,7 @@ class AsyncPrompt: setattr(self.session, self.name, formatted_tokens) self.session.app.invalidate() - self.timer = threading.Timer( - builtins.__xonsh__.env["ASYNC_INVALIDATE_INTERVAL"], _invalidate - ) + self.timer = threading.Timer(XSH.env["ASYNC_INVALIDATE_INTERVAL"], _invalidate) self.timer.start() def stop(self): diff --git a/xonsh/pyghooks.py b/xonsh/pyghooks.py index ab2c395e3..6814dc645 100644 --- a/xonsh/pyghooks.py +++ b/xonsh/pyghooks.py @@ -10,6 +10,7 @@ from collections.abc import MutableMapping from keyword import iskeyword import typing as tp +from xonsh.built_ins import XSH from xonsh.lazyimps import os_listxattr from pygments.lexer import inherit, bygroups, include @@ -242,7 +243,7 @@ def color_token_by_name(xc: tuple, styles=None) -> _TokenType: """Returns (color) token corresponding to Xonsh color tuple, side effect: defines token is defined in styles""" if not styles: try: - styles = builtins.__xonsh__.shell.shell.styler.styles # type:ignore + styles = XSH.shell.shell.styler.styles # type:ignore except AttributeError: return Color @@ -264,7 +265,7 @@ def partial_color_tokenize(template): of tuples mapping the token to the string which has that color. These sub-strings maybe templates themselves. """ - if builtins.__xonsh__.shell is not None: + if XSH.shell is not None: styles = __xonsh__.shell.shell.styler.styles else: styles = None @@ -390,7 +391,7 @@ class XonshStyle(Style): file=sys.stderr, ) value = "default" - builtins.__xonsh__.env["XONSH_COLOR_STYLE"] = value + XSH.env["XONSH_COLOR_STYLE"] = value cmap = STYLES[value] if value == "default": self._smap = XONSH_BASE_STYLE.copy() @@ -411,13 +412,11 @@ class XonshStyle(Style): ) self._style_name = value - for file_type, xonsh_color in builtins.__xonsh__.env.get( - "LS_COLORS", {} - ).items(): + for file_type, xonsh_color in XSH.env.get("LS_COLORS", {}).items(): color_token = color_token_by_name(xonsh_color, self.styles) file_color_tokens[file_type] = color_token - if ON_WINDOWS and "prompt_toolkit" in builtins.__xonsh__.shell.shell_type: + if ON_WINDOWS and "prompt_toolkit" in XSH.shell.shell_type: self.enhance_colors_for_cmd_exe() @style_name.deleter @@ -436,7 +435,7 @@ class XonshStyle(Style): When using the default style all blue and dark red colors are changed to CYAN and intense red. """ - env = builtins.__xonsh__.env + env = XSH.env # Ensure we are not using the new Windows Terminal, ConEmu or Visual Stuio Code if "WT_SESSION" in env or "CONEMUANSI" in env or "VSCODE_PID" in env: return @@ -1522,7 +1521,7 @@ def color_file(file_path: str, path_stat: os.stat_result) -> tp.Tuple[_TokenType This is arguably a bug. """ - lsc = builtins.__xonsh__.env["LS_COLORS"] # type:ignore + lsc = XSH.env["LS_COLORS"] # type:ignore color_key = "fi" # if symlink, get info on (final) target @@ -1600,13 +1599,13 @@ def _command_is_valid(cmd): cmd_abspath = os.path.abspath(os.path.expanduser(cmd)) except (FileNotFoundError, OSError): return False - return (cmd in builtins.__xonsh__.commands_cache and not iskeyword(cmd)) or ( + return (cmd in XSH.commands_cache and not iskeyword(cmd)) or ( os.path.isfile(cmd_abspath) and os.access(cmd_abspath, os.X_OK) ) def _command_is_autocd(cmd): - if not builtins.__xonsh__.env.get("AUTO_CD", False): + if not XSH.env.get("AUTO_CD", False): return False try: cmd_abspath = os.path.abspath(os.path.expanduser(cmd)) @@ -1654,14 +1653,14 @@ class XonshLexer(Python3Lexer): from argparse import Namespace setattr(builtins, "__xonsh__", Namespace()) - if not hasattr(builtins.__xonsh__, "env"): - setattr(builtins.__xonsh__, "env", {}) + if not hasattr(XSH, "env"): + setattr(XSH, "env", {}) if ON_WINDOWS: pathext = os_environ.get("PATHEXT", [".EXE", ".BAT", ".CMD"]) - builtins.__xonsh__.env["PATHEXT"] = pathext.split(os.pathsep) - if not hasattr(builtins.__xonsh__, "commands_cache"): - setattr(builtins.__xonsh__, "commands_cache", CommandsCache()) - _ = builtins.__xonsh__.commands_cache.all_commands # NOQA + XSH.env["PATHEXT"] = pathext.split(os.pathsep) + if not hasattr(XSH, "commands_cache"): + setattr(XSH, "commands_cache", CommandsCache()) + _ = XSH.commands_cache.all_commands # NOQA super().__init__(*args, **kwargs) tokens = { diff --git a/xonsh/readline_shell.py b/xonsh/readline_shell.py index 74ca118d9..874e3aa49 100644 --- a/xonsh/readline_shell.py +++ b/xonsh/readline_shell.py @@ -15,12 +15,12 @@ import sys import cmd import select import shutil -import builtins import importlib import threading import collections import xonsh.completers.tools as xct +from xonsh.built_ins import XSH from xonsh.lazyasd import LazyObject, lazyobject from xonsh.base_shell import BaseShell from xonsh.ansi_colors import ( @@ -103,7 +103,7 @@ def setup_readline(): except Exception: pass RL_CAN_RESIZE = hasattr(lib, "rl_reset_screen_size") - env = builtins.__xonsh__.env + env = XSH.env # reads in history readline.set_history_length(-1) ReadlineHistoryAdder() @@ -170,7 +170,7 @@ def teardown_readline(): def _rebind_case_sensitive_completions(): # handle case sensitive, see Github issue #1342 for details global _RL_PREV_CASE_SENSITIVE_COMPLETIONS - env = builtins.__xonsh__.env + env = XSH.env case_sensitive = env.get("CASE_SENSITIVE_COMPLETIONS") if case_sensitive is _RL_PREV_CASE_SENSITIVE_COMPLETIONS: return @@ -221,7 +221,7 @@ def rl_completion_query_items(val=None): if RL_COMPLETION_QUERY_ITEMS is None: return if val is None: - val = builtins.__xonsh__.env.get("COMPLETION_QUERY_LIMIT") + val = XSH.env.get("COMPLETION_QUERY_LIMIT") RL_COMPLETION_QUERY_ITEMS.value = val @@ -240,7 +240,7 @@ def rl_variable_value(variable): RL_VARIABLE_VALUE = RL_LIB.rl_variable_value RL_VARIABLE_VALUE.restype = ctypes.c_char_p - env = builtins.__xonsh__.env + env = XSH.env enc, errors = env.get("XONSH_ENCODING"), env.get("XONSH_ENCODING_ERRORS") if isinstance(variable, str): variable = variable.encode(encoding=enc, errors=errors) @@ -386,7 +386,7 @@ class ReadlineShell(BaseShell, cmd.Cmd): """ if os.path.commonprefix([c[loc:] for c in completions]): return 1 - elif len(completions) <= builtins.__xonsh__.env.get("COMPLETION_QUERY_LIMIT"): + elif len(completions) <= XSH.env.get("COMPLETION_QUERY_LIMIT"): return 2 msg = "\nDisplay all {} possibilities? ".format(len(completions)) msg += "({GREEN}y{RESET} or {RED}n{RESET})" @@ -493,11 +493,11 @@ class ReadlineShell(BaseShell, cmd.Cmd): self._current_indent = "" elif line.rstrip()[-1] == ":": ind = line[: len(line) - len(line.lstrip())] - ind += builtins.__xonsh__.env.get("INDENT") + ind += XSH.env.get("INDENT") readline.set_pre_input_hook(_insert_text_func(ind, readline)) self._current_indent = ind elif line.split(maxsplit=1)[0] in DEDENT_TOKENS: - env = builtins.__xonsh__.env + env = XSH.env ind = self._current_indent[: -len(env.get("INDENT"))] readline.set_pre_input_hook(_insert_text_func(ind, readline)) self._current_indent = ind @@ -551,7 +551,7 @@ class ReadlineShell(BaseShell, cmd.Cmd): try: line = self.singleline() except EOFError: - if builtins.__xonsh__.env.get("IGNOREEOF"): + if XSH.env.get("IGNOREEOF"): self.stdout.write('Use "exit" to leave the shell.' "\n") line = "" else: @@ -589,7 +589,7 @@ class ReadlineShell(BaseShell, cmd.Cmd): pass def cmdloop(self, intro=None): - while not builtins.__xonsh__.exit: + while not XSH.exit: try: self._cmdloop(intro=intro) except (KeyboardInterrupt, SystemExit): @@ -614,7 +614,7 @@ class ReadlineShell(BaseShell, cmd.Cmd): print_exception() self.mlprompt = " " return self.mlprompt - env = builtins.__xonsh__.env # pylint: disable=no-member + env = XSH.env # pylint: disable=no-member p = env.get("PROMPT") try: p = self.prompt_formatter(p) @@ -631,7 +631,7 @@ class ReadlineShell(BaseShell, cmd.Cmd): codes. """ hide = hide if self._force_hide is None else self._force_hide - style = builtins.__xonsh__.env.get("XONSH_COLOR_STYLE") + style = XSH.env.get("XONSH_COLOR_STYLE") return ansi_partial_color_format(string, hide=hide, style=style) def print_color(self, string, hide=False, **kwargs): @@ -639,7 +639,7 @@ class ReadlineShell(BaseShell, cmd.Cmd): s = self.format_color(string, hide=hide) else: # assume this is a list of (Token, str) tuples and format it - env = builtins.__xonsh__.env + env = XSH.env style_overrides_env = env.get("XONSH_STYLE_OVERRIDES", {}) self.styler.style_name = env.get("XONSH_COLOR_STYLE") self.styler.override(style_overrides_env) @@ -654,7 +654,7 @@ class ReadlineShell(BaseShell, cmd.Cmd): def color_style(self): """Returns the current color map.""" - style = style = builtins.__xonsh__.env.get("XONSH_COLOR_STYLE") + style = XSH.env.get("XONSH_COLOR_STYLE") return ansi_color_style(style=style) def restore_tty_sanity(self): @@ -664,7 +664,7 @@ class ReadlineShell(BaseShell, cmd.Cmd): """ if not ON_POSIX: return - stty, _ = builtins.__xonsh__.commands_cache.lazyget("stty", (None, None)) + stty, _ = XSH.commands_cache.lazyget("stty", (None, None)) if stty is None: return # If available, we should just call the stty utility. This call should @@ -694,7 +694,7 @@ class ReadlineHistoryAdder(threading.Thread): import readline except ImportError: return - hist = builtins.__xonsh__.history + hist = XSH.history if hist is None: return i = 1 diff --git a/xonsh/shell.py b/xonsh/shell.py index 8e3b96d56..05bcc0cb7 100644 --- a/xonsh/shell.py +++ b/xonsh/shell.py @@ -3,7 +3,6 @@ import sys import time import difflib -import builtins import warnings from xonsh.platform import ( @@ -16,7 +15,7 @@ from xonsh.tools import XonshError, print_exception, simple_random_choice from xonsh.events import events from xonsh.history.dummy import DummyHistory import xonsh.history.main as xhm - +from xonsh.built_ins import XSH events.doc( "on_transform_command", @@ -106,7 +105,7 @@ def transform_command(src, show_diff=True): "the recursion limit number of iterations to " "converge." ) - debug_level = builtins.__xonsh__.env.get("XONSH_DEBUG") + debug_level = XSH.env.get("XONSH_DEBUG") if show_diff and debug_level > 1 and src != raw: sys.stderr.writelines( difflib.unified_diff( @@ -200,11 +199,11 @@ class Shell(object): """ self.execer = execer self.ctx = {} if ctx is None else ctx - env = builtins.__xonsh__.env + env = XSH.env # build history backend before creating shell if env.get("XONSH_INTERACTIVE"): - builtins.__xonsh__.history = hist = xhm.construct_history( + XSH.history = hist = xhm.construct_history( env=env.detype(), ts=[time.time(), None], locked=True, @@ -212,7 +211,7 @@ class Shell(object): ) env["XONSH_HISTORY_FILE"] = hist.filename else: - builtins.__xonsh__.history = hist = DummyHistory() + XSH.history = hist = DummyHistory() env["XONSH_HISTORY_FILE"] = None shell_type = self.choose_shell_type(shell_type, env) diff --git a/xonsh/style_tools.py b/xonsh/style_tools.py index 27b65e41c..328e85b57 100644 --- a/xonsh/style_tools.py +++ b/xonsh/style_tools.py @@ -1,5 +1,4 @@ """Xonsh color styling tools that simulate pygments, when it is unavailable.""" -import builtins from collections import defaultdict from xonsh.platform import HAS_PYGMENTS @@ -64,9 +63,11 @@ def partial_color_tokenize(template): of tuples mapping the token to the string which has that color. These sub-strings maybe templates themselves. """ - if HAS_PYGMENTS and builtins.__xonsh__.shell is not None: - styles = __xonsh__.shell.shell.styler.styles - elif builtins.__xonsh__.shell is not None: + from xonsh.built_ins import XSH + + if HAS_PYGMENTS and XSH.shell is not None: + styles = XSH.shell.shell.styler.styles + elif XSH.shell is not None: styles = DEFAULT_STYLE_DICT else: styles = None diff --git a/xonsh/timings.py b/xonsh/timings.py index af196c7fd..fa95576fc 100644 --- a/xonsh/timings.py +++ b/xonsh/timings.py @@ -13,9 +13,9 @@ import sys import math import time import timeit -import builtins import itertools +from xonsh.built_ins import XSH from xonsh.lazyasd import lazyobject, lazybool from xonsh.events import events from xonsh.platform import ON_WINDOWS @@ -188,7 +188,7 @@ def timeit_alias(args, stdin=None): repeat = 3 precision = 3 # setup - ctx = builtins.__xonsh__.ctx + ctx = XSH.ctx timer = Timer(timer=clock) stmt = " ".join(args) innerstr = INNER_TEMPLATE.format(stmt=stmt) @@ -196,13 +196,13 @@ def timeit_alias(args, stdin=None): # Minimum time above which compilation time will be reported tc_min = 0.1 t0 = clock() - innercode = builtins.compilex( + innercode = XSH.builtins.compilex( innerstr, filename="", mode="exec", glbs=ctx ) tc = clock() - t0 # get inner func ns = {} - builtins.execx(innercode, glbs=ctx, locs=ns, mode="exec") + XSH.builtins.execx(innercode, glbs=ctx, locs=ns, mode="exec") timer.inner = ns["inner"] # Check if there is a huge difference between the best and worst timings. worst_tuning = 0 diff --git a/xonsh/tools.py b/xonsh/tools.py index 4f680a69f..edab0bc64 100644 --- a/xonsh/tools.py +++ b/xonsh/tools.py @@ -17,7 +17,6 @@ Implementations: * indent() """ -import builtins import collections import collections.abc as cabc import contextlib @@ -63,6 +62,13 @@ def is_superuser(): return rtn +@lazyobject +def xsh(): + from xonsh.built_ins import XSH + + return XSH + + class XonshError(Exception): pass @@ -99,8 +105,7 @@ class XonshCalledProcessError(XonshError, subprocess.CalledProcessError): def expand_path(s, expand_user=True): """Takes a string path and expands ~ to home if expand_user is set and environment vars if EXPAND_ENV_VARS is set.""" - session = getattr(builtins, "__xonsh__", None) - env = os_environ if session is None else getattr(session, "env", os_environ) + env = xsh.env or os_environ if env.get("EXPAND_ENV_VARS", False): s = expandvars(s) if expand_user: @@ -121,8 +126,7 @@ def _expandpath(path): """Performs environment variable / user expansion on a given path if EXPAND_ENV_VARS is set. """ - session = getattr(builtins, "__xonsh__", None) - env = os_environ if session is None else getattr(session, "env", os_environ) + env = xsh.env or os_environ expand_user = env.get("EXPAND_ENV_VARS", False) return expand_path(path, expand_user=expand_user) @@ -139,8 +143,7 @@ def decode_bytes(b): """Tries to decode the bytes using XONSH_ENCODING if available, otherwise using sys.getdefaultencoding(). """ - session = getattr(builtins, "__xonsh__", None) - env = os_environ if session is None else getattr(session, "env", os_environ) + env = xsh.env or os_environ enc = env.get("XONSH_ENCODING") or DEFAULT_ENCODING err = env.get("XONSH_ENCODING_ERRORS") or "strict" return b.decode(encoding=enc, errors=err) @@ -332,7 +335,7 @@ def balanced_parens(line, mincol=0, maxcol=None, lexer=None): """Determines if parentheses are balanced in an expression.""" line = line[mincol:maxcol] if lexer is None: - lexer = builtins.__xonsh__.execer.parser.lexer + lexer = xsh.execer.parser.lexer if "(" not in line and ")" not in line: return True cnt = 0 @@ -355,7 +358,7 @@ def find_next_break(line, mincol=0, lexer=None): if mincol >= 1: line = line[mincol:] if lexer is None: - lexer = builtins.__xonsh__.execer.parser.lexer + lexer = xsh.execer.parser.lexer if RE_END_TOKS.search(line) is None: return None maxcol = None @@ -393,7 +396,7 @@ def subproc_toks( normal parentheses. Greedy is False by default. """ if lexer is None: - lexer = builtins.__xonsh__.execer.parser.lexer + lexer = xsh.execer.parser.lexer if maxcol is None: maxcol = len(line) + 1 lexer.reset() @@ -528,11 +531,7 @@ def get_line_continuation(): mode on Windows the backslash must be preceded by a space. This is because paths on Windows may end in a backslash. """ - if ( - ON_WINDOWS - and hasattr(builtins.__xonsh__, "env") - and builtins.__xonsh__.env.get("XONSH_INTERACTIVE", False) - ): + if ON_WINDOWS and hasattr(xsh, "env") and xsh.env.get("XONSH_INTERACTIVE", False): return " \\" else: return "\\" @@ -703,7 +702,7 @@ def get_sep(): """Returns the appropriate filepath separator char depending on OS and xonsh options set """ - if ON_WINDOWS and builtins.__xonsh__.env.get("FORCE_POSIX_PATHS"): + if ON_WINDOWS and xsh.env.get("FORCE_POSIX_PATHS"): return os.altsep else: return os.sep @@ -789,7 +788,7 @@ def _executables_in_posix(path): def _executables_in_windows(path): if not os.path.isdir(path): return - extensions = builtins.__xonsh__.env["PATHEXT"] + extensions = xsh.env["PATHEXT"] try: for x in os.scandir(path): try: @@ -829,7 +828,7 @@ def debian_command_not_found(cmd): if not ON_LINUX: return "" - cnf = builtins.__xonsh__.commands_cache.lazyget( + cnf = xsh.commands_cache.lazyget( "command-not-found", ("/usr/lib/command-not-found",) )[0] @@ -885,12 +884,12 @@ def suggest_commands(cmd, env, aliases): cmd = cmd.lower() suggested = {} - for alias in builtins.aliases: + for alias in xsh.aliases: if alias not in suggested: if levenshtein(alias.lower(), cmd, thresh) < thresh: suggested[alias] = "Alias" - for _cmd in builtins.__xonsh__.commands_cache.all_commands: + for _cmd in xsh.commands_cache.all_commands: if _cmd not in suggested: if levenshtein(_cmd.lower(), cmd, thresh) < thresh: suggested[_cmd] = "Command ({0})".format(_cmd) @@ -920,7 +919,7 @@ def suggest_commands(cmd, env, aliases): def _get_manual_env_var(name, default=None): """Returns if the given variable is manually set as well as it's value.""" - env = getattr(builtins.__xonsh__, "env", None) + env = getattr(xsh, "env", None) if env is None: env = os_environ manually_set = name in env @@ -1865,13 +1864,13 @@ def format_color(string, **kwargs): shell instances method of the same name. The results of this function should be directly usable by print_color(). """ - if hasattr(builtins.__xonsh__.shell, "shell"): - return builtins.__xonsh__.shell.shell.format_color(string, **kwargs) + if hasattr(xsh.shell, "shell"): + return xsh.shell.shell.format_color(string, **kwargs) else: # fallback for ANSI if shell is not yet initialized from xonsh.ansi_colors import ansi_partial_color_format - style = builtins.__xonsh__.env.get("XONSH_COLOR_STYLE") + style = xsh.env.get("XONSH_COLOR_STYLE") return ansi_partial_color_format(string, style=style) @@ -1880,8 +1879,8 @@ def print_color(string, **kwargs): method of the same name. Colors will be formatted if they have not already been. """ - if hasattr(builtins.__xonsh__.shell, "shell"): - builtins.__xonsh__.shell.shell.print_color(string, **kwargs) + if hasattr(xsh.shell, "shell"): + xsh.shell.shell.print_color(string, **kwargs) else: # fallback for ANSI if shell is not yet initialized print(format_color(string, **kwargs)) @@ -1889,12 +1888,12 @@ def print_color(string, **kwargs): def color_style_names(): """Returns an iterable of all available style names.""" - return builtins.__xonsh__.shell.shell.color_style_names() + return xsh.shell.shell.color_style_names() def color_style(): """Returns the current color map.""" - return builtins.__xonsh__.shell.shell.color_style() + return xsh.shell.shell.color_style() def register_custom_style( @@ -1939,7 +1938,7 @@ def _token_attr_from_stylemap(stylemap): """yields tokens attr, and index from a stylemap""" import prompt_toolkit as ptk - if builtins.__xonsh__.shell.shell_type == "prompt_toolkit1": + if xsh.shell.shell_type == "prompt_toolkit1": style = ptk.styles.style_from_dict(stylemap) for token in stylemap: yield token, style.token_to_attrs[token] @@ -1954,7 +1953,7 @@ def _token_attr_from_stylemap(stylemap): def _get_color_lookup_table(): """Returns the prompt_toolkit win32 ColorLookupTable""" - if builtins.__xonsh__.shell.shell_type == "prompt_toolkit1": + if xsh.shell.shell_type == "prompt_toolkit1": from prompt_toolkit.terminal.win32_output import ColorLookupTable else: from prompt_toolkit.output.win32 import ColorLookupTable @@ -2059,8 +2058,8 @@ def hardcode_colors_for_win10(style_map): in conhost.exe """ modified_style = {} - if not builtins.__xonsh__.env["PROMPT_TOOLKIT_COLOR_DEPTH"]: - builtins.__xonsh__.env["PROMPT_TOOLKIT_COLOR_DEPTH"] = "DEPTH_24_BIT" + if not xsh.env["PROMPT_TOOLKIT_COLOR_DEPTH"]: + xsh.env["PROMPT_TOOLKIT_COLOR_DEPTH"] = "DEPTH_24_BIT" # Replace all ansi colors with hardcoded colors to avoid unreadable defaults # in conhost.exe for token, style_str in style_map.items(): @@ -2107,7 +2106,7 @@ def intensify_colors_for_cmd_exe(style_map): 6: "ansibrightyellow", # subst yellow with bright yellow 9: "ansicyan", # subst intense blue with dark cyan (more readable) } - if builtins.__xonsh__.shell.shell_type == "prompt_toolkit1": + if xsh.shell.shell_type == "prompt_toolkit1": replace_colors = ansicolors_to_ptk1_names(replace_colors) for token, idx, _ in _get_color_indexes(style_map): if idx in replace_colors: @@ -2121,11 +2120,11 @@ def intensify_colors_on_win_setter(enable): """ enable = to_bool(enable) if ( - hasattr(builtins.__xonsh__, "shell") - and builtins.__xonsh__.shell is not None - and hasattr(builtins.__xonsh__.shell.shell.styler, "style_name") + hasattr(xsh, "shell") + and xsh.shell is not None + and hasattr(xsh.shell.shell.styler, "style_name") ): - delattr(builtins.__xonsh__.shell.shell.styler, "style_name") + delattr(xsh.shell.shell.styler, "style_name") return enable @@ -2135,9 +2134,9 @@ def format_std_prepost(template, env=None): """ if not template: return "" - env = builtins.__xonsh__.env if env is None else env + env = xsh.env if env is None else env invis = "\001\002" - if builtins.__xonsh__.shell is None: + if xsh.shell is None: # shell hasn't fully started up (probably still in xonshrc) from xonsh.prompt.base import PromptFormatter from xonsh.ansi_colors import ansi_partial_color_format @@ -2148,7 +2147,7 @@ def format_std_prepost(template, env=None): s = ansi_partial_color_format(invis + s + invis, hide=False, style=style) else: # shell has fully started. do the normal thing - shell = builtins.__xonsh__.shell.shell + shell = xsh.shell.shell try: s = shell.prompt_formatter(template) except Exception: @@ -2323,7 +2322,7 @@ def POSIX_ENVVAR_REGEX(): def expandvars(path): """Expand shell variables of the forms $var, ${var} and %var%. Unknown variables are left unchanged.""" - env = builtins.__xonsh__.env + env = xsh.env if isinstance(path, bytes): path = path.decode( encoding=env.get("XONSH_ENCODING"), errors=env.get("XONSH_ENCODING_ERRORS") @@ -2444,11 +2443,11 @@ def _dotglobstr(s): def _iglobpath(s, ignore_case=False, sort_result=None, include_dotfiles=None): - s = builtins.__xonsh__.expand_path(s) + s = xsh.expand_path(s) if sort_result is None: - sort_result = builtins.__xonsh__.env.get("GLOB_SORTED") + sort_result = xsh.env.get("GLOB_SORTED") if include_dotfiles is None: - include_dotfiles = builtins.__xonsh__.env.get("DOTGLOB") + include_dotfiles = xsh.env.get("DOTGLOB") if ignore_case: s = expand_case_matching(s) if "**" in s and "**/*" not in s: @@ -2490,7 +2489,7 @@ def ensure_timestamp(t, datetime_format=None): except (ValueError, TypeError): pass if datetime_format is None: - datetime_format = builtins.__xonsh__.env["XONSH_DATETIME_FORMAT"] + datetime_format = xsh.env["XONSH_DATETIME_FORMAT"] if isinstance(t, datetime.datetime): t = t.timestamp() else: @@ -2500,7 +2499,7 @@ def ensure_timestamp(t, datetime_format=None): def format_datetime(dt): """Format datetime object to string base on $XONSH_DATETIME_FORMAT Env.""" - format_ = builtins.__xonsh__.env["XONSH_DATETIME_FORMAT"] + format_ = xsh.env["XONSH_DATETIME_FORMAT"] return dt.strftime(format_) diff --git a/xonsh/wizard.py b/xonsh/wizard.py index c2f631fec..89c2b41db 100644 --- a/xonsh/wizard.py +++ b/xonsh/wizard.py @@ -6,12 +6,12 @@ import ast import json import pprint import fnmatch -import builtins import textwrap import collections.abc as cabc import typing as tp from xonsh.tools import to_bool, to_bool_or_break, backup_file, print_color +from xonsh.built_ins import XSH from xonsh.jsonutils import serialize_xonsh_json @@ -714,8 +714,8 @@ class PromptVisitor(StateVisitor): singleline() method. See BaseShell for mor details. """ super().__init__(tree=tree, state=state) - self.env = builtins.__xonsh__.env - self.shell = builtins.__xonsh__.shell.shell + self.env = XSH.env + self.shell = XSH.shell.shell self.shell_kwargs = kwargs def visit_wizard(self, node): diff --git a/xonsh/xonfig.py b/xonsh/xonfig.py index 56697e403..10b11760c 100644 --- a/xonsh/xonfig.py +++ b/xonsh/xonfig.py @@ -9,7 +9,6 @@ import random import pprint import tempfile import textwrap -import builtins import argparse import functools import itertools @@ -21,6 +20,7 @@ from xonsh.ply import ply import xonsh.wizard as wiz from xonsh import __version__ as XONSH_VERSION +from xonsh.built_ins import XSH from xonsh.prompt.base import is_template_string from xonsh.platform import ( is_readline_available, @@ -189,7 +189,7 @@ def _dump_xonfig_foreign_shell(path, value): def _dump_xonfig_env(path, value): name = os.path.basename(path.rstrip("/")) - detyper = builtins.__xonsh__.env.get_detyper(name) + detyper = XSH.env.get_detyper(name) dval = str(value) if detyper is None else detyper(value) dval = str(value) if dval is None else dval return "${name} = {val!r}".format(name=name, val=dval) @@ -289,7 +289,7 @@ ENVVAR_PROMPT = "{BOLD_GREEN}>>>{RESET} " def make_exit_message(): """Creates a message for how to exit the wizard.""" - shell_type = builtins.__xonsh__.shell.shell_type + shell_type = XSH.shell.shell_type keyseq = "Ctrl-D" if shell_type == "readline" else "Ctrl-C" msg = "To exit the wizard at any time, press {BOLD_UNDERLINE_CYAN}" msg += keyseq + "{RESET}.\n" @@ -299,7 +299,7 @@ def make_exit_message(): def make_envvar(name): """Makes a StoreNonEmpty node for an environment variable.""" - env = builtins.__xonsh__.env + env = XSH.env vd = env.get_docs(name) if not vd.is_configurable: return @@ -345,7 +345,7 @@ def _make_flat_wiz(kidfunc, *args): def make_env_wiz(): """Makes an environment variable wizard.""" - w = _make_flat_wiz(make_envvar, sorted(builtins.__xonsh__.env.keys())) + w = _make_flat_wiz(make_envvar, sorted(XSH.env.keys())) return w @@ -444,8 +444,8 @@ def make_xonfig_wizard(default_file=None, confirm=False, no_wizard_file=None): def _wizard(ns): - env = builtins.__xonsh__.env - shell = builtins.__xonsh__.shell.shell + env = XSH.env + shell = XSH.shell.shell xonshrcs = env.get("XONSHRC", []) fname = xonshrcs[-1] if xonshrcs and ns.file is None else ns.file no_wiz = os.path.join(env.get("XONSH_CONFIG_DIR"), "no-wizard") @@ -503,7 +503,7 @@ def _xonfig_format_json(data): def _info(ns): - env = builtins.__xonsh__.env + env = XSH.env data = [("xonsh", XONSH_VERSION)] hash_, date_ = githash() if hash_: @@ -554,7 +554,7 @@ def _info(ns): def _styles(ns): - env = builtins.__xonsh__.env + env = XSH.env curr = env.get("XONSH_COLOR_STYLE") styles = sorted(color_style_names()) if ns.json: @@ -618,13 +618,13 @@ def _tok_colors(cmap, cols): def _colors(args): columns, _ = shutil.get_terminal_size() columns -= int(ON_WINDOWS) - style_stash = builtins.__xonsh__.env["XONSH_COLOR_STYLE"] + style_stash = XSH.env["XONSH_COLOR_STYLE"] if args.style is not None: if args.style not in color_style_names(): print("Invalid style: {}".format(args.style)) return - builtins.__xonsh__.env["XONSH_COLOR_STYLE"] = args.style + XSH.env["XONSH_COLOR_STYLE"] = args.style color_map = color_style() akey = next(iter(color_map)) @@ -633,7 +633,7 @@ def _colors(args): else: s = _tok_colors(color_map, columns) print_color(s) - builtins.__xonsh__.env["XONSH_COLOR_STYLE"] = style_stash + XSH.env["XONSH_COLOR_STYLE"] = style_stash def _tutorial(args): @@ -878,7 +878,7 @@ WELCOME_MSG = [ def print_welcome_screen(): - shell_type = builtins.__xonsh__.env.get("SHELL_TYPE") + shell_type = XSH.env.get("SHELL_TYPE") subst = dict(tagline=random.choice(list(TAGLINES)), version=XONSH_VERSION) for elem in WELCOME_MSG: if elem == "[SHELL_TYPE_WARNING]": diff --git a/xonsh/xontribs.py b/xonsh/xontribs.py index 6930dad3b..0df95b67a 100644 --- a/xonsh/xontribs.py +++ b/xonsh/xontribs.py @@ -1,6 +1,5 @@ """Tools for helping manage xontributions.""" import argparse -import builtins import functools import importlib import importlib.util @@ -10,6 +9,7 @@ import typing as tp from enum import IntEnum from pathlib import Path +from xonsh.built_ins import XSH from xonsh.xontribs_meta import get_xontribs from xonsh.tools import print_color, print_exception, unthreadable @@ -68,7 +68,7 @@ def update_context(name, ctx=None): then __xonsh__.ctx is updated. """ if ctx is None: - ctx = builtins.__xonsh__.ctx + ctx = XSH.ctx modctx = xontrib_context(name) if modctx is None: if not hasattr(update_context, "bad_imports"): @@ -80,7 +80,7 @@ def update_context(name, ctx=None): def xontribs_load(names, verbose=False): """Load xontribs from a list of names""" - ctx = builtins.__xonsh__.ctx + ctx = XSH.ctx res = ExitCode.OK for name in names: if verbose: diff --git a/xonsh/xoreutils/_which.py b/xonsh/xoreutils/_which.py index 583b0aaf1..ad500dc51 100644 --- a/xonsh/xoreutils/_which.py +++ b/xonsh/xoreutils/_which.py @@ -28,9 +28,10 @@ import os import sys import stat import getopt -import builtins import collections.abc as cabc +from xonsh.built_ins import XSH + r"""Find the full path to commands. which(command, path=None, verbose=0, exts=None) @@ -191,7 +192,7 @@ def whichgen(command, path=None, verbose=0, exts=None): # Windows has the concept of a list of extensions (PATHEXT env var). if sys.platform.startswith("win"): if exts is None: - exts = builtins.__xonsh__.env["PATHEXT"] + exts = XSH.env["PATHEXT"] # If '.exe' is not in exts then obviously this is Win9x and # or a bogus PATHEXT, then use a reasonable default. for ext in exts: diff --git a/xonsh/xoreutils/cat.py b/xonsh/xoreutils/cat.py index 0ddc08d4d..ff75152af 100644 --- a/xonsh/xoreutils/cat.py +++ b/xonsh/xoreutils/cat.py @@ -2,9 +2,9 @@ import os import sys import time -import builtins import xonsh.procs.pipelines as xpp +from xonsh.built_ins import XSH from xonsh.xoreutils.util import arg_handler @@ -39,7 +39,7 @@ def _cat_line( def _cat_single_file(opts, fname, stdin, out, err, line_count=1): - env = builtins.__xonsh__.env + env = XSH.env enc = env.get("XONSH_ENCODING") enc_errors = env.get("XONSH_ENCODING_ERRORS") read_size = 0 diff --git a/xonsh/xoreutils/pwd.py b/xonsh/xoreutils/pwd.py index 4ed394e04..5c9b97f72 100644 --- a/xonsh/xoreutils/pwd.py +++ b/xonsh/xoreutils/pwd.py @@ -1,10 +1,11 @@ """A pwd implementation for xonsh.""" import os +from xonsh.built_ins import XSH def pwd(args, stdin, stdout, stderr): """A pwd implementation""" - e = __xonsh__.env["PWD"] + e = XSH.env["PWD"] if "-h" in args or "--help" in args: print(PWD_HELP, file=stdout) return 0 diff --git a/xonsh/xoreutils/which.py b/xonsh/xoreutils/which.py index dc6ed0867..e49a4907d 100644 --- a/xonsh/xoreutils/which.py +++ b/xonsh/xoreutils/which.py @@ -1,13 +1,13 @@ """Implements the which xoreutil.""" import os import argparse -import builtins import functools import xonsh from xonsh.xoreutils import _which import xonsh.platform as xp import xonsh.procs.pipelines as xpp +from xonsh.built_ins import XSH @functools.lru_cache() @@ -76,7 +76,7 @@ def _which_create_parser(): def print_global_object(arg, stdout): """Print the object.""" - obj = builtins.__xonsh__.ctx.get(arg) + obj = XSH.ctx.get(arg) print("global object of {}".format(type(obj)), file=stdout) @@ -88,7 +88,7 @@ def print_path(abs_name, from_where, stdout, verbose=False, captured=False): p, f = os.path.split(abs_name) f = next(s.name for s in os.scandir(p) if s.name.lower() == f.lower()) abs_name = os.path.join(p, f) - if builtins.__xonsh__.env.get("FORCE_POSIX_PATHS", False): + if XSH.env.get("FORCE_POSIX_PATHS", False): abs_name.replace(os.sep, os.altsep) if verbose: print(f"{abs_name} ({from_where})", file=stdout) @@ -99,7 +99,7 @@ def print_path(abs_name, from_where, stdout, verbose=False, captured=False): def print_alias(arg, stdout, verbose=False): """Print the alias.""" - alias = builtins.aliases[arg] + alias = XSH.aliases[arg] if not verbose: if not callable(alias): print(" ".join(alias), file=stdout) @@ -114,7 +114,7 @@ def print_alias(arg, stdout, verbose=False): file=stdout, ) if callable(alias) and not isinstance(alias, xonsh.aliases.ExecAlias): - builtins.__xonsh__.superhelp(alias) + XSH.superhelp(alias) def which(args, stdin=None, stdout=None, stderr=None, spec=None): @@ -141,16 +141,16 @@ def which(args, stdin=None, stdout=None, stderr=None, spec=None): if pargs.exts: exts = pargs.exts else: - exts = builtins.__xonsh__.env["PATHEXT"] + exts = XSH.env["PATHEXT"] else: exts = None failures = [] for arg in pargs.args: nmatches = 0 - if pargs.all and arg in builtins.__xonsh__.ctx: + if pargs.all and arg in XSH.ctx: print_global_object(arg, stdout) nmatches += 1 - if arg in builtins.aliases and not pargs.skip: + if arg in XSH.aliases and not pargs.skip: print_alias(arg, stdout, verbose) nmatches += 1 if not pargs.all: @@ -159,7 +159,7 @@ def which(args, stdin=None, stdout=None, stderr=None, spec=None): # from os.environ so we temporarily override it with # __xosnh_env__['PATH'] original_os_path = xp.os_environ["PATH"] - xp.os_environ["PATH"] = builtins.__xonsh__.env.detype()["PATH"] + xp.os_environ["PATH"] = XSH.env.detype()["PATH"] matches = _which.whichgen(arg, exts=exts, verbose=verbose) for abs_name, from_where in matches: print_path(abs_name, from_where, stdout, verbose, captured) diff --git a/xontrib/abbrevs.py b/xontrib/abbrevs.py index 7ac9d5947..d3c841145 100644 --- a/xontrib/abbrevs.py +++ b/xontrib/abbrevs.py @@ -31,13 +31,14 @@ import typing as tp from prompt_toolkit.buffer import Buffer from prompt_toolkit.filters import completion_is_selected, IsMultiline from prompt_toolkit.keys import Keys -from xonsh.built_ins import DynamicAccessProxy +from xonsh.built_ins import DynamicAccessProxy, XSH from xonsh.events import events from xonsh.tools import check_for_partial_string __all__ = () -builtins.__xonsh__.abbrevs = dict() +# todo: do not assign .abbrevs and directly use abbrevs as mutable const. +XSH.abbrevs = abbrevs = dict() proxy = DynamicAccessProxy("abbrevs", "__xonsh__.abbrevs") setattr(builtins, "abbrevs", proxy) @@ -47,12 +48,50 @@ class _LastExpanded(tp.NamedTuple): expanded: str -last_expanded: tp.Optional[_LastExpanded] = None +class Abbreviation: + """A container class to handle state related to abbreviating keywords""" + + last_expanded: tp.Optional[_LastExpanded] = None + + def expand(self, buffer: Buffer) -> bool: + """expand the given abbr text. Return true if cursor position changed.""" + if not abbrevs: + return False + document = buffer.document + word = document.get_word_before_cursor(WORD=True) + if word in abbrevs.keys(): + partial = document.text[: document.cursor_position] + startix, endix, quote = check_for_partial_string(partial) + if startix is not None and endix is None: + return False + text = get_abbreviated(word, buffer) + + buffer.delete_before_cursor(count=len(word)) + buffer.insert_text(text) + + self.last_expanded = _LastExpanded(word, text) + if EDIT_SYMBOL in text: + set_cursor_position(buffer, text) + return True + return False + + def revert(self, buffer) -> bool: + if self.last_expanded is None: + return False + document = buffer.document + expansion = self.last_expanded.expanded + " " + if not document.text_before_cursor.endswith(expansion): + return False + buffer.delete_before_cursor(count=len(expansion)) + buffer.insert_text(self.last_expanded.word) + self.last_expanded = None + return True + + EDIT_SYMBOL = "" def get_abbreviated(key: str, buffer) -> str: - abbrevs = getattr(builtins, "abbrevs", None) abbr = abbrevs[key] if callable(abbr): text = abbr(buffer=buffer, word=key) @@ -61,46 +100,6 @@ def get_abbreviated(key: str, buffer) -> str: return text -def expand_abbrev(buffer: Buffer) -> bool: - """expand the given abbr text. Return true if cursor position changed.""" - global last_expanded - last_expanded = None - abbrevs = getattr(builtins, "abbrevs", None) - if abbrevs is None: - return False - document = buffer.document - word = document.get_word_before_cursor(WORD=True) - if word in abbrevs.keys(): - partial = document.text[: document.cursor_position] - startix, endix, quote = check_for_partial_string(partial) - if startix is not None and endix is None: - return False - text = get_abbreviated(word, buffer) - - buffer.delete_before_cursor(count=len(word)) - buffer.insert_text(text) - - last_expanded = _LastExpanded(word, text) - if EDIT_SYMBOL in text: - set_cursor_position(buffer, text) - return True - return False - - -def revert_abbrev(buffer) -> bool: - global last_expanded - if last_expanded is None: - return False - document = buffer.document - expansion = last_expanded.expanded + " " - if not document.text_before_cursor.endswith(expansion): - return False - buffer.delete_before_cursor(count=len(expansion)) - buffer.insert_text(last_expanded.word) - last_expanded = None - return True - - def set_cursor_position(buffer, expanded: str) -> None: pos = expanded.rfind(EDIT_SYMBOL) if pos == -1: @@ -117,14 +116,15 @@ def custom_keybindings(bindings, **kw): handler = bindings.add insert_mode = ViInsertMode() | EmacsInsertMode() + abbrev = Abbreviation() @handler(" ", filter=IsMultiline() & insert_mode) def handle_space(event): buffer = event.app.current_buffer add_space = True - if not revert_abbrev(buffer): - position_changed = expand_abbrev(buffer) + if not abbrev.revert(buffer): + position_changed = abbrev.expand(buffer) if position_changed: add_space = False if add_space: @@ -140,5 +140,5 @@ def custom_keybindings(bindings, **kw): buffer = event.app.current_buffer current_char = buffer.document.current_char if not current_char or current_char.isspace(): - expand_abbrev(buffer) + abbrev.expand(buffer) carriage_return(buffer, event.cli) diff --git a/xontrib/autovox.py b/xontrib/autovox.py index 816d1c4bc..cc5d3e705 100644 --- a/xontrib/autovox.py +++ b/xontrib/autovox.py @@ -6,19 +6,20 @@ mechanics of venv searching and chdir handling. This provides no interface for end users. -Developers should look at events.autovox_policy +Developers should look at XSH.builtins.events.autovox_policy """ import itertools from pathlib import Path import xontrib.voxapi as voxapi import warnings +from xonsh.built_ins import XSH __all__ = () _policies = [] -events.doc( +XSH.builtins.events.doc( "autovox_policy", """ autovox_policy(path: pathlib.Path) -> Union[str, pathlib.Path, None] @@ -44,7 +45,7 @@ def get_venv(vox, dirpath): for path in itertools.chain((dirpath,), dirpath.parents): venvs = [ vox[p] - for p in events.autovox_policy.fire(path=path) + for p in XSH.builtins.events.autovox_policy.fire(path=path) if p is not None and p in vox # Filter out venvs that don't exist ] if len(venvs) == 0: @@ -80,7 +81,7 @@ def check_for_new_venv(curdir, olddir): # Core mechanism: Check for venv when the current directory changes -@events.on_chdir +@XSH.builtins.events.on_chdir def cd_handler(newdir, olddir, **_): check_for_new_venv(Path(newdir), Path(olddir)) @@ -88,12 +89,12 @@ def cd_handler(newdir, olddir, **_): # Recalculate when venvs are created or destroyed -@events.vox_on_create +@XSH.builtins.events.vox_on_create def create_handler(**_): check_for_new_venv(Path.cwd(), ...) -@events.vox_on_destroy +@XSH.builtins.events.vox_on_destroy def destroy_handler(**_): check_for_new_venv(Path.cwd(), ...) @@ -101,6 +102,6 @@ def destroy_handler(**_): # Initial activation before first prompt -@events.on_post_init +@XSH.builtins.events.on_post_init def load_handler(**_): check_for_new_venv(Path.cwd(), None) diff --git a/xontrib/bashisms.py b/xontrib/bashisms.py index aedbbd351..8c7cb8d3a 100644 --- a/xontrib/bashisms.py +++ b/xontrib/bashisms.py @@ -2,13 +2,12 @@ import shlex import sys import re -import builtins - +from xonsh.built_ins import XSH __all__ = () -@events.on_transform_command +@XSH.builtins.events.on_transform_command def bash_preproc(cmd, **kw): bang_previous = { "!": lambda x: x, @@ -19,7 +18,7 @@ def bash_preproc(cmd, **kw): def replace_bang(m): arg = m.group(1) - inputs = __xonsh__.history.inps + inputs = XSH.history.inps # Dissect the previous command. if arg in bang_previous: @@ -49,21 +48,21 @@ def alias(args, stdin=None): # shlex.split to remove quotes, e.g. "foo='echo hey'" into # "foo=echo hey" name, cmd = shlex.split(arg)[0].split("=", 1) - aliases[name] = shlex.split(cmd) - elif arg in aliases: - print("{}={}".format(arg, aliases[arg])) + XSH.aliases[name] = shlex.split(cmd) + elif arg in XSH.aliases: + print("{}={}".format(arg, XSH.aliases[arg])) else: print("alias: {}: not found".format(arg), file=sys.stderr) ret = 1 else: - for alias, cmd in aliases.items(): + for alias, cmd in XSH.aliases.items(): print("{}={}".format(alias, cmd)) return ret -aliases["alias"] = alias -builtins.__xonsh__.env["THREAD_SUBPROCS"] = False +XSH.aliases["alias"] = alias +XSH.env["THREAD_SUBPROCS"] = False def _unset(args): @@ -72,12 +71,12 @@ def _unset(args): for v in args: try: - __xonsh__.env.pop(v) + XSH.env.pop(v) except KeyError: print(f"{v} not found", file=sys.stderr) -aliases["unset"] = _unset +XSH.aliases["unset"] = _unset def _export(args): @@ -87,24 +86,24 @@ def _export(args): for eq in args: if "=" in eq: name, val = shlex.split(eq)[0].split("=", 1) - __xonsh__.env[name] = val + XSH.env[name] = val else: print(f"{eq} equal sign not found", file=sys.stderr) -aliases["export"] = _export +XSH.aliases["export"] = _export def _set(args): arg = args[0] if arg == "-e": - __xonsh__.env["RAISE_SUBPROC_ERROR"] = True + XSH.env["RAISE_SUBPROC_ERROR"] = True elif arg == "+e": - __xonsh__.env["RAISE_SUBPROC_ERROR"] = False + XSH.env["RAISE_SUBPROC_ERROR"] = False elif arg == "-x": - __xonsh__.env["XONSH_TRACE_SUBPROC"] = True + XSH.env["XONSH_TRACE_SUBPROC"] = True elif arg == "+x": - __xonsh__.env["XONSH_TRACE_SUBPROC"] = False + XSH.env["XONSH_TRACE_SUBPROC"] = False else: print( "Not supported in xontrib bashisms.\nPRs are welcome - https://github.com/xonsh/xonsh/blob/master/xontrib/bashisms.py", @@ -112,7 +111,7 @@ def _set(args): ) -aliases["set"] = _set +XSH.aliases["set"] = _set def _shopt(args): @@ -122,7 +121,7 @@ def _shopt(args): args_len = len(args) if args_len == 0: for so in supported_shopt: - onoff = "on" if so in __xonsh__.env and __xonsh__.env[so] else "off" + onoff = "on" if so in XSH.env and XSH.env[so] else "off" print(f"dotglob\t{onoff}") return elif args_len < 2 or args[0] in ["-h", "--help"]: @@ -133,9 +132,9 @@ def _shopt(args): optname = args[1] if opt == "-s" and optname == "dotglob": - __xonsh__.env["DOTGLOB"] = True + XSH.env["DOTGLOB"] = True elif opt == "-u" and optname == "dotglob": - __xonsh__.env["DOTGLOB"] = False + XSH.env["DOTGLOB"] = False else: print( "Not supported in xontrib bashisms.\nPRs are welcome - https://github.com/xonsh/xonsh/blob/master/xontrib/bashisms.py", @@ -143,7 +142,7 @@ def _shopt(args): ) -aliases["shopt"] = _shopt +XSH.aliases["shopt"] = _shopt -aliases["complete"] = "completer list" +XSH.aliases["complete"] = "completer list" diff --git a/xontrib/coreutils.py b/xontrib/coreutils.py index 2dd629fa1..6a43d4169 100644 --- a/xontrib/coreutils.py +++ b/xontrib/coreutils.py @@ -19,12 +19,13 @@ from xonsh.xoreutils.pwd import pwd from xonsh.xoreutils.tee import tee from xonsh.xoreutils.tty import tty from xonsh.xoreutils.yes import yes +from xonsh.built_ins import XSH __all__ = () -aliases["cat"] = cat -aliases["echo"] = echo -aliases["pwd"] = pwd -aliases["tee"] = tee -aliases["tty"] = tty -aliases["yes"] = yes +XSH.aliases["cat"] = cat +XSH.aliases["echo"] = echo +XSH.aliases["pwd"] = pwd +XSH.aliases["tee"] = tee +XSH.aliases["tty"] = tty +XSH.aliases["yes"] = yes diff --git a/xontrib/distributed.py b/xontrib/distributed.py index e0d430eff..30608e7d4 100644 --- a/xontrib/distributed.py +++ b/xontrib/distributed.py @@ -1,5 +1,6 @@ """Hooks for the distributed parallel computing library.""" from xonsh.contexts import Functor +from xonsh.built_ins import XSH __all__ = ["DSubmitter", "dsubmit"] @@ -13,7 +14,7 @@ def dworker(args, stdin=None): dworker.main.main(args=args, prog_name="dworker", standalone_mode=False) -aliases["dworker"] = dworker +XSH.aliases["dworker"] = dworker class DSubmitter(Functor): diff --git a/xontrib/free_cwd.py b/xontrib/free_cwd.py index 1c60a61ee..dfa15923a 100644 --- a/xontrib/free_cwd.py +++ b/xontrib/free_cwd.py @@ -8,11 +8,11 @@ ``os.getcwd()``. """ import os -import builtins import functools from pathlib import Path from xonsh.tools import print_exception +from xonsh.built_ins import XSH from xonsh.platform import ON_WINDOWS, ON_CYGWIN, ON_MSYS @@ -35,7 +35,7 @@ def _cwd_release_wrapper(func): displayed. This works by temporarily setting the workdir to the users home directory. """ - env = builtins.__xonsh__.env + env = XSH.env if env.get("UPDATE_PROMPT_ON_KEYPRESS"): return func if not hasattr(func, "_orgfunc") else func._orgfunc @@ -57,7 +57,7 @@ def _cwd_release_wrapper(func): except (FileNotFoundError, NotADirectoryError): print_exception() newpath = _chdir_up(pwd) - builtins.__xonsh__.env["PWD"] = newpath + XSH.env["PWD"] = newpath raise KeyboardInterrupt return out @@ -70,7 +70,7 @@ def _cwd_restore_wrapper(func): directory. Designed to wrap completer callbacks from the prompt_toolkit or readline. """ - env = builtins.__xonsh__.env + env = XSH.env if env.get("UPDATE_PROMPT_ON_KEYPRESS"): return func if not hasattr(func, "_orgfunc") else func._orgfunc @@ -91,7 +91,7 @@ def _cwd_restore_wrapper(func): return wrapper -@events.on_ptk_create +@XSH.builtins.events.on_ptk_create def setup_release_cwd_hook(prompter, history, completer, bindings, **kw): if ON_WINDOWS and not ON_CYGWIN and not ON_MSYS: prompter.prompt = _cwd_release_wrapper(prompter.prompt) diff --git a/xontrib/jedi.py b/xontrib/jedi.py index d18f8a897..1d860b821 100644 --- a/xontrib/jedi.py +++ b/xontrib/jedi.py @@ -1,10 +1,9 @@ """Use Jedi as xonsh's python completer.""" -import builtins import os import xonsh -from xonsh.built_ins import XonshSession from xonsh.lazyasd import lazyobject, lazybool +from xonsh.built_ins import XSH from xonsh.completers.tools import ( get_filter_function, RichCompletion, @@ -55,14 +54,13 @@ def complete_jedi(context: CompletionContext): if context.python is None: return None - xonsh_execer: XonshSession = builtins.__xonsh__ # type: ignore ctx = context.python.ctx or {} # if the first word is a known command (and we're not completing it), don't complete. # taken from xonsh/completers/python.py if context.command and context.command.arg_index != 0: first = context.command.args[0].value - if first in xonsh_execer.commands_cache and first not in ctx: # type: ignore + if first in XSH.commands_cache and first not in ctx: # type: ignore return None # if we're completing a possible command and the prefix contains a valid path, don't complete. @@ -72,7 +70,7 @@ def complete_jedi(context: CompletionContext): return None filter_func = get_filter_function() - jedi.settings.case_insensitive_completion = not xonsh_execer.env.get( + jedi.settings.case_insensitive_completion = not XSH.env.get( "CASE_SENSITIVE_COMPLETIONS" ) @@ -83,7 +81,7 @@ def complete_jedi(context: CompletionContext): index - source.rfind("\n", 0, index) - 1 ) # will be `index - (-1) - 1` if there's no newline - extra_ctx = {"__xonsh__": xonsh_execer} + extra_ctx = {"__xonsh__": XSH} try: extra_ctx["_"] = _ except NameError: diff --git a/xontrib/mpl.py b/xontrib/mpl.py index 7b0096954..67dff1ad6 100644 --- a/xontrib/mpl.py +++ b/xontrib/mpl.py @@ -4,6 +4,7 @@ is imported. from xonsh.tools import unthreadable from xonsh.lazyasd import lazyobject +from xonsh.built_ins import XSH __all__ = () @@ -17,7 +18,7 @@ def mpl(args, stdin=None): show() -aliases["mpl"] = mpl +XSH.aliases["mpl"] = mpl @lazyobject @@ -29,12 +30,10 @@ def pylab_helpers(): return m -@events.on_import_post_exec_module +@XSH.builtins.events.on_import_post_exec_module def interactive_pyplot(module=None, **kwargs): """This puts pyplot in interactive mode once it is imported.""" - if module.__name__ != "matplotlib.pyplot" or not __xonsh__.env.get( - "XONSH_INTERACTIVE" - ): + if module.__name__ != "matplotlib.pyplot" or not XSH.env.get("XONSH_INTERACTIVE"): return # Since we are in interactive mode, let's monkey-patch plt.show # to try to never block. @@ -60,7 +59,7 @@ def interactive_pyplot(module=None, **kwargs): module.show = xonsh_show # register figure drawer - @events.on_postcommand + @XSH.builtins.events.on_postcommand def redraw_mpl_figure(**kwargs): """Redraws the current matplotlib figure after each command.""" pylab_helpers.Gcf.draw_all() diff --git a/xontrib/mplhooks.py b/xontrib/mplhooks.py index 66b1aa744..0736f71ac 100644 --- a/xontrib/mplhooks.py +++ b/xontrib/mplhooks.py @@ -8,6 +8,7 @@ import matplotlib.pyplot as plt from xonsh.tools import print_color, ON_WINDOWS +from xonsh.built_ins import XSH try: # Use iterm2_tools as an indicator for the iterm2 terminal emulator @@ -154,7 +155,7 @@ def display_figure_with_iterm2(fig): def show(): """Run the mpl display sequence by printing the most recent figure to console""" try: - minimal = __xonsh__.env["XONTRIB_MPL_MINIMAL"] + minimal = XSH.env["XONTRIB_MPL_MINIMAL"] except KeyError: minimal = XONTRIB_MPL_MINIMAL_DEFAULT fig = plt.gcf() diff --git a/xontrib/prompt_ret_code.py b/xontrib/prompt_ret_code.py index 5feee9eb9..e245d60c4 100644 --- a/xontrib/prompt_ret_code.py +++ b/xontrib/prompt_ret_code.py @@ -1,10 +1,10 @@ from xonsh.tools import ON_WINDOWS as _ON_WINDOWS -import builtins +from xonsh.built_ins import XSH def _ret_code_color(): - if builtins.__xonsh__.history.rtns: - color = "blue" if builtins.__xonsh__.history.rtns[-1] == 0 else "red" + if XSH.history.rtns: + color = "blue" if XSH.history.rtns[-1] == 0 else "red" else: color = "blue" if _ON_WINDOWS: @@ -20,8 +20,8 @@ def _ret_code_color(): def _ret_code(): - if builtins.__xonsh__.history.rtns: - return_code = builtins.__xonsh__.history.rtns[-1] + if XSH.history.rtns: + return_code = XSH.history.rtns[-1] if return_code != 0: return "[{}]".format(return_code) return None @@ -29,7 +29,7 @@ def _ret_code(): def _update(): - env = builtins.__xonsh__.env + env = XSH.env env["PROMPT"] = env["PROMPT"].replace( "{prompt_end}{RESET}", "{ret_code_color}{ret_code}{prompt_end}{RESET}" diff --git a/xontrib/voxapi.py b/xontrib/voxapi.py index 393274e99..96237d689 100644 --- a/xontrib/voxapi.py +++ b/xontrib/voxapi.py @@ -12,11 +12,10 @@ import os import sys import shutil import logging -import builtins import collections.abc import subprocess as sp - +from xonsh.built_ins import XSH from xonsh.platform import ON_POSIX, ON_WINDOWS @@ -123,12 +122,12 @@ class Vox(collections.abc.Mapping): """ def __init__(self): - if not builtins.__xonsh__.env.get("VIRTUALENV_HOME"): + if not XSH.env.get("VIRTUALENV_HOME"): home_path = os.path.expanduser("~") self.venvdir = os.path.join(home_path, ".virtualenvs") - builtins.__xonsh__.env["VIRTUALENV_HOME"] = self.venvdir + XSH.env["VIRTUALENV_HOME"] = self.venvdir else: - self.venvdir = builtins.__xonsh__.env["VIRTUALENV_HOME"] + self.venvdir = XSH.env["VIRTUALENV_HOME"] def create( self, @@ -272,7 +271,7 @@ class Vox(collections.abc.Mapping): the current one (throws a KeyError if there isn't one). """ if name is ...: - env = builtins.__xonsh__.env + env = XSH.env env_paths = [env["VIRTUAL_ENV"]] elif isinstance(name, os.PathLike): env_paths = [os.fspath(name)] @@ -331,7 +330,7 @@ class Vox(collections.abc.Mapping): Returns None if no environment is active. """ - env = builtins.__xonsh__.env + env = XSH.env if "VIRTUAL_ENV" not in env: return env_path = env["VIRTUAL_ENV"] @@ -352,7 +351,7 @@ class Vox(collections.abc.Mapping): name : str Virtual environment name or absolute path. """ - env = builtins.__xonsh__.env + env = XSH.env ve = self[name] if "VIRTUAL_ENV" in env: self.deactivate() @@ -369,7 +368,7 @@ class Vox(collections.abc.Mapping): """ Deactivate the active virtual environment. Returns its name. """ - env = builtins.__xonsh__.env + env = XSH.env if "VIRTUAL_ENV" not in env: raise NoEnvironmentActive("No environment currently active.") @@ -410,4 +409,4 @@ class Vox(collections.abc.Mapping): def _get_vox_default_interpreter(): """Return the interpreter set by the $VOX_DEFAULT_INTERPRETER if set else sys.executable""" - return builtins.__xonsh__.env.get("VOX_DEFAULT_INTERPRETER", sys.executable) + return XSH.env.get("VOX_DEFAULT_INTERPRETER", sys.executable) diff --git a/xontrib/whole_word_jumping.py b/xontrib/whole_word_jumping.py index ac72fc9c9..cafdd5f27 100644 --- a/xontrib/whole_word_jumping.py +++ b/xontrib/whole_word_jumping.py @@ -4,10 +4,12 @@ Alt+Left/Right remains unmodified to jump over smaller word segments. """ from prompt_toolkit.keys import Keys +from xonsh.built_ins import XSH + __all__ = () -@events.on_ptk_create +@XSH.builtins.events.on_ptk_create def custom_keybindings(bindings, **kw): # Key bindings for jumping over whole words (everything that's not diff --git a/xontrib/xog.py b/xontrib/xog.py index d9d66e1f7..3e5602cff 100644 --- a/xontrib/xog.py +++ b/xontrib/xog.py @@ -2,11 +2,12 @@ This adds `xog` - a simple command to establish and print temporary traceback log file. """ -import builtins import os import pathlib import tempfile +from xonsh.built_ins import XSH + __all__ = () @@ -51,7 +52,7 @@ def _xog(args, stdout=None, stderr=None): _print_help(stdout) return 0 - logfile = builtins.__xonsh__.env.get("XONSH_TRACEBACK_LOGFILE", "") + logfile = XSH.env.get("XONSH_TRACEBACK_LOGFILE", "") if not (logfile and os.path.isfile(logfile)): print("Traceback log file doesn't exist.", file=stderr) return -1 @@ -64,5 +65,5 @@ def _xog(args, stdout=None, stderr=None): return 0 if rc else -1 -builtins.__xonsh__.env["XONSH_TRACEBACK_LOGFILE"] = _get_log_file_name() -aliases["xog"] = _xog +XSH.env["XONSH_TRACEBACK_LOGFILE"] = _get_log_file_name() +XSH.aliases["xog"] = _xog