From 7c4e207abd7c808d345e4c511bf5fffb4105b9f9 Mon Sep 17 00:00:00 2001 From: Noorhteen Raja NJ Date: Sat, 8 Jan 2022 04:03:22 +0530 Subject: [PATCH] update test xsh usage (#4581) * todo * test: remove usage of DummyEnv and setting .env attribute on xession fixture one step closer to making too much of tweaking to xession during tests * test: fix tests vox and gitstatus-prompt * docs: update test-fixture usage * fix: import flake8 error * test: remove direct access to XSH in tests * test: remove usage of XSH in test files * todo * test: use tmp-dir to create stubs * refactor: use fixture factory to mock out XonshSession * refactor: remove direct access of XSH from functions * refactor: remove direct access of XSH from functions * fix: qa checks * refactor: rename variables to match their values * test: update failing tests because it had no PATH set previously * fix: remove builtins usage from pyghooks.py * style: * refactor: update tests to use fixtures * fix: env varialbe is setup per function some tests accidentally update the env variables and that is leaking into next tests * fix: failing vox tests * test: set commands_cache per test * test: fix failing tests * fix: failing tests on linux ptk-highlight * fix: failing tests on Windows cwd-prompt * test: copy env as to not affect original object * fix: lazily evaluate cmds-cache in pyghooks * test: fix failing tests * fix: qa errors import * test: set commands-cache per test while caching path results * test: speedup test_thread_local_swap * fix: failing tests on windows * refactor: Execer doesn't control session * refactor: XSH.unload will take care of reversing builtins attrs set * test: use env.update over monkeypatch * Revert "test: use env.update over monkeypatch" This reverts commit 010a5022247a098f1741966b8af1bf758663480e. --- .pre-commit-config.yaml | 2 +- CONTRIBUTING.rst | 7 +- tests/aliases/test_completer_alias.py | 8 +- tests/aliases/test_source.py | 6 +- tests/completers/test_command_completers.py | 5 +- .../completers/test_environment_completer.py | 5 +- tests/completers/test_pip_completer.py | 9 +- tests/conftest.py | 223 ++- tests/procs/test_specs.py | 15 +- tests/prompt/test_base.py | 27 +- tests/prompt/test_cwd.py | 12 +- tests/prompt/test_gitstatus.py | 5 + tests/prompt/test_vc.py | 3 +- tests/test_aliases.py | 27 +- tests/test_ast.py | 18 +- tests/test_base_shell.py | 5 +- tests/test_builtins.py | 4 +- tests/test_commands_cache.py | 95 +- tests/test_completion_context.py | 16 +- tests/test_contexts.py | 108 +- tests/test_dirstack.py | 13 +- tests/test_dirstack_unc.py | 11 +- tests/test_environ.py | 31 +- tests/test_execer.py | 147 +- tests/test_imphooks.py | 5 +- tests/test_main.py | 2 +- tests/test_parser.py | 1470 +++++++++-------- tests/test_pipelines.py | 11 +- tests/test_ptk_highlight.py | 233 ++- tests/test_ptk_shell.py | 2 +- tests/test_pyghooks.py | 14 +- tests/test_shell.py | 31 +- tests/test_tools.py | 15 +- tests/test_vox.py | 5 +- tests/test_xonfig.py | 8 +- tests/tools.py | 124 +- xonsh/commands_cache.py | 82 +- xonsh/execer.py | 2 - xonsh/prompt/cwd.py | 19 +- xonsh/pyghooks.py | 9 +- xonsh/tools.py | 10 +- xontrib/voxapi.py | 2 +- 42 files changed, 1444 insertions(+), 1402 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7db173427..019722c6d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,7 +5,7 @@ repos: name: black # this gets run within development environment. # Otherwise will raise command not found or use system level binary - entry: black --check xonsh/ xontrib/ tests/ + entry: black xonsh/ xontrib/ tests/ language: system stages: [ commit ] types: diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index df9f419ec..87c718a94 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -246,8 +246,11 @@ parts of xonsh for more test isolation. For a list of the various fixtures:: when writing tests it's best to use pytest features i.e. parametrization:: @pytest.mark.parametrize('env', [test_env1, test_env2]) - def test_one(env, xonsh_builtins): - xonsh_builtins.__xonsh__.env = env + def test_one(env, xession): + # update the environment variables instead of setting the attribute + # which could result in leaks to other tests. + # each run will have the same set of default env variables set. + xession.env.update(env) ... this will run the test two times each time with the respective `test_env`. diff --git a/tests/aliases/test_completer_alias.py b/tests/aliases/test_completer_alias.py index 8b2051d40..9da09594d 100644 --- a/tests/aliases/test_completer_alias.py +++ b/tests/aliases/test_completer_alias.py @@ -1,6 +1,5 @@ import pytest -from xonsh.built_ins import XSH from xonsh.completers._aliases import add_one_completer from xonsh.completers.tools import non_exclusive_completer @@ -29,7 +28,8 @@ NON_EXCLUSIVE = non_exclusive_completer(lambda: None) ), ), ) -def test_add_completer_start(monkeypatch, initial, exp): - monkeypatch.setattr(XSH, "completers", initial) +def test_add_completer_start(monkeypatch, initial, exp, xession): + xession.completers.clear() + xession.completers.update(initial) add_one_completer("new", SIMPLE, "start") - assert list(XSH.completers.keys()) == exp + assert list(xession.completers.keys()) == exp diff --git a/tests/aliases/test_source.py b/tests/aliases/test_source.py index ce7dd4921..d38735f55 100644 --- a/tests/aliases/test_source.py +++ b/tests/aliases/test_source.py @@ -8,7 +8,7 @@ from xonsh.aliases import source_alias, make_default_aliases @pytest.fixture -def mockopen(xonsh_builtins, monkeypatch): +def mockopen(xession, monkeypatch): @contextmanager def mocked_open(fpath, *args, **kwargs): yield MagicMock(read=lambda: fpath) @@ -33,7 +33,9 @@ def test_source_current_dir(mockopen, monkeypatch, mocked_execx_checker): assert mocked_execx_checker == ["foo", "bar"] -def test_source_path(mockopen, mocked_execx_checker): +def test_source_path(mockopen, mocked_execx_checker, patch_locate_binary, xession): + patch_locate_binary(xession.commands_cache) + source_alias(["foo", "bar"]) path_foo = os.path.join("tests", "bin", "foo") path_bar = os.path.join("tests", "bin", "bar") diff --git a/tests/completers/test_command_completers.py b/tests/completers/test_command_completers.py index 3d9ea1387..0619d4e0a 100644 --- a/tests/completers/test_command_completers.py +++ b/tests/completers/test_command_completers.py @@ -15,9 +15,8 @@ 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 xs_orig_commands_cache(xession): + pass def test_complete_command(completion_context_parse): diff --git a/tests/completers/test_environment_completer.py b/tests/completers/test_environment_completer.py index 9f9e9d8e2..ba5a61b5c 100644 --- a/tests/completers/test_environment_completer.py +++ b/tests/completers/test_environment_completer.py @@ -1,6 +1,5 @@ import pytest -from xonsh.environ import Env from xonsh.parsers.completion_context import CompletionContextParser from xonsh.completers.environment import complete_environment_vars @@ -19,7 +18,7 @@ def parser(): ), ) def test_simple(cmd, xession, monkeypatch, parser): - monkeypatch.setattr(xession, "env", Env({"WOW": 1})) + xession.env.update({"WOW": 1}) context = parser.parse(cmd, len(cmd)) comps, lprefix = complete_environment_vars(context) @@ -28,7 +27,7 @@ def test_simple(cmd, xession, monkeypatch, parser): def test_rich_completions(xession, monkeypatch, parser): - monkeypatch.setattr(xession, "env", Env({"WOW": 1})) + xession.env.update({"WOW": 1}) xession.env.register("WOW", type=int, doc="Nice Docs!") context = parser.parse("$WO", 3) diff --git a/tests/completers/test_pip_completer.py b/tests/completers/test_pip_completer.py index 3f3b788bd..08bb9de05 100644 --- a/tests/completers/test_pip_completer.py +++ b/tests/completers/test_pip_completer.py @@ -45,13 +45,12 @@ def test_pip_list_re1(line): ["pip show", "", {"setuptools", "wheel", "pip"}], ], ) -def test_completions( - line, prefix, exp, check_completer, xession, monkeypatch, session_vars -): +def test_completions(line, prefix, exp, check_completer, xession, os_env, monkeypatch): + # use the actual PATH from os. Otherwise subproc will fail on windows. `unintialized python...` + monkeypatch.setattr(xession, "env", os_env) + if ON_WINDOWS: line = line.replace("pip", "pip.exe") - # needs original env for subproc all on all platforms - monkeypatch.setattr(xession, "env", session_vars["env"]) comps = check_completer(line, prefix=prefix) assert comps.intersection(exp) diff --git a/tests/conftest.py b/tests/conftest.py index 933b34777..8cd775f2e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,3 @@ -import builtins import os import sys import types @@ -13,11 +12,10 @@ from xonsh.completer import Completer 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 xonsh import commands_cache -from tools import DummyShell, sp, DummyEnv, DummyHistory +from tools import DummyShell, sp, DummyHistory, copy_env @pytest.fixture @@ -28,29 +26,52 @@ def source_path(): @pytest.fixture -def xonsh_execer(monkeypatch): +def xonsh_execer(monkeypatch, xonsh_session): """Initiate the Execer with a mocked nop `load_builtins`""" - execer = Execer() - XSH.load(execer=execer) - # TODO this monkeypatch *shouldn't* be useful now. - monkeypatch.setattr(XSH, "execer", execer) - yield execer + yield xonsh_session.execer + + +@pytest.fixture +def xonsh_execer_exec(xonsh_execer): + def factory(input, **kwargs): + xonsh_execer.exec(input, **kwargs) + return True + + return factory + + +@pytest.fixture +def xonsh_execer_parse(xonsh_execer): + def factory(input): + tree = XSH.execer.parse(input, ctx=None) + return tree + + return factory @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] + 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 xession.commands_cache return _factory +@pytest.fixture +def patch_locate_binary(monkeypatch): + def locate_binary(self, name): + return os.path.join(os.path.dirname(__file__), "bin", name) + + def factory(cc: commands_cache.CommandsCache): + monkeypatch.setattr(cc, "locate_binary", types.MethodType(locate_binary, cc)) + return cc + + return factory + + @pytest.fixture def monkeypatch_stderr(monkeypatch): """Monkeypath sys.stderr with no ResourceWarning.""" @@ -70,88 +91,140 @@ def xonsh_events(): @pytest.fixture(scope="session") -def session_vars(): - """keep costly vars per session""" +def session_os_env(): + """Env with values from os.environ like real session""" from xonsh.environ import Env, default_env - from xonsh.commands_cache import CommandsCache - execer = Execer() - XSH.load(execer=execer) - return { - "execer": execer, - "env": Env(default_env()), - "commands_cache": CommandsCache(), + return Env(default_env()) + + +@pytest.fixture(scope="session") +def session_env(): + """Env with some initial values that doesn't load from os.environ""" + from xonsh.environ import Env + + initial_vars = { + "UPDATE_OS_ENVIRON": False, + "XONSH_DEBUG": 1, + "XONSH_COLOR_STYLE": "default", + "VC_BRANCH_TIMEOUT": 1, + "XONSH_ENCODING": "utf-8", + "XONSH_ENCODING_ERRORS": "strict", + "COMMANDS_CACHE_SAVE_INTERMEDIATE": False, } + env = Env(initial_vars) + return env + + +@pytest.fixture(scope="session") +def session_execer(): + return Execer() @pytest.fixture -def xonsh_builtins(monkeypatch, xonsh_events, session_vars): - """Mock out most of the builtins xonsh attributes.""" - old_builtins = dict(vars(builtins).items()) # type: ignore +def os_env(session_os_env): + """A mutable copy of Original session_os_env""" - XSH.load(ctx={}, **session_vars) + return copy_env(session_os_env) - 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", 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) +@pytest.fixture +def env(tmpdir, session_env): + """a mutable copy of session_env""" + env_copy = copy_env(session_env) + initial_vars = {"XONSH_DATA_DIR": str(tmpdir)} - if ON_WINDOWS: - XSH.env["PATHEXT"] = [".EXE", ".BAT", ".CMD"] + env_copy.update(initial_vars) + return env_copy - cc = XSH.commands_cache - monkeypatch.setattr(cc, "locate_binary", types.MethodType(locate_binary, cc)) - monkeypatch.setattr(cc, "_cmds_cache", {}) - 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) +@pytest.fixture +def xonsh_session(xonsh_events, session_execer, os_env, monkeypatch) -> XonshSession: + """a fixture to use where XonshSession is fully loaded without any mocks""" - # todo: remove using builtins for tests at all - yield builtins + XSH.load( + ctx={}, + execer=session_execer, + commands_cache=commands_cache.CommandsCache(), + env=os_env, + ) + yield XSH XSH.unload() - for attr in set(dir(builtins)) - set(old_builtins): - if hasattr(builtins, attr): - delattr(builtins, attr) - for attr, old_value in old_builtins.items(): - setattr(builtins, attr, old_value) - tasks.clear() # must to this to enable resetting all_jobs @pytest.fixture -def xession(xonsh_builtins) -> XonshSession: - return XSH +def mock_xonsh_session(monkeypatch, xonsh_events, xonsh_session, env): + """Mock out most of the builtins xonsh attributes.""" + + # make sure that all other fixtures call this mock only one time + session = [] + + def factory(*attrs: str): + """ + + Parameters + ---------- + attrs + do not mock the given attributes + + Returns + ------- + XonshSession + with most of the attributes mocked out + """ + if session: + raise RuntimeError("The factory should be called only once per test") + + for attr, val in [ + ("env", env), + ("shell", DummyShell()), + ("help", lambda x: x), + ("aliases", Aliases()), + ("exit", False), + ("history", DummyHistory()), + ( + "commands_cache", + commands_cache.CommandsCache(), + ), # since env,aliases change , patch cmds-cache + # ("subproc_captured", sp), + ("subproc_uncaptured", sp), + ("subproc_captured_stdout", sp), + ("subproc_captured_inject", sp), + ("subproc_captured_object", sp), + ("subproc_captured_hiddenobject", sp), + ]: + if attr in attrs: + continue + monkeypatch.setattr(xonsh_session, attr, val) + + 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(xonsh_session.builtins, attr, val) + + session.append(xonsh_session) + return xonsh_session + + yield factory + session.clear() @pytest.fixture -def xsh_with_aliases(xession, monkeypatch): - from xonsh.aliases import Aliases, make_default_aliases +def xession(mock_xonsh_session) -> XonshSession: + """Mock out most of the builtins xonsh attributes.""" + return mock_xonsh_session() - xsh = xession - monkeypatch.setattr(xsh, "aliases", Aliases(make_default_aliases())) - return xsh + +@pytest.fixture +def xsh_with_aliases(mock_xonsh_session) -> XonshSession: + return mock_xonsh_session("aliases") @pytest.fixture(scope="session") @@ -160,7 +233,7 @@ def completion_context_parse(): @pytest.fixture -def check_completer(xession): +def check_completer(): """Helper function to run completer and parse the results as set of strings""" completer = Completer() diff --git a/tests/procs/test_specs.py b/tests/procs/test_specs.py index dcc92a2ee..b7152c199 100644 --- a/tests/procs/test_specs.py +++ b/tests/procs/test_specs.py @@ -6,7 +6,6 @@ from subprocess import Popen import pytest from xonsh.procs.specs import cmds_to_specs, run_subproc -from xonsh.built_ins import XSH from xonsh.procs.posix import PopenThread from xonsh.procs.proxies import ProcProxy, ProcProxyThread, STDOUT_DISPATCHER @@ -49,8 +48,8 @@ def test_cmds_to_specs_thread_subproc(xession): @pytest.mark.parametrize("thread_subprocs", [True, False]) -def test_cmds_to_specs_capture_stdout_not_stderr(thread_subprocs): - env = XSH.env +def test_cmds_to_specs_capture_stdout_not_stderr(thread_subprocs, xonsh_session): + env = xonsh_session.env cmds = (["ls", "/root"],) env["THREAD_SUBPROCS"] = thread_subprocs @@ -68,7 +67,7 @@ def test_cmds_to_specs_capture_stdout_not_stderr(thread_subprocs): ) @pytest.mark.flaky(reruns=5, reruns_delay=2) def test_capture_always( - capfd, thread_subprocs, capture_always, alias_type, pipe, monkeypatch + capfd, thread_subprocs, capture_always, alias_type, pipe, monkeypatch, xonsh_session ): if not thread_subprocs and alias_type in ["func", "exec"]: if pipe: @@ -76,7 +75,7 @@ def test_capture_always( else: return pytest.skip("https://github.com/xonsh/xonsh/issues/4444") - env = XSH.env + env = xonsh_session.env exp = "HELLO\nBYE\n" cmds = [["echo", "-n", exp]] if pipe: @@ -88,15 +87,15 @@ def test_capture_always( # Enable capfd for function aliases: monkeypatch.setattr(STDOUT_DISPATCHER, "default", sys.stdout) if alias_type == "func": - XSH.aliases["tst"] = ( + xonsh_session.aliases["tst"] = ( lambda: run_subproc([first_cmd], "hiddenobject") and None ) # Don't return a value elif alias_type == "exec": first_cmd = " ".join(repr(arg) for arg in first_cmd) - XSH.aliases["tst"] = f"![{first_cmd}]" + xonsh_session.aliases["tst"] = f"![{first_cmd}]" else: # alias_type == "simple" - XSH.aliases["tst"] = first_cmd + xonsh_session.aliases["tst"] = first_cmd cmds[0] = ["tst"] diff --git a/tests/prompt/test_base.py b/tests/prompt/test_base.py index 55251cbeb..f3ea08977 100644 --- a/tests/prompt/test_base.py +++ b/tests/prompt/test_base.py @@ -2,7 +2,6 @@ from unittest.mock import Mock import pytest -from xonsh.environ import Env from xonsh.prompt.base import PromptFormatter, PROMPT_FIELDS @@ -76,8 +75,6 @@ def test_format_prompt_with_broken_template_in_func(inp, formatter): def test_format_prompt_with_invalid_func(formatter, xession): - xession.env = Env() - def p(): foo = bar # raises exception # noqa return "{user}" @@ -86,7 +83,6 @@ def test_format_prompt_with_invalid_func(formatter, xession): 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,13 +92,11 @@ def test_format_prompt_with_func_that_raises(formatter, capsys, xession): assert "prompt: error" in err -def test_format_prompt_with_no_env(formatter, xession, live_fields): +def test_format_prompt_with_no_env(formatter, xession, live_fields, env): xession.shell.prompt_formatter = formatter - env = Env() env.pop("VIRTUAL_ENV", None) # For virtualenv env.pop("CONDA_DEFAULT_ENV", None) # For conda/CircleCI - xession.env = env assert formatter("{env_name}", fields=live_fields) == "" @@ -111,8 +105,7 @@ def test_format_prompt_with_no_env(formatter, xession, live_fields): def test_format_prompt_with_various_envs(formatter, xession, live_fields, envname): xession.shell.prompt_formatter = formatter - env = Env(VIRTUAL_ENV=envname) - xession.env = env + xession.env["VIRTUAL_ENV"] = envname exp = live_fields["env_prefix"] + envname + live_fields["env_postfix"] assert formatter("{env_name}", fields=live_fields) == exp @@ -123,8 +116,7 @@ def test_format_prompt_with_various_envs(formatter, xession, live_fields, envnam def test_format_prompt_with_various_prepost(formatter, xession, live_fields, pre, post): xession.shell.prompt_formatter = formatter - env = Env(VIRTUAL_ENV="env") - xession.env = env + xession.env["VIRTUAL_ENV"] = "env" live_fields.update({"env_prefix": pre, "env_postfix": post}) @@ -134,9 +126,7 @@ def test_format_prompt_with_various_prepost(formatter, xession, live_fields, pre 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) - xession.env = env + xession.env.update(dict(VIRTUAL_ENV="env", VIRTUAL_ENV_DISABLE_PROMPT=1)) exp = "" assert formatter("{env_name}", fields=live_fields) == exp @@ -148,10 +138,13 @@ def test_custom_env_overrides_default(formatter, xession, live_fields, disable): prompt = "!venv active! " - env = Env( - VIRTUAL_ENV="env", VIRTUAL_ENV_PROMPT=prompt, VIRTUAL_ENV_DISABLE_PROMPT=disable + xession.env.update( + dict( + VIRTUAL_ENV="env", + VIRTUAL_ENV_PROMPT=prompt, + VIRTUAL_ENV_DISABLE_PROMPT=disable, + ) ) - xession.env = env exp = "" if disable else prompt assert formatter("{env_name}", fields=live_fields) == exp diff --git a/tests/prompt/test_cwd.py b/tests/prompt/test_cwd.py index 977a64b09..cbf3f081d 100644 --- a/tests/prompt/test_cwd.py +++ b/tests/prompt/test_cwd.py @@ -1,16 +1,16 @@ from xonsh.prompt.cwd import _replace_home_cwd -from xonsh.built_ins import XSH -def test_cwd_escapes_curly_brackets_with_more_curly_brackets(): - XSH.env["PWD"] = "{foo}" +def test_cwd_escapes_curly_brackets_with_more_curly_brackets(xession, tmpdir): + xession.env["HOME"] = str(tmpdir) + xession.env["PWD"] = "{foo}" assert _replace_home_cwd() == "{{foo}}" - XSH.env["PWD"] = "{{foo}}" + xession.env["PWD"] = "{{foo}}" assert _replace_home_cwd() == "{{{{foo}}}}" - XSH.env["PWD"] = "{" + xession.env["PWD"] = "{" assert _replace_home_cwd() == "{{" - XSH.env["PWD"] = "}}" + xession.env["PWD"] = "}}" assert _replace_home_cwd() == "}}}}" diff --git a/tests/prompt/test_gitstatus.py b/tests/prompt/test_gitstatus.py index c82a802c1..092969be4 100644 --- a/tests/prompt/test_gitstatus.py +++ b/tests/prompt/test_gitstatus.py @@ -3,6 +3,11 @@ import pytest from xonsh.prompt import gitstatus +@pytest.fixture(autouse=True) +def git_no_stash(mocker): + return mocker.patch.object(gitstatus, "_get_stash", return_value=0) + + @pytest.mark.parametrize( "hidden, exp", [ diff --git a/tests/prompt/test_vc.py b/tests/prompt/test_vc.py index b5c5bed32..b32091044 100644 --- a/tests/prompt/test_vc.py +++ b/tests/prompt/test_vc.py @@ -5,7 +5,6 @@ from unittest.mock import Mock import pytest -from xonsh.environ import Env from xonsh.prompt import vc # Xonsh interaction with version control systems. @@ -46,7 +45,7 @@ defaultBranch = main @pytest.fixture def set_xenv(xession, monkeypatch): def _wrapper(path): - monkeypatch.setattr(xession, "env", Env(VC_BRANCH_TIMEOUT=2, PWD=path)) + xession.env.update(dict(VC_BRANCH_TIMEOUT=2, PWD=path)) return xession return _wrapper diff --git a/tests/test_aliases.py b/tests/test_aliases.py index 28a779cd1..f2b21f1ca 100644 --- a/tests/test_aliases.py +++ b/tests/test_aliases.py @@ -6,7 +6,6 @@ import pytest import inspect from xonsh.aliases import Aliases, ExecAlias -from xonsh.environ import Env from tools import skip_if_on_windows @@ -26,7 +25,7 @@ def make_aliases(): return ales -def test_imports(xonsh_builtins): +def test_imports(xession): ales = make_aliases() expected = { "o": ["omg", "lala"], @@ -39,17 +38,17 @@ def test_imports(xonsh_builtins): assert raw == expected -def test_eval_normal(xonsh_builtins): +def test_eval_normal(xession): ales = make_aliases() assert ales.get("o") == ["omg", "lala"] -def test_eval_self_reference(xonsh_builtins): +def test_eval_self_reference(xession): ales = make_aliases() assert ales.get("ls") == ["ls", "- -"] -def test_eval_recursive(xonsh_builtins): +def test_eval_recursive(xession): ales = make_aliases() assert ales.get("color_ls") == ["ls", "- -", "--color=true"] @@ -57,7 +56,7 @@ def test_eval_recursive(xonsh_builtins): @skip_if_on_windows def test_eval_recursive_callable_partial(xonsh_execer, xession): ales = make_aliases() - xession.env = Env(HOME=os.path.expanduser("~")) + xession.env["HOME"] = os.path.expanduser("~") assert ales.get("indirect_cd")(["arg2", "arg3"]) == ["..", "arg2", "arg3"] @@ -74,7 +73,7 @@ def _return_to_sender_all(args, stdin, stdout, stderr, spec, stack): ) -def test_recursive_callable_partial_all(xonsh_builtins): +def test_recursive_callable_partial_all(xession): ales = Aliases({"rtn": _return_to_sender_all, "rtn-recurse": ["rtn", "arg1"]}) alias = ales.get("rtn-recurse") assert callable(alias) @@ -89,7 +88,7 @@ def _return_to_sender_handles(args, stdin, stdout, stderr): return args, {"stdin": stdin, "stdout": stdout, "stderr": stderr} -def test_recursive_callable_partial_handles(xonsh_builtins): +def test_recursive_callable_partial_handles(xession): ales = Aliases({"rtn": _return_to_sender_handles, "rtn-recurse": ["rtn", "arg1"]}) alias = ales.get("rtn-recurse") assert callable(alias) @@ -104,7 +103,7 @@ def _return_to_sender_none(): return "wakka", {} -def test_recursive_callable_partial_none(xonsh_builtins): +def test_recursive_callable_partial_none(xession): ales = Aliases({"rtn": _return_to_sender_none, "rtn-recurse": ["rtn"]}) alias = ales.get("rtn-recurse") assert callable(alias) @@ -123,7 +122,7 @@ def test_recursive_callable_partial_none(xonsh_builtins): "echo 'hi'; echo 'there'", ], ) -def test_subprocess_logical_operators(xonsh_builtins, alias): +def test_subprocess_logical_operators(xession, alias): ales = make_aliases() ales["echocat"] = alias assert isinstance(ales["echocat"], ExecAlias) @@ -140,7 +139,7 @@ def test_subprocess_logical_operators(xonsh_builtins, alias): "echo 'h|i << x > 3' | grep x", ], ) -def test_subprocess_io_operators(xonsh_builtins, alias): +def test_subprocess_io_operators(xession, alias): ales = make_aliases() ales["echocat"] = alias assert isinstance(ales["echocat"], ExecAlias) @@ -152,7 +151,7 @@ def test_subprocess_io_operators(xonsh_builtins, alias): {"echocat": "ls"}, ], ) -def test_dict_merging(xonsh_builtins, alias): +def test_dict_merging(xession, alias): ales = make_aliases() assert (ales | alias)["echocat"] == ["ls"] assert (alias | ales)["echocat"] == ["ls"] @@ -166,7 +165,7 @@ def test_dict_merging(xonsh_builtins, alias): {"echocat": "echo Why?"}, ], ) -def test_dict_merging_assignment(xonsh_builtins, alias): +def test_dict_merging_assignment(xession, alias): ales = make_aliases() ales |= alias @@ -180,7 +179,7 @@ def test_dict_merging_assignment(xonsh_builtins, alias): assert alias["o"] == ales["o"] -def test_exec_alias_args(xonsh_builtins): +def test_exec_alias_args(xession): stack = inspect.stack() try: ExecAlias("myargs = $args")(["arg0"], stack=stack) diff --git a/tests/test_ast.py b/tests/test_ast.py index 084d2bde8..31ad5a456 100644 --- a/tests/test_ast.py +++ b/tests/test_ast.py @@ -6,7 +6,7 @@ from xonsh.ast import Tuple, Name, Store, min_line, Call, BinOp, isexpression import pytest -from tools import check_parse, nodes_equal +from tools import nodes_equal @pytest.fixture(autouse=True) @@ -45,20 +45,20 @@ def test_gather_load_store_names_tuple(): "l = 1", # ls remains undefined. ], ) -def test_multilline_num(xonsh_execer, line1): +def test_multilline_num(xonsh_execer_parse, line1): # Subprocess transformation happens on the second line, # because not all variables are known. code = line1 + "\nls -l\n" - tree = check_parse(code) + tree = xonsh_execer_parse(code) lsnode = tree.body[1] assert 2 == min_line(lsnode) assert isinstance(lsnode.value, Call) -def test_multilline_no_transform(): +def test_multilline_no_transform(xonsh_execer_parse): # No subprocess transformations happen here, since all variables are known. code = "ls = 1\nl = 1\nls -l\n" - tree = check_parse(code) + tree = xonsh_execer_parse(code) lsnode = tree.body[2] assert 3 == min_line(lsnode) assert isinstance(lsnode.value, BinOp) @@ -109,10 +109,10 @@ for root, dirs, files in os.walk(path): """, ], ) -def test_unmodified(inp): +def test_unmodified(inp, xonsh_execer_parse): # Context sensitive parsing should not modify AST exp = pyast.parse(inp) - obs = check_parse(inp) + obs = xonsh_execer_parse(inp) assert nodes_equal(exp, obs) @@ -121,8 +121,8 @@ def test_unmodified(inp): "test_input", ["echo; echo && echo\n", "echo; echo && echo a\n", "true && false && true\n"], ) -def test_whitespace_subproc(test_input): - assert check_parse(test_input) +def test_whitespace_subproc(test_input, xonsh_execer_parse): + assert xonsh_execer_parse(test_input) @pytest.mark.parametrize( diff --git a/tests/test_base_shell.py b/tests/test_base_shell.py index 80bdc9b3f..2335d6ba6 100644 --- a/tests/test_base_shell.py +++ b/tests/test_base_shell.py @@ -1,7 +1,6 @@ """(A down payment on) Testing for ``xonsh.base_shell.BaseShell`` and associated classes""" import os -from xonsh.environ import Env from xonsh.base_shell import BaseShell from xonsh.shell import transform_command @@ -9,8 +8,8 @@ from xonsh.shell import transform_command def test_pwd_tracks_cwd(xession, xonsh_execer, tmpdir_factory, monkeypatch): asubdir = str(tmpdir_factory.mktemp("asubdir")) cur_wd = os.getcwd() - xession.env = Env( - PWD=cur_wd, XONSH_CACHE_SCRIPTS=False, XONSH_CACHE_EVERYTHING=False + xession.env.update( + dict(PWD=cur_wd, XONSH_CACHE_SCRIPTS=False, XONSH_CACHE_EVERYTHING=False) ) monkeypatch.setattr(xonsh_execer, "cacheall", False, raising=False) diff --git a/tests/test_builtins.py b/tests/test_builtins.py index c901d5071..b31cb2483 100644 --- a/tests/test_builtins.py +++ b/tests/test_builtins.py @@ -42,7 +42,7 @@ def test_reglob_tests(testfile): @pytest.fixture def home_env(xession): """Set `__xonsh__.env ` to a new Env instance on `xonsh_builtins`""" - xession.env = Env(HOME=HOME_PATH) + xession.env["HOME"] = HOME_PATH return xession @@ -146,7 +146,7 @@ def test_list_of_strs_or_callables(exp, inp): ([["y", "z"], ["a", "b"]], ["ya", "yb", "za", "zb"]), ], ) -def test_list_of_list_of_strs_outer_product(xonsh_builtins, inp, exp): +def test_list_of_list_of_strs_outer_product(xession, inp, exp): obs = list_of_list_of_strs_outer_product(inp) assert exp == obs diff --git a/tests/test_commands_cache.py b/tests/test_commands_cache.py index 539da2503..c5510c350 100644 --- a/tests/test_commands_cache.py +++ b/tests/test_commands_cache.py @@ -15,27 +15,25 @@ from xonsh.commands_cache import ( from tools import skip_if_on_windows -def test_commands_cache_lazy(xonsh_builtins): - cc = CommandsCache() +def test_commands_cache_lazy(xession): + cc = xession.commands_cache assert not cc.lazyin("xonsh") assert 0 == len(list(cc.lazyiter())) assert 0 == cc.lazylen() -def test_predict_threadable_unknown_command(xonsh_builtins): - cc = CommandsCache() - result = cc.predict_threadable(["command_should_not_found"]) +def test_predict_threadable_unknown_command(xession): + result = xession.commands_cache.predict_threadable(["command_should_not_found"]) assert isinstance(result, bool) @pytest.fixture 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): +def test_commands_cached_between_runs(commands_cache_tmp, tmp_path, tmpdir): # 1. no pickle file # 2. return empty result first and create a thread to populate result # 3. once the result is available then next call to cc.all_commands returns @@ -76,6 +74,7 @@ def test_commands_cache_uses_pickle_file(commands_cache_tmp, tmp_path, monkeypat } file.write_bytes(pickle.dumps(bins)) + assert str(cc.cache_file) == str(file) assert cc.all_commands == bins assert cc._loaded_pickled @@ -112,14 +111,38 @@ def test_predict_shell_false(args): PATTERN_BIN_USING_TTY_OR_NOT = [ - (False, {10: b"isnotatty"}), - (False, {12: b"isatty"}), - (False, {151: b"gpm"}), - (False, {10: b"isatty", 100: b"tcgetattr"}), - (False, {10: b"isatty", 100: b"tcsetattr"}), - (True, {10: b"isatty", 100: b"tcsetattr", 1000: b"tcgetattr"}), - (True, {1000: b"libncurses"}), - (True, {4094: b"libgpm"}), + ( + False, + {10: b"isnotatty"}, + ), + ( + False, + {12: b"isatty"}, + ), + ( + False, + {151: b"gpm"}, + ), + ( + False, + {10: b"isatty", 100: b"tcgetattr"}, + ), + ( + False, + {10: b"isatty", 100: b"tcsetattr"}, + ), + ( + True, + {10: b"isatty", 100: b"tcsetattr", 1000: b"tcgetattr"}, + ), + ( + True, + {1000: b"libncurses"}, + ), + ( + True, + {4094: b"libgpm"}, + ), ( True, {2045: b"tcgetattr", 4095: b"tcgetattr", 6140: b"tcsetattr", 8190: b"isatty"}, @@ -129,24 +152,23 @@ PATTERN_BIN_USING_TTY_OR_NOT = [ @pytest.mark.parametrize("args", PATTERN_BIN_USING_TTY_OR_NOT) @skip_if_on_windows -def test_commands_cache_predictor_default(args, xonsh_builtins): - cc = CommandsCache() +def test_commands_cache_predictor_default(args, xession, tmp_path): use_tty, patterns = args - f = open("testfile", "wb") + file = tmp_path / "testfile" where = list(patterns.keys()) where.sort() - pos = 0 - for w in where: - f.write(b"\x20" * (w - pos)) - f.write(patterns[w]) - pos = w + len(patterns[w]) + with file.open("wb") as f: + pos = 0 + for w in where: + f.write(b"\x20" * (w - pos)) + f.write(patterns[w]) + pos = w + len(patterns[w]) - f.write(b"\x20" * (pos // 2)) - f.close() + f.write(b"\x20" * (pos // 2)) - result = cc.default_predictor_readbin( - "", os.getcwd() + os.sep + "testfile", timeout=1, failure=None + result = xession.commands_cache.default_predictor_readbin( + "", str(file), timeout=1, failure=None ) expected = predict_false if use_tty else predict_true assert result == expected @@ -154,26 +176,23 @@ def test_commands_cache_predictor_default(args, xonsh_builtins): @skip_if_on_windows def test_cd_is_only_functional_alias(xession): - cc = CommandsCache() xession.aliases["cd"] = lambda args: os.chdir(args[0]) - assert cc.is_only_functional_alias("cd") + xession.env["PATH"] = [] + assert xession.commands_cache.is_only_functional_alias("cd") -def test_non_exist_is_only_functional_alias(xonsh_builtins): - cc = CommandsCache() - assert not cc.is_only_functional_alias("") +def test_non_exist_is_only_functional_alias(xession): + assert not xession.commands_cache.is_only_functional_alias( + "" + ) @skip_if_on_windows 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") + assert not xession.commands_cache.is_only_functional_alias("bash") @skip_if_on_windows def test_bash_and_is_alias_is_only_functional_alias(xession): - xession.env["PATH"] = os.environ["PATH"].split(os.pathsep) - cc = CommandsCache() xession.aliases["bash"] = lambda args: os.chdir(args[0]) - assert not cc.is_only_functional_alias("bash") + assert not xession.commands_cache.is_only_functional_alias("bash") diff --git a/tests/test_completion_context.py b/tests/test_completion_context.py index 1437c739f..55011ca7d 100644 --- a/tests/test_completion_context.py +++ b/tests/test_completion_context.py @@ -2,7 +2,7 @@ import itertools import typing as tp import pytest - +from unittest import mock from xonsh.parsers.completion_context import ( CommandArg, CommandContext, @@ -10,6 +10,9 @@ from xonsh.parsers.completion_context import ( PythonContext, ) +import xonsh.parsers.completion_context as ctx +from tests.tools import ON_WINDOWS + DEBUG = False MISSING = object() @@ -21,8 +24,19 @@ PARSER: tp.Optional[CompletionContextParser] = None def parser(): global PARSER PARSER = CompletionContextParser(debug=DEBUG) + patcher = None + if ON_WINDOWS: + # on-windows has an option for interactive sessions. Overriding the lazyObject + patcher = mock.patch.object( + ctx, + "LINE_CONT_REPLACEMENT_DIFF", + ("\\\n", "", -2), + ) + patcher.start() yield PARSER = None + if ON_WINDOWS and patcher: + patcher.stop() def parse(command, inner_index): diff --git a/tests/test_contexts.py b/tests/test_contexts.py index 06d6c6786..3d75ca151 100644 --- a/tests/test_contexts.py +++ b/tests/test_contexts.py @@ -1,16 +1,8 @@ """Tests xonsh contexts.""" from textwrap import dedent -from tools import check_exec from xonsh.contexts import Block, Functor -import pytest - - -@pytest.fixture(autouse=True) -def xonsh_execer_autouse(xonsh_builtins, xonsh_execer): - return xonsh_execer - # # helpers @@ -75,64 +67,64 @@ def block_checks_func(name, glbs, body, obsg=None, obsl=None): # -def test_block_noexec(): +def test_block_noexec(xonsh_execer_exec): s = "x = 1\n" "with! Block():\n" " x += 42\n" glbs = {"Block": Block} - check_exec(s, glbs=glbs, locs=None) + xonsh_execer_exec(s, glbs=glbs, locs=None) assert 1 == glbs["x"] -def test_block_oneline(): +def test_block_oneline(xonsh_execer_exec): body = " x += 42\n" s = X1_WITH + body glbs = {"Block": Block} - check_exec(s, glbs=glbs, locs=None) + xonsh_execer_exec(s, glbs=glbs, locs=None) block_checks_glb("b", glbs, body, {"x": 1}) -def test_block_manylines(): +def test_block_manylines(xonsh_execer_exec): body = " ![echo wow mom]\n" "# bad place for a comment\n" " x += 42" s = X1_WITH + body glbs = {"Block": Block} - check_exec(s, glbs=glbs, locs=None) + xonsh_execer_exec(s, glbs=glbs, locs=None) block_checks_glb("b", glbs, body, {"x": 1}) -def test_block_leading_comment(): +def test_block_leading_comment(xonsh_execer_exec): # leading comments do not show up in block lines body = " # I am a leading comment\n" " x += 42\n" s = X1_WITH + body glbs = {"Block": Block} - check_exec(s, glbs=glbs, locs=None) + xonsh_execer_exec(s, glbs=glbs, locs=None) block_checks_glb("b", glbs, [" x += 42"], {"x": 1}) -def test_block_trailing_comment(): +def test_block_trailing_comment(xonsh_execer_exec): # trailing comments show up in block lines body = " x += 42\n" " # I am a trailing comment\n" s = X1_WITH + body glbs = {"Block": Block} - check_exec(s, glbs=glbs, locs=None) + xonsh_execer_exec(s, glbs=glbs, locs=None) block_checks_glb("b", glbs, body, {"x": 1}) -def test_block_trailing_line_continuation(): +def test_block_trailing_line_continuation(xonsh_execer_exec): body = " x += \\\n" " 42\n" s = X1_WITH + body glbs = {"Block": Block} - check_exec(s, glbs=glbs, locs=None) + xonsh_execer_exec(s, glbs=glbs, locs=None) block_checks_glb("b", glbs, body, {"x": 1}) -def test_block_trailing_close_paren(): +def test_block_trailing_close_paren(xonsh_execer_exec): body = ' x += int("42"\n' " )\n" s = X1_WITH + body glbs = {"Block": Block} - check_exec(s, glbs=glbs, locs=None) + xonsh_execer_exec(s, glbs=glbs, locs=None) block_checks_glb("b", glbs, body, {"x": 1}) -def test_block_trailing_close_many(): +def test_block_trailing_close_many(xonsh_execer_exec): body = ( ' x = {None: [int("42"\n' " )\n" @@ -141,69 +133,69 @@ def test_block_trailing_close_many(): ) s = SIMPLE_WITH + body glbs = {"Block": Block} - check_exec(s, glbs=glbs, locs=None) + xonsh_execer_exec(s, glbs=glbs, locs=None) block_checks_glb("b", glbs, body) -def test_block_trailing_triple_string(): +def test_block_trailing_triple_string(xonsh_execer_exec): body = ' x = """This\n' "is\n" '"probably"\n' "'not' what I meant.\n" '"""\n' s = SIMPLE_WITH + body glbs = {"Block": Block} - check_exec(s, glbs=glbs, locs=None) + xonsh_execer_exec(s, glbs=glbs, locs=None) block_checks_glb("b", glbs, body) -def test_block_func_oneline(): +def test_block_func_oneline(xonsh_execer_exec): body = " x += 42\n" s = FUNC_WITH.format(body=body) glbs = {"Block": Block} - check_exec(s, glbs=glbs, locs=None) + xonsh_execer_exec(s, glbs=glbs, locs=None) block_checks_func("rtn", glbs, body, FUNC_OBSG, FUNC_OBSL) -def test_block_func_manylines(): +def test_block_func_manylines(xonsh_execer_exec): body = " ![echo wow mom]\n" "# bad place for a comment\n" " x += 42\n" s = FUNC_WITH.format(body=body) glbs = {"Block": Block} - check_exec(s, glbs=glbs, locs=None) + xonsh_execer_exec(s, glbs=glbs, locs=None) block_checks_func("rtn", glbs, body, FUNC_OBSG, FUNC_OBSL) -def test_block_func_leading_comment(): +def test_block_func_leading_comment(xonsh_execer_exec): # leading comments do not show up in block lines body = " # I am a leading comment\n" " x += 42\n" s = FUNC_WITH.format(body=body) glbs = {"Block": Block} - check_exec(s, glbs=glbs, locs=None) + xonsh_execer_exec(s, glbs=glbs, locs=None) block_checks_func("rtn", glbs, " x += 42\n", FUNC_OBSG, FUNC_OBSL) -def test_block_func_trailing_comment(): +def test_block_func_trailing_comment(xonsh_execer_exec): # trailing comments show up in block lines body = " x += 42\n" " # I am a trailing comment\n" s = FUNC_WITH.format(body=body) glbs = {"Block": Block} - check_exec(s, glbs=glbs, locs=None) + xonsh_execer_exec(s, glbs=glbs, locs=None) block_checks_func("rtn", glbs, body, FUNC_OBSG, FUNC_OBSL) -def test_blockfunc__trailing_line_continuation(): +def test_blockfunc__trailing_line_continuation(xonsh_execer_exec): body = " x += \\\n" " 42\n" s = FUNC_WITH.format(body=body) glbs = {"Block": Block} - check_exec(s, glbs=glbs, locs=None) + xonsh_execer_exec(s, glbs=glbs, locs=None) block_checks_func("rtn", glbs, body, FUNC_OBSG, FUNC_OBSL) -def test_block_func_trailing_close_paren(): +def test_block_func_trailing_close_paren(xonsh_execer_exec): body = ' x += int("42"\n' " )\n" s = FUNC_WITH.format(body=body) glbs = {"Block": Block} - check_exec(s, glbs=glbs, locs=None) + xonsh_execer_exec(s, glbs=glbs, locs=None) block_checks_func("rtn", glbs, body, FUNC_OBSG, FUNC_OBSL) -def test_block_func_trailing_close_many(): +def test_block_func_trailing_close_many(xonsh_execer_exec): body = ( ' x = {None: [int("42"\n' " )\n" @@ -212,15 +204,15 @@ def test_block_func_trailing_close_many(): ) s = FUNC_WITH.format(body=body) glbs = {"Block": Block} - check_exec(s, glbs=glbs, locs=None) + xonsh_execer_exec(s, glbs=glbs, locs=None) block_checks_func("rtn", glbs, body, FUNC_OBSG, FUNC_OBSL) -def test_block_func_trailing_triple_string(): +def test_block_func_trailing_triple_string(xonsh_execer_exec): body = ' x = """This\n' "is\n" '"probably"\n' "'not' what I meant.\n" '"""\n' s = FUNC_WITH.format(body=body) glbs = {"Block": Block} - check_exec(s, glbs=glbs, locs=None) + xonsh_execer_exec(s, glbs=glbs, locs=None) block_checks_func("rtn", glbs, body, FUNC_OBSG, FUNC_OBSL) @@ -231,55 +223,55 @@ def test_block_func_trailing_triple_string(): X2_WITH = "{var} = 1\n" "with! Functor() as f:\n" "{body}" "{var} += 1\n" "{calls}\n" -def test_functor_oneline_onecall_class(): +def test_functor_oneline_onecall_class(xonsh_execer_exec): body = " global y\n" " y += 42\n" calls = "f()" s = X2_WITH.format(body=body, calls=calls, var="y") glbs = {"Functor": Functor} - check_exec(s, glbs=glbs, locs=None) + xonsh_execer_exec(s, glbs=glbs, locs=None) block_checks_glb("f", glbs, body, {"y": 44}) -def test_functor_oneline_onecall_func(): +def test_functor_oneline_onecall_func(xonsh_execer_exec): body = " global z\n" " z += 42\n" calls = "f.func()" s = X2_WITH.format(body=body, calls=calls, var="z") glbs = {"Functor": Functor} - check_exec(s, glbs=glbs, locs=None) + xonsh_execer_exec(s, glbs=glbs, locs=None) block_checks_glb("f", glbs, body, {"z": 44}) -def test_functor_oneline_onecall_both(): +def test_functor_oneline_onecall_both(xonsh_execer_exec): body = " global x\n" " x += 42\n" calls = "f()\nf.func()" s = X2_WITH.format(body=body, calls=calls, var="x") glbs = {"Functor": Functor} - check_exec(s, glbs=glbs, locs=None) + xonsh_execer_exec(s, glbs=glbs, locs=None) block_checks_glb("f", glbs, body, {"x": 86}) XA_WITH = "x = [1]\n" "with! Functor() as f:\n" "{body}" "x.append(2)\n" "{calls}\n" -def test_functor_oneline_append(): +def test_functor_oneline_append(xonsh_execer_exec): body = " x.append(3)\n" calls = "f()\n" s = XA_WITH.format(body=body, calls=calls) glbs = {"Functor": Functor} - check_exec(s, glbs=glbs, locs=None) + xonsh_execer_exec(s, glbs=glbs, locs=None) block_checks_glb("f", glbs, body, {"x": [1, 2, 3]}) -def test_functor_return(): +def test_functor_return(xonsh_execer_exec): body = " x = 42" t = "res = 0\n" 'with! Functor(rtn="x") as f:\n' "{body}\n" "res = f()\n" s = t.format(body=body) glbs = {"Functor": Functor} - check_exec(s, glbs=glbs, locs=None) + xonsh_execer_exec(s, glbs=glbs, locs=None) block_checks_glb("f", glbs, body, {"res": 42}) -def test_functor_args(): +def test_functor_args(xonsh_execer_exec): body = " x = 42 + a" t = ( "res = 0\n" @@ -289,11 +281,11 @@ def test_functor_args(): ) s = t.format(body=body) glbs = {"Functor": Functor} - check_exec(s, glbs=glbs, locs=None) + xonsh_execer_exec(s, glbs=glbs, locs=None) block_checks_glb("f", glbs, body, {"res": 44}) -def test_functor_kwargs(): +def test_functor_kwargs(xonsh_execer_exec): body = " x = 42 + a + b" t = ( "res = 0\n" @@ -303,11 +295,11 @@ def test_functor_kwargs(): ) s = t.format(body=body) glbs = {"Functor": Functor} - check_exec(s, glbs=glbs, locs=None) + xonsh_execer_exec(s, glbs=glbs, locs=None) block_checks_glb("f", glbs, body, {"res": 49}) -def test_functor_fullsig(): +def test_functor_fullsig(xonsh_execer_exec): body = " x = 42 + a + b + c" t = ( "res = 0\n" @@ -317,5 +309,5 @@ def test_functor_fullsig(): ) s = t.format(body=body) glbs = {"Functor": Functor} - check_exec(s, glbs=glbs, locs=None) + xonsh_execer_exec(s, glbs=glbs, locs=None) block_checks_glb("f", glbs, body, {"res": 110}) diff --git a/tests/test_dirstack.py b/tests/test_dirstack.py index e19816c43..47b0eaec9 100644 --- a/tests/test_dirstack.py +++ b/tests/test_dirstack.py @@ -6,7 +6,6 @@ import os import pytest # noqa F401 from xonsh import dirstack -from xonsh.environ import Env HERE = os.path.abspath(os.path.dirname(__file__)) @@ -22,7 +21,7 @@ def chdir(adir): def test_simple(xession): - xession.env = Env(CDPATH=PARENT, PWD=PARENT) + xession.env.update(dict(CDPATH=PARENT, PWD=PARENT)) with chdir(PARENT): assert os.getcwd() != HERE dirstack.cd(["tests"]) @@ -30,7 +29,7 @@ def test_simple(xession): def test_cdpath_simple(xession): - xession.env = Env(CDPATH=PARENT, PWD=HERE) + xession.env.update(dict(CDPATH=PARENT, PWD=HERE)) with chdir(os.path.normpath("/")): assert os.getcwd() != HERE dirstack.cd(["tests"]) @@ -38,7 +37,7 @@ def test_cdpath_simple(xession): def test_cdpath_collision(xession): - xession.env = Env(CDPATH=PARENT, PWD=HERE) + xession.env.update(dict(CDPATH=PARENT, PWD=HERE)) sub_tests = os.path.join(HERE, "tests") if not os.path.exists(sub_tests): os.mkdir(sub_tests) @@ -49,7 +48,7 @@ def test_cdpath_collision(xession): def test_cdpath_expansion(xession): - xession.env = Env(HERE=HERE, CDPATH=("~", "$HERE")) + xession.env.update(dict(HERE=HERE, CDPATH=("~", "$HERE"))) test_dirs = ( os.path.join(HERE, "xonsh-test-cdpath-here"), os.path.expanduser("~/xonsh-test-cdpath-home"), @@ -68,7 +67,7 @@ def test_cdpath_expansion(xession): def test_cdpath_events(xession, tmpdir): - xession.env = Env(CDPATH=PARENT, PWD=os.getcwd()) + xession.env.update(dict(CDPATH=PARENT, PWD=os.getcwd())) target = str(tmpdir) ev = None @@ -91,7 +90,7 @@ def test_cdpath_events(xession, tmpdir): def test_cd_autopush(xession, tmpdir): - xession.env = Env(CDPATH=PARENT, PWD=os.getcwd(), AUTO_PUSHD=True) + xession.env.update(dict(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 64ae519dd..b1b02d669 100644 --- a/tests/test_dirstack_unc.py +++ b/tests/test_dirstack_unc.py @@ -8,7 +8,6 @@ import sys import pytest from xonsh import dirstack -from xonsh.environ import Env from xonsh.dirstack import DIRSTACK from xonsh.platform import ON_WINDOWS from xonsh.dirstack import _unc_tempDrives @@ -93,7 +92,7 @@ def shares_setup(tmpdir_factory): def test_pushdpopd(xession): """Simple non-UNC push/pop to verify we didn't break nonUNC case.""" - xession.env = Env(CDPATH=PARENT, PWD=HERE) + xession.env.update(dict(CDPATH=PARENT, PWD=HERE)) dirstack.cd([PARENT]) owd = os.getcwd() @@ -106,7 +105,7 @@ def test_pushdpopd(xession): def test_cd_dot(xession): - xession.env = Env(PWD=os.getcwd()) + xession.env.update(dict(PWD=os.getcwd())) owd = os.getcwd().casefold() dirstack.cd(["."]) @@ -117,7 +116,7 @@ def test_cd_dot(xession): def test_uncpushd_simple_push_pop(xession, shares_setup): if shares_setup is None: return - xession.env = Env(CDPATH=PARENT, PWD=HERE) + xession.env.update(dict(CDPATH=PARENT, PWD=HERE)) dirstack.cd([PARENT]) owd = os.getcwd() assert owd.casefold() == xession.env["PWD"].casefold() @@ -134,7 +133,7 @@ def test_uncpushd_simple_push_pop(xession, shares_setup): def test_uncpushd_push_to_same_share(xession, shares_setup): if shares_setup is None: return - xession.env = Env(CDPATH=PARENT, PWD=HERE) + xession.env.update(dict(CDPATH=PARENT, PWD=HERE)) dirstack.cd([PARENT]) owd = os.getcwd() @@ -168,7 +167,7 @@ def test_uncpushd_push_other_push_same(xession, shares_setup): 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 - xession.env = Env(CDPATH=PARENT, PWD=HERE) + xession.env.update(dict(CDPATH=PARENT, PWD=HERE)) dirstack.cd([PARENT]) owd = os.getcwd() diff --git a/tests/test_environ.py b/tests/test_environ.py index 752a15b1b..b57396ccb 100644 --- a/tests/test_environ.py +++ b/tests/test_environ.py @@ -11,7 +11,6 @@ from time import sleep import pytest from xonsh.tools import always_true, DefaultNotGiven -from xonsh.commands_cache import CommandsCache from xonsh.environ import ( Env, locate_binary, @@ -168,13 +167,13 @@ def test_thread_local_swap(): success_variables[index] = False break with env.swap(a=index): - sleep(0.1) + sleep(0.01) if env["a"] == index: success_variables[index] = True else: success_variables[index] = False break - sleep(0.1) + sleep(0.01) with env.swap(a="swapped"): threads = [ @@ -200,7 +199,6 @@ def test_locate_binary_on_windows(xession): with open(fpath, "w") as f: f.write(fpath) 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") @@ -208,9 +206,8 @@ def test_locate_binary_on_windows(xession): assert locate_binary("file3") is None -def test_event_on_envvar_change(xession): - env = Env(TEST=0) - xession.env = env +def test_event_on_envvar_change(xession, env): + env["TEST"] = 0 share = [] # register @@ -224,9 +221,7 @@ def test_event_on_envvar_change(xession): assert share == ["TEST", 0, 1] -def test_event_on_envvar_new(xession): - env = Env() - xession.env = env +def test_event_on_envvar_new(xession, env): share = [] # register @@ -240,9 +235,8 @@ def test_event_on_envvar_new(xession): assert share == ["TEST", 1] -def test_event_on_envvar_change_from_none_value(xession): - env = Env(TEST=None) - xession.env = env +def test_event_on_envvar_change_from_none_value(xession, env): + env["TEST"] = None share = [] # register @@ -257,9 +251,8 @@ def test_event_on_envvar_change_from_none_value(xession): @pytest.mark.parametrize("val", [1, None, True, "ok"]) -def test_event_on_envvar_change_no_fire_when_value_is_same(val, xession): - env = Env(TEST=val) - xession.env = env +def test_event_on_envvar_change_no_fire_when_value_is_same(val, xession, env): + env["TEST"] = val share = [] # register @@ -273,9 +266,7 @@ def test_event_on_envvar_change_no_fire_when_value_is_same(val, xession): assert share == [] -def test_events_on_envvar_called_in_right_order(xession): - env = Env() - xession.env = env +def test_events_on_envvar_called_in_right_order(xession, env): share = [] # register @@ -341,7 +332,7 @@ def test_delitem_default(): assert env[a_key] == a_value -def test_lscolors_target(xonsh_builtins): +def test_lscolors_target(xession): lsc = LsColors.fromstring("ln=target") assert lsc["ln"] == ("RESET",) assert lsc.is_target("ln") diff --git a/tests/test_execer.py b/tests/test_execer.py index d3db78a9e..2abfd1ebc 100644 --- a/tests/test_execer.py +++ b/tests/test_execer.py @@ -1,82 +1,93 @@ """Tests the xonsh lexer.""" import os -from tools import ( - check_eval, - check_exec, - check_parse, - skip_if_on_unix, - skip_if_on_windows, -) +from tools import skip_if_on_unix, skip_if_on_windows, ON_WINDOWS import pytest -@pytest.fixture(autouse=True) -def xonsh_execer_autouse(xonsh_builtins, xonsh_execer): - return xonsh_execer +@pytest.fixture +def check_eval(xonsh_execer, xonsh_session, monkeypatch): + def factory(input): + + env = { + "AUTO_CD": False, + "XONSH_ENCODING": "utf-8", + "XONSH_ENCODING_ERRORS": "strict", + "PATH": [], + } + for key, val in env.items(): + monkeypatch.setitem(xonsh_session.env, key, val) + if ON_WINDOWS: + monkeypatch.setitem( + xonsh_session.env, "PATHEXT", [".COM", ".EXE", ".BAT", ".CMD"] + ) + xonsh_execer.eval(input) + return True + + return factory @skip_if_on_unix -def test_win_ipconfig(): +def test_win_ipconfig(check_eval): assert check_eval(os.environ["SYSTEMROOT"] + "\\System32\\ipconfig.exe /all") @skip_if_on_unix -def test_ipconfig(): +def test_ipconfig(check_eval): assert check_eval("ipconfig /all") @skip_if_on_windows -def test_bin_ls(): +def test_bin_ls(check_eval): assert check_eval("/bin/ls -l") -def test_ls_dashl(): - assert check_parse("ls -l") +def test_ls_dashl(xonsh_execer_parse): + assert xonsh_execer_parse("ls -l") -def test_which_ls(): - assert check_parse("which ls") +def test_which_ls(xonsh_execer_parse): + assert xonsh_execer_parse("which ls") -def test_echo_hello(): - assert check_parse("echo hello") +def test_echo_hello(xonsh_execer_parse): + assert xonsh_execer_parse("echo hello") -def test_echo_star_with_semi(): - assert check_parse("echo * spam ; ![echo eggs]\n") +def test_echo_star_with_semi(xonsh_execer_parse): + assert xonsh_execer_parse("echo * spam ; ![echo eggs]\n") -def test_simple_func(): +def test_simple_func(xonsh_execer_parse): code = "def prompt():\n" " return '{user}'.format(user='me')\n" - assert check_parse(code) + assert xonsh_execer_parse(code) -def test_lookup_alias(): +def test_lookup_alias(xonsh_execer_parse): code = "def foo(a, s=None):\n" ' return "bar"\n' "@(foo)\n" - assert check_parse(code) + assert xonsh_execer_parse(code) -def test_lookup_anon_alias(): +def test_lookup_anon_alias(xonsh_execer_parse): code = 'echo "hi" | @(lambda a, s=None: a[0]) foo bar baz\n' - assert check_parse(code) + assert xonsh_execer_parse(code) -def test_simple_func_broken(): +def test_simple_func_broken(xonsh_execer_parse): code = "def prompt():\n" " return '{user}'.format(\n" " user='me')\n" - assert check_parse(code) + assert xonsh_execer_parse(code) -def test_bad_indent(): +def test_bad_indent(xonsh_execer_parse): code = "if True:\n" "x = 1\n" with pytest.raises(SyntaxError): - check_parse(code) + xonsh_execer_parse(code) -def test_comment_colon_ending(): +def test_comment_colon_ending(xonsh_execer_parse): code = "# this is a comment:\necho hello" - assert check_parse(code) + assert xonsh_execer_parse(code) def test_good_rhs_subproc(): @@ -85,56 +96,56 @@ def test_good_rhs_subproc(): assert code -def test_bad_rhs_subproc(): +def test_bad_rhs_subproc(xonsh_execer_parse): # nonsense but unparsable code = "str().split() | grep exit\n" with pytest.raises(SyntaxError): - check_parse(code) + xonsh_execer_parse(code) -def test_indent_with_empty_line(): +def test_indent_with_empty_line(xonsh_execer_parse): code = "if True:\n" "\n" " some_command for_sub_process_mode\n" - assert check_parse(code) + assert xonsh_execer_parse(code) -def test_command_in_func(): +def test_command_in_func(xonsh_execer_parse): code = "def f():\n" " echo hello\n" - assert check_parse(code) + assert xonsh_execer_parse(code) -def test_command_in_func_with_comment(): +def test_command_in_func_with_comment(xonsh_execer_parse): code = "def f():\n" " echo hello # comment\n" - assert check_parse(code) + assert xonsh_execer_parse(code) -def test_pyeval_redirect(): +def test_pyeval_redirect(xonsh_execer_parse): code = 'echo @("foo") > bar\n' - assert check_parse(code) + assert xonsh_execer_parse(code) -def test_pyeval_multiline_str(): +def test_pyeval_multiline_str(xonsh_execer_parse): code = 'echo @("""hello\nmom""")\n' - assert check_parse(code) + assert xonsh_execer_parse(code) -def test_echo_comma(): +def test_echo_comma(xonsh_execer_parse): code = "echo ,\n" - assert check_parse(code) + assert xonsh_execer_parse(code) -def test_echo_comma_val(): +def test_echo_comma_val(xonsh_execer_parse): code = "echo ,1\n" - assert check_parse(code) + assert xonsh_execer_parse(code) -def test_echo_comma_2val(): +def test_echo_comma_2val(xonsh_execer_parse): code = "echo 1,2\n" - assert check_parse(code) + assert xonsh_execer_parse(code) -def test_echo_line_cont(): +def test_echo_line_cont(xonsh_execer_parse): code = 'echo "1 \\\n2"\n' - assert check_parse(code) + assert xonsh_execer_parse(code) @pytest.mark.parametrize( @@ -146,40 +157,40 @@ def test_echo_line_cont(): "if True:\\\n echo a \\\n b\n", ], ) -def test_two_echo_line_cont(code): - assert check_parse(code) +def test_two_echo_line_cont(code, xonsh_execer_parse): + assert xonsh_execer_parse(code) -def test_eval_eol(): +def test_eval_eol(check_eval): assert check_eval("0") and check_eval("0\n") -def test_annotated_assign(): +def test_annotated_assign(xonsh_execer_exec): # issue #3959 - didn't work because of `CtxAwareTransformer` - assert check_exec("x : int = 42") + assert xonsh_execer_exec("x : int = 42") -def test_exec_eol(): +def test_exec_eol(xonsh_execer_exec): locs = dict() - assert check_exec("a=0", locs=locs) and check_exec("a=0\n", locs=locs) + assert xonsh_execer_exec("a=0", locs=locs) and xonsh_execer_exec("a=0\n", locs=locs) -def test_exec_print(capsys): +def test_exec_print(capsys, xonsh_execer_exec): ls = {"nested": "some long list"} - check_exec("print(ls)", locs=dict(ls=ls)) + xonsh_execer_exec("print(ls)", locs=dict(ls=ls)) out, err = capsys.readouterr() assert out.strip() == repr(ls) -def test_exec_function_scope(): +def test_exec_function_scope(xonsh_execer_exec): # issue 4363 - assert check_exec("x = 0; (lambda: x)()") - assert check_exec("x = 0; [x for _ in [0]]") + assert xonsh_execer_exec("x = 0; (lambda: x)()") + assert xonsh_execer_exec("x = 0; [x for _ in [0]]") -def test_exec_scope_reuse(): +def test_exec_scope_reuse(xonsh_execer_exec): # Scopes should not be reused between execs. # A first-pass incorrect solution to issue 4363 made this mistake. - assert check_exec("x = 0") + assert xonsh_execer_exec("x = 0") with pytest.raises(NameError): - check_exec("print(x)") + xonsh_execer_exec("print(x)") diff --git a/tests/test_imphooks.py b/tests/test_imphooks.py index 9a6d7dc27..232a8d3a5 100644 --- a/tests/test_imphooks.py +++ b/tests/test_imphooks.py @@ -5,16 +5,13 @@ from importlib import import_module import pytest from xonsh import imphooks -from xonsh.environ import Env -from xonsh.built_ins import XSH @pytest.fixture(autouse=True) def imp_env(xession): - xession.env = Env({"PATH": [], "PATHEXT": []}) + xession.env.update({"PATH": [], "PATHEXT": []}) imphooks.install_import_hooks(xession.execer) yield - XSH.unload() def test_import(): diff --git a/tests/test_main.py b/tests/test_main.py index b197c0528..2677ff453 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -423,7 +423,7 @@ def test_xonsh_failback( rc_shells, exp_shell, shell, - xonsh_builtins, + xession, monkeypatch, monkeypatch_stderr, ): diff --git a/tests/test_parser.py b/tests/test_parser.py index 33e1d656d..535a2871d 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -6,63 +6,85 @@ import itertools 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 from tools import nodes_equal, skip_if_pre_3_8, VER_MAJOR_MINOR -@pytest.fixture(autouse=True) -def xonsh_builtins_autouse(xonsh_builtins): - return xonsh_builtins +@pytest.fixture +def xsh(xession, monkeypatch, parser): + monkeypatch.setattr(xession.execer, "parser", parser) + return xession -PARSER = Parser(yacc_optimize=False, yacc_debug=True) +@pytest.fixture(scope="module") +def parser(): + return Parser(yacc_optimize=False, yacc_debug=True) -def check_ast(inp, run=True, mode="eval", debug_level=0): - __tracebackhide__ = True - # expect a Python AST - exp = ast.parse(inp, mode=mode) - # observe something from xonsh - obs = PARSER.parse(inp, debug_level=debug_level) - # Check that they are equal - assert nodes_equal(exp, obs) - # round trip by running xonsh AST via Python - if run: - exec(compile(obs, "", mode)) +@pytest.fixture +def check_ast(parser, xsh): + def factory(inp, run=True, mode="eval", debug_level=0): + __tracebackhide__ = True + # expect a Python AST + exp = ast.parse(inp, mode=mode) + # observe something from xonsh + obs = parser.parse(inp, debug_level=debug_level) + # Check that they are equal + assert nodes_equal(exp, obs) + # round trip by running xonsh AST via Python + if run: + exec(compile(obs, "", mode)) + + return factory -def check_stmts(inp, run=True, mode="exec", debug_level=0): - __tracebackhide__ = True - if not inp.endswith("\n"): - inp += "\n" - check_ast(inp, run=run, mode=mode, debug_level=debug_level) +@pytest.fixture +def check_stmts(check_ast): + def factory(inp, run=True, mode="exec", debug_level=0): + __tracebackhide__ = True + if not inp.endswith("\n"): + inp += "\n" + check_ast(inp, run=run, mode=mode, debug_level=debug_level) + + return factory -def check_xonsh_ast(xenv, inp, run=True, mode="eval", debug_level=0, return_obs=False): - XSH.env = xenv - obs = PARSER.parse(inp, debug_level=debug_level) - if obs is None: - return # comment only - bytecode = compile(obs, "", mode) - if run: - exec(bytecode) - return obs if return_obs else True +@pytest.fixture +def check_xonsh_ast(xsh, parser): + def factory(xenv, inp, run=True, mode="eval", debug_level=0, return_obs=False): + xsh.env.update(xenv) + obs = parser.parse(inp, debug_level=debug_level) + if obs is None: + return # comment only + bytecode = compile(obs, "", mode) + if run: + exec(bytecode) + return obs if return_obs else True + + return factory -def check_xonsh(xenv, inp, run=True, mode="exec"): - __tracebackhide__ = True - if not inp.endswith("\n"): - inp += "\n" - check_xonsh_ast(xenv, inp, run=run, mode=mode) +@pytest.fixture +def check_xonsh(check_xonsh_ast): + def factory(xenv, inp, run=True, mode="exec"): + __tracebackhide__ = True + if not inp.endswith("\n"): + inp += "\n" + check_xonsh_ast(xenv, inp, run=run, mode=mode) + + return factory -def eval_code(inp, mode="eval", **loc_vars): - obs = PARSER.parse(inp, debug_level=1) - bytecode = compile(obs, "", mode) - return eval(bytecode, loc_vars) +@pytest.fixture +def eval_code(parser, xsh): + def factory(inp, mode="eval", **loc_vars): + obs = parser.parse(inp, debug_level=1) + bytecode = compile(obs, "", mode) + return eval(bytecode, loc_vars) + + return factory # @@ -74,54 +96,54 @@ def eval_code(inp, mode="eval", **loc_vars): # -def test_int_literal(): +def test_int_literal(check_ast): check_ast("42") -def test_int_literal_underscore(): +def test_int_literal_underscore(check_ast): check_ast("4_2") -def test_float_literal(): +def test_float_literal(check_ast): check_ast("42.0") -def test_float_literal_underscore(): +def test_float_literal_underscore(check_ast): check_ast("4_2.4_2") -def test_imag_literal(): +def test_imag_literal(check_ast): check_ast("42j") -def test_float_imag_literal(): +def test_float_imag_literal(check_ast): check_ast("42.0j") -def test_complex(): +def test_complex(check_ast): check_ast("42+84j") -def test_str_literal(): +def test_str_literal(check_ast): check_ast('"hello"') -def test_bytes_literal(): +def test_bytes_literal(check_ast): check_ast('b"hello"') check_ast('B"hello"') -def test_raw_literal(): +def test_raw_literal(check_ast): check_ast('r"hell\\o"') check_ast('R"hell\\o"') -def test_f_literal(): +def test_f_literal(check_ast): check_ast('f"wakka{yo}yakka{42}"', run=False) check_ast('F"{yo}"', run=False) -def test_f_env_var(): +def test_f_env_var(check_xonsh_ast): check_xonsh_ast({}, 'f"{$HOME}"', run=False) check_xonsh_ast({}, "f'{$XONSH_DEBUG}'", run=False) check_xonsh_ast({}, 'F"{$PATH} and {$XONSH_DEBUG}"', run=False) @@ -161,240 +183,242 @@ if VER_MAJOR_MINOR >= (3, 8): @pytest.mark.parametrize("inp, exp", fstring_adaptor_parameters) -def test_fstring_adaptor(inp, exp): +def test_fstring_adaptor(inp, exp, xsh, monkeypatch): joined_str_node = FStringAdaptor(inp, "f").run() assert isinstance(joined_str_node, ast.JoinedStr) node = ast.Expression(body=joined_str_node) code = compile(node, "", mode="eval") - XSH.env = {"HOME": "/foo/bar", "FOO": "HO", "BAR": "ME"} + xenv = {"HOME": "/foo/bar", "FOO": "HO", "BAR": "ME"} + for key, val in xenv.items(): + monkeypatch.setitem(xsh.env, key, val) obs = eval(code) assert exp == obs -def test_raw_bytes_literal(): +def test_raw_bytes_literal(check_ast): check_ast('br"hell\\o"') check_ast('RB"hell\\o"') check_ast('Br"hell\\o"') check_ast('rB"hell\\o"') -def test_unary_plus(): +def test_unary_plus(check_ast): check_ast("+1") -def test_unary_minus(): +def test_unary_minus(check_ast): check_ast("-1") -def test_unary_invert(): +def test_unary_invert(check_ast): check_ast("~1") -def test_binop_plus(): +def test_binop_plus(check_ast): check_ast("42 + 65") -def test_binop_minus(): +def test_binop_minus(check_ast): check_ast("42 - 65") -def test_binop_times(): +def test_binop_times(check_ast): check_ast("42 * 65") -def test_binop_matmult(): +def test_binop_matmult(check_ast): check_ast("x @ y", False) -def test_binop_div(): +def test_binop_div(check_ast): check_ast("42 / 65") -def test_binop_mod(): +def test_binop_mod(check_ast): check_ast("42 % 65") -def test_binop_floordiv(): +def test_binop_floordiv(check_ast): check_ast("42 // 65") -def test_binop_pow(): +def test_binop_pow(check_ast): check_ast("2 ** 2") -def test_plus_pow(): +def test_plus_pow(check_ast): check_ast("42 + 2 ** 2") -def test_plus_plus(): +def test_plus_plus(check_ast): check_ast("42 + 65 + 6") -def test_plus_minus(): +def test_plus_minus(check_ast): check_ast("42 + 65 - 6") -def test_minus_plus(): +def test_minus_plus(check_ast): check_ast("42 - 65 + 6") -def test_minus_minus(): +def test_minus_minus(check_ast): check_ast("42 - 65 - 6") -def test_minus_plus_minus(): +def test_minus_plus_minus(check_ast): check_ast("42 - 65 + 6 - 28") -def test_times_plus(): +def test_times_plus(check_ast): check_ast("42 * 65 + 6") -def test_plus_times(): +def test_plus_times(check_ast): check_ast("42 + 65 * 6") -def test_times_times(): +def test_times_times(check_ast): check_ast("42 * 65 * 6") -def test_times_div(): +def test_times_div(check_ast): check_ast("42 * 65 / 6") -def test_times_div_mod(): +def test_times_div_mod(check_ast): check_ast("42 * 65 / 6 % 28") -def test_times_div_mod_floor(): +def test_times_div_mod_floor(check_ast): check_ast("42 * 65 / 6 % 28 // 13") -def test_str_str(): +def test_str_str(check_ast): check_ast("\"hello\" 'mom'") -def test_str_str_str(): +def test_str_str_str(check_ast): check_ast('"hello" \'mom\' "wow"') -def test_str_plus_str(): +def test_str_plus_str(check_ast): check_ast("\"hello\" + 'mom'") -def test_str_times_int(): +def test_str_times_int(check_ast): check_ast('"hello" * 20') -def test_int_times_str(): +def test_int_times_str(check_ast): check_ast('2*"hello"') -def test_group_plus_times(): +def test_group_plus_times(check_ast): check_ast("(42 + 65) * 20") -def test_plus_group_times(): +def test_plus_group_times(check_ast): check_ast("42 + (65 * 20)") -def test_group(): +def test_group(check_ast): check_ast("(42)") -def test_lt(): +def test_lt(check_ast): check_ast("42 < 65") -def test_gt(): +def test_gt(check_ast): check_ast("42 > 65") -def test_eq(): +def test_eq(check_ast): check_ast("42 == 65") -def test_le(): +def test_le(check_ast): check_ast("42 <= 65") -def test_ge(): +def test_ge(check_ast): check_ast("42 >= 65") -def test_ne(): +def test_ne(check_ast): check_ast("42 != 65") -def test_in(): +def test_in(check_ast): check_ast('"4" in "65"') -def test_is(): +def test_is(check_ast): check_ast("int is float") # avoid PY3.8 SyntaxWarning "is" with a literal -def test_not_in(): +def test_not_in(check_ast): check_ast('"4" not in "65"') -def test_is_not(): +def test_is_not(check_ast): check_ast("float is not int") -def test_lt_lt(): +def test_lt_lt(check_ast): check_ast("42 < 65 < 105") -def test_lt_lt_lt(): +def test_lt_lt_lt(check_ast): check_ast("42 < 65 < 105 < 77") -def test_not(): +def test_not(check_ast): check_ast("not 0") -def test_or(): +def test_or(check_ast): check_ast("1 or 0") -def test_or_or(): +def test_or_or(check_ast): check_ast("1 or 0 or 42") -def test_and(): +def test_and(check_ast): check_ast("1 and 0") -def test_and_and(): +def test_and_and(check_ast): check_ast("1 and 0 and 2") -def test_and_or(): +def test_and_or(check_ast): check_ast("1 and 0 or 2") -def test_or_and(): +def test_or_and(check_ast): check_ast("1 or 0 and 2") -def test_group_and_and(): +def test_group_and_and(check_ast): check_ast("(1 and 0) and 2") -def test_group_and_or(): +def test_group_and_or(check_ast): check_ast("(1 and 0) or 2") -def test_if_else_expr(): +def test_if_else_expr(check_ast): check_ast("42 if True else 65") -def test_if_else_expr_expr(): +def test_if_else_expr_expr(check_ast): check_ast("42+5 if 1 == 2 else 65-5") -def test_subscription_syntaxes(): +def test_subscription_syntaxes(eval_code): assert eval_code("[1, 2, 3][-1]") == 3 assert eval_code("[1, 2, 3][-1]") == 3 assert eval_code("'string'[-1]") == "g" @@ -410,7 +434,7 @@ def arr_container(): return Arr() -def test_subscription_special_syntaxes(arr_container): +def test_subscription_special_syntaxes(arr_container, eval_code): assert eval_code("arr[1, 2, 3]", arr=arr_container) == (1, 2, 3) # dataframe assert eval_code('arr[["a", "b"]]', arr=arr_container) == ["a", "b"] @@ -418,7 +442,7 @@ def test_subscription_special_syntaxes(arr_container): # todo: enable this test @pytest.mark.xfail -def test_subscription_special_syntaxes_2(arr_container): +def test_subscription_special_syntaxes_2(arr_container, eval_code): # aliases d = {} eval_code("d[arr.__name__]=True", arr=arr_container, d=d) @@ -427,255 +451,255 @@ def test_subscription_special_syntaxes_2(arr_container): assert eval_code('arr[:, "2"]') == 2 -def test_str_idx(): +def test_str_idx(check_ast): check_ast('"hello"[0]') -def test_str_slice(): +def test_str_slice(check_ast): check_ast('"hello"[0:3]') -def test_str_step(): +def test_str_step(check_ast): check_ast('"hello"[0:3:1]') -def test_str_slice_all(): +def test_str_slice_all(check_ast): check_ast('"hello"[:]') -def test_str_slice_upper(): +def test_str_slice_upper(check_ast): check_ast('"hello"[5:]') -def test_str_slice_lower(): +def test_str_slice_lower(check_ast): check_ast('"hello"[:3]') -def test_str_slice_other(): +def test_str_slice_other(check_ast): check_ast('"hello"[::2]') -def test_str_slice_lower_other(): +def test_str_slice_lower_other(check_ast): check_ast('"hello"[:3:2]') -def test_str_slice_upper_other(): +def test_str_slice_upper_other(check_ast): check_ast('"hello"[3::2]') -def test_str_2slice(): +def test_str_2slice(check_ast): check_ast('"hello"[0:3,0:3]', False) -def test_str_2step(): +def test_str_2step(check_ast): check_ast('"hello"[0:3:1,0:4:2]', False) -def test_str_2slice_all(): +def test_str_2slice_all(check_ast): check_ast('"hello"[:,:]', False) -def test_str_2slice_upper(): +def test_str_2slice_upper(check_ast): check_ast('"hello"[5:,5:]', False) -def test_str_2slice_lower(): +def test_str_2slice_lower(check_ast): check_ast('"hello"[:3,:3]', False) -def test_str_2slice_lowerupper(): +def test_str_2slice_lowerupper(check_ast): check_ast('"hello"[5:,:3]', False) -def test_str_2slice_other(): +def test_str_2slice_other(check_ast): check_ast('"hello"[::2,::2]', False) -def test_str_2slice_lower_other(): +def test_str_2slice_lower_other(check_ast): check_ast('"hello"[:3:2,:3:2]', False) -def test_str_2slice_upper_other(): +def test_str_2slice_upper_other(check_ast): check_ast('"hello"[3::2,3::2]', False) -def test_str_3slice(): +def test_str_3slice(check_ast): check_ast('"hello"[0:3,0:3,0:3]', False) -def test_str_3step(): +def test_str_3step(check_ast): check_ast('"hello"[0:3:1,0:4:2,1:3:2]', False) -def test_str_3slice_all(): +def test_str_3slice_all(check_ast): check_ast('"hello"[:,:,:]', False) -def test_str_3slice_upper(): +def test_str_3slice_upper(check_ast): check_ast('"hello"[5:,5:,5:]', False) -def test_str_3slice_lower(): +def test_str_3slice_lower(check_ast): check_ast('"hello"[:3,:3,:3]', False) -def test_str_3slice_lowerlowerupper(): +def test_str_3slice_lowerlowerupper(check_ast): check_ast('"hello"[:3,:3,:3]', False) -def test_str_3slice_lowerupperlower(): +def test_str_3slice_lowerupperlower(check_ast): check_ast('"hello"[:3,5:,:3]', False) -def test_str_3slice_lowerupperupper(): +def test_str_3slice_lowerupperupper(check_ast): check_ast('"hello"[:3,5:,5:]', False) -def test_str_3slice_upperlowerlower(): +def test_str_3slice_upperlowerlower(check_ast): check_ast('"hello"[5:,5:,:3]', False) -def test_str_3slice_upperlowerupper(): +def test_str_3slice_upperlowerupper(check_ast): check_ast('"hello"[5:,:3,5:]', False) -def test_str_3slice_upperupperlower(): +def test_str_3slice_upperupperlower(check_ast): check_ast('"hello"[5:,5:,:3]', False) -def test_str_3slice_other(): +def test_str_3slice_other(check_ast): check_ast('"hello"[::2,::2,::2]', False) -def test_str_3slice_lower_other(): +def test_str_3slice_lower_other(check_ast): check_ast('"hello"[:3:2,:3:2,:3:2]', False) -def test_str_3slice_upper_other(): +def test_str_3slice_upper_other(check_ast): check_ast('"hello"[3::2,3::2,3::2]', False) -def test_str_slice_true(): +def test_str_slice_true(check_ast): check_ast('"hello"[0:3,True]', False) -def test_str_true_slice(): +def test_str_true_slice(check_ast): check_ast('"hello"[True,0:3]', False) -def test_list_empty(): +def test_list_empty(check_ast): check_ast("[]") -def test_list_one(): +def test_list_one(check_ast): check_ast("[1]") -def test_list_one_comma(): +def test_list_one_comma(check_ast): check_ast("[1,]") -def test_list_two(): +def test_list_two(check_ast): check_ast("[1, 42]") -def test_list_three(): +def test_list_three(check_ast): check_ast("[1, 42, 65]") -def test_list_three_comma(): +def test_list_three_comma(check_ast): check_ast("[1, 42, 65,]") -def test_list_one_nested(): +def test_list_one_nested(check_ast): check_ast("[[1]]") -def test_list_list_four_nested(): +def test_list_list_four_nested(check_ast): check_ast("[[1], [2], [3], [4]]") -def test_list_tuple_three_nested(): +def test_list_tuple_three_nested(check_ast): check_ast("[(1,), (2,), (3,)]") -def test_list_set_tuple_three_nested(): +def test_list_set_tuple_three_nested(check_ast): check_ast("[{(1,)}, {(2,)}, {(3,)}]") -def test_list_tuple_one_nested(): +def test_list_tuple_one_nested(check_ast): check_ast("[(1,)]") -def test_tuple_tuple_one_nested(): +def test_tuple_tuple_one_nested(check_ast): check_ast("((1,),)") -def test_dict_list_one_nested(): +def test_dict_list_one_nested(check_ast): check_ast("{1: [2]}") -def test_dict_list_one_nested_comma(): +def test_dict_list_one_nested_comma(check_ast): check_ast("{1: [2],}") -def test_dict_tuple_one_nested(): +def test_dict_tuple_one_nested(check_ast): check_ast("{1: (2,)}") -def test_dict_tuple_one_nested_comma(): +def test_dict_tuple_one_nested_comma(check_ast): check_ast("{1: (2,),}") -def test_dict_list_two_nested(): +def test_dict_list_two_nested(check_ast): check_ast("{1: [2], 3: [4]}") -def test_set_tuple_one_nested(): +def test_set_tuple_one_nested(check_ast): check_ast("{(1,)}") -def test_set_tuple_two_nested(): +def test_set_tuple_two_nested(check_ast): check_ast("{(1,), (2,)}") -def test_tuple_empty(): +def test_tuple_empty(check_ast): check_ast("()") -def test_tuple_one_bare(): +def test_tuple_one_bare(check_ast): check_ast("1,") -def test_tuple_two_bare(): +def test_tuple_two_bare(check_ast): check_ast("1, 42") -def test_tuple_three_bare(): +def test_tuple_three_bare(check_ast): check_ast("1, 42, 65") -def test_tuple_three_bare_comma(): +def test_tuple_three_bare_comma(check_ast): check_ast("1, 42, 65,") -def test_tuple_one_comma(): +def test_tuple_one_comma(check_ast): check_ast("(1,)") -def test_tuple_two(): +def test_tuple_two(check_ast): check_ast("(1, 42)") -def test_tuple_three(): +def test_tuple_three(check_ast): check_ast("(1, 42, 65)") -def test_tuple_three_comma(): +def test_tuple_three_comma(check_ast): check_ast("(1, 42, 65,)") -def test_bare_tuple_of_tuples(): +def test_bare_tuple_of_tuples(check_ast): check_ast("(),") check_ast("((),),(1,)") check_ast("(),(),") @@ -686,600 +710,600 @@ def test_bare_tuple_of_tuples(): check_ast("((),[()],)") -def test_set_one(): +def test_set_one(check_ast): check_ast("{42}") -def test_set_one_comma(): +def test_set_one_comma(check_ast): check_ast("{42,}") -def test_set_two(): +def test_set_two(check_ast): check_ast("{42, 65}") -def test_set_two_comma(): +def test_set_two_comma(check_ast): check_ast("{42, 65,}") -def test_set_three(): +def test_set_three(check_ast): check_ast("{42, 65, 45}") -def test_dict_empty(): +def test_dict_empty(check_ast): check_ast("{}") -def test_dict_one(): +def test_dict_one(check_ast): check_ast("{42: 65}") -def test_dict_one_comma(): +def test_dict_one_comma(check_ast): check_ast("{42: 65,}") -def test_dict_two(): +def test_dict_two(check_ast): check_ast("{42: 65, 6: 28}") -def test_dict_two_comma(): +def test_dict_two_comma(check_ast): check_ast("{42: 65, 6: 28,}") -def test_dict_three(): +def test_dict_three(check_ast): check_ast("{42: 65, 6: 28, 1: 2}") -def test_dict_from_dict_one(): +def test_dict_from_dict_one(check_ast): check_ast('{**{"x": 2}}') -def test_dict_from_dict_one_comma(): +def test_dict_from_dict_one_comma(check_ast): check_ast('{**{"x": 2},}') -def test_dict_from_dict_two_xy(): +def test_dict_from_dict_two_xy(check_ast): check_ast('{"x": 1, **{"y": 2}}') -def test_dict_from_dict_two_x_first(): +def test_dict_from_dict_two_x_first(check_ast): check_ast('{"x": 1, **{"x": 2}}') -def test_dict_from_dict_two_x_second(): +def test_dict_from_dict_two_x_second(check_ast): check_ast('{**{"x": 2}, "x": 1}') -def test_dict_from_dict_two_x_none(): +def test_dict_from_dict_two_x_none(check_ast): check_ast('{**{"x": 1}, **{"x": 2}}') @pytest.mark.parametrize("third", [True, False]) @pytest.mark.parametrize("second", [True, False]) @pytest.mark.parametrize("first", [True, False]) -def test_dict_from_dict_three_xyz(first, second, third): +def test_dict_from_dict_three_xyz(first, second, third, check_ast): val1 = '"x": 1' if first else '**{"x": 1}' val2 = '"y": 2' if second else '**{"y": 2}' val3 = '"z": 3' if third else '**{"z": 3}' check_ast("{" + val1 + "," + val2 + "," + val3 + "}") -def test_unpack_range_tuple(): +def test_unpack_range_tuple(check_stmts): check_stmts("*range(4),") -def test_unpack_range_tuple_4(): +def test_unpack_range_tuple_4(check_stmts): check_stmts("*range(4), 4") -def test_unpack_range_tuple_parens(): +def test_unpack_range_tuple_parens(check_ast): check_ast("(*range(4),)") -def test_unpack_range_tuple_parens_4(): +def test_unpack_range_tuple_parens_4(check_ast): check_ast("(*range(4), 4)") -def test_unpack_range_list(): +def test_unpack_range_list(check_ast): check_ast("[*range(4)]") -def test_unpack_range_list_4(): +def test_unpack_range_list_4(check_ast): check_ast("[*range(4), 4]") -def test_unpack_range_set(): +def test_unpack_range_set(check_ast): check_ast("{*range(4)}") -def test_unpack_range_set_4(): +def test_unpack_range_set_4(check_ast): check_ast("{*range(4), 4}") -def test_true(): +def test_true(check_ast): check_ast("True") -def test_false(): +def test_false(check_ast): check_ast("False") -def test_none(): +def test_none(check_ast): check_ast("None") -def test_elipssis(): +def test_elipssis(check_ast): check_ast("...") -def test_not_implemented_name(): +def test_not_implemented_name(check_ast): check_ast("NotImplemented") -def test_genexpr(): +def test_genexpr(check_ast): check_ast('(x for x in "mom")') -def test_genexpr_if(): +def test_genexpr_if(check_ast): check_ast('(x for x in "mom" if True)') -def test_genexpr_if_and(): +def test_genexpr_if_and(check_ast): check_ast('(x for x in "mom" if True and x == "m")') -def test_dbl_genexpr(): +def test_dbl_genexpr(check_ast): check_ast('(x+y for x in "mom" for y in "dad")') -def test_genexpr_if_genexpr(): +def test_genexpr_if_genexpr(check_ast): check_ast('(x+y for x in "mom" if True for y in "dad")') -def test_genexpr_if_genexpr_if(): +def test_genexpr_if_genexpr_if(check_ast): check_ast('(x+y for x in "mom" if True for y in "dad" if y == "d")') -def test_listcomp(): +def test_listcomp(check_ast): check_ast('[x for x in "mom"]') -def test_listcomp_if(): +def test_listcomp_if(check_ast): check_ast('[x for x in "mom" if True]') -def test_listcomp_if_and(): +def test_listcomp_if_and(check_ast): check_ast('[x for x in "mom" if True and x == "m"]') -def test_listcomp_multi_if(): +def test_listcomp_multi_if(check_ast): check_ast('[x for x in "mom" if True if x in "mo" if x == "m"]') -def test_dbl_listcomp(): +def test_dbl_listcomp(check_ast): check_ast('[x+y for x in "mom" for y in "dad"]') -def test_listcomp_if_listcomp(): +def test_listcomp_if_listcomp(check_ast): check_ast('[x+y for x in "mom" if True for y in "dad"]') -def test_listcomp_if_listcomp_if(): +def test_listcomp_if_listcomp_if(check_ast): check_ast('[x+y for x in "mom" if True for y in "dad" if y == "d"]') -def test_setcomp(): +def test_setcomp(check_ast): check_ast('{x for x in "mom"}') -def test_setcomp_if(): +def test_setcomp_if(check_ast): check_ast('{x for x in "mom" if True}') -def test_setcomp_if_and(): +def test_setcomp_if_and(check_ast): check_ast('{x for x in "mom" if True and x == "m"}') -def test_dbl_setcomp(): +def test_dbl_setcomp(check_ast): check_ast('{x+y for x in "mom" for y in "dad"}') -def test_setcomp_if_setcomp(): +def test_setcomp_if_setcomp(check_ast): check_ast('{x+y for x in "mom" if True for y in "dad"}') -def test_setcomp_if_setcomp_if(): +def test_setcomp_if_setcomp_if(check_ast): check_ast('{x+y for x in "mom" if True for y in "dad" if y == "d"}') -def test_dictcomp(): +def test_dictcomp(check_ast): check_ast('{x: x for x in "mom"}') -def test_dictcomp_unpack_parens(): +def test_dictcomp_unpack_parens(check_ast): check_ast('{k: v for (k, v) in {"x": 42}.items()}') -def test_dictcomp_unpack_no_parens(): +def test_dictcomp_unpack_no_parens(check_ast): check_ast('{k: v for k, v in {"x": 42}.items()}') -def test_dictcomp_if(): +def test_dictcomp_if(check_ast): check_ast('{x: x for x in "mom" if True}') -def test_dictcomp_if_and(): +def test_dictcomp_if_and(check_ast): check_ast('{x: x for x in "mom" if True and x == "m"}') -def test_dbl_dictcomp(): +def test_dbl_dictcomp(check_ast): check_ast('{x: y for x in "mom" for y in "dad"}') -def test_dictcomp_if_dictcomp(): +def test_dictcomp_if_dictcomp(check_ast): check_ast('{x: y for x in "mom" if True for y in "dad"}') -def test_dictcomp_if_dictcomp_if(): +def test_dictcomp_if_dictcomp_if(check_ast): check_ast('{x: y for x in "mom" if True for y in "dad" if y == "d"}') -def test_lambda(): +def test_lambda(check_ast): check_ast("lambda: 42") -def test_lambda_x(): +def test_lambda_x(check_ast): check_ast("lambda x: x") -def test_lambda_kwx(): +def test_lambda_kwx(check_ast): check_ast("lambda x=42: x") -def test_lambda_x_y(): +def test_lambda_x_y(check_ast): check_ast("lambda x, y: x") -def test_lambda_x_y_z(): +def test_lambda_x_y_z(check_ast): check_ast("lambda x, y, z: x") -def test_lambda_x_kwy(): +def test_lambda_x_kwy(check_ast): check_ast("lambda x, y=42: x") -def test_lambda_kwx_kwy(): +def test_lambda_kwx_kwy(check_ast): check_ast("lambda x=65, y=42: x") -def test_lambda_kwx_kwy_kwz(): +def test_lambda_kwx_kwy_kwz(check_ast): check_ast("lambda x=65, y=42, z=1: x") -def test_lambda_x_comma(): +def test_lambda_x_comma(check_ast): check_ast("lambda x,: x") -def test_lambda_x_y_comma(): +def test_lambda_x_y_comma(check_ast): check_ast("lambda x, y,: x") -def test_lambda_x_y_z_comma(): +def test_lambda_x_y_z_comma(check_ast): check_ast("lambda x, y, z,: x") -def test_lambda_x_kwy_comma(): +def test_lambda_x_kwy_comma(check_ast): check_ast("lambda x, y=42,: x") -def test_lambda_kwx_kwy_comma(): +def test_lambda_kwx_kwy_comma(check_ast): check_ast("lambda x=65, y=42,: x") -def test_lambda_kwx_kwy_kwz_comma(): +def test_lambda_kwx_kwy_kwz_comma(check_ast): check_ast("lambda x=65, y=42, z=1,: x") -def test_lambda_args(): +def test_lambda_args(check_ast): check_ast("lambda *args: 42") -def test_lambda_args_x(): +def test_lambda_args_x(check_ast): check_ast("lambda *args, x: 42") -def test_lambda_args_x_y(): +def test_lambda_args_x_y(check_ast): check_ast("lambda *args, x, y: 42") -def test_lambda_args_x_kwy(): +def test_lambda_args_x_kwy(check_ast): check_ast("lambda *args, x, y=10: 42") -def test_lambda_args_kwx_y(): +def test_lambda_args_kwx_y(check_ast): check_ast("lambda *args, x=10, y: 42") -def test_lambda_args_kwx_kwy(): +def test_lambda_args_kwx_kwy(check_ast): check_ast("lambda *args, x=42, y=65: 42") -def test_lambda_x_args(): +def test_lambda_x_args(check_ast): check_ast("lambda x, *args: 42") -def test_lambda_x_args_y(): +def test_lambda_x_args_y(check_ast): check_ast("lambda x, *args, y: 42") -def test_lambda_x_args_y_z(): +def test_lambda_x_args_y_z(check_ast): check_ast("lambda x, *args, y, z: 42") -def test_lambda_kwargs(): +def test_lambda_kwargs(check_ast): check_ast("lambda **kwargs: 42") -def test_lambda_x_kwargs(): +def test_lambda_x_kwargs(check_ast): check_ast("lambda x, **kwargs: 42") -def test_lambda_x_y_kwargs(): +def test_lambda_x_y_kwargs(check_ast): check_ast("lambda x, y, **kwargs: 42") -def test_lambda_x_kwy_kwargs(): +def test_lambda_x_kwy_kwargs(check_ast): check_ast("lambda x, y=42, **kwargs: 42") -def test_lambda_args_kwargs(): +def test_lambda_args_kwargs(check_ast): check_ast("lambda *args, **kwargs: 42") -def test_lambda_x_args_kwargs(): +def test_lambda_x_args_kwargs(check_ast): check_ast("lambda x, *args, **kwargs: 42") -def test_lambda_x_y_args_kwargs(): +def test_lambda_x_y_args_kwargs(check_ast): check_ast("lambda x, y, *args, **kwargs: 42") -def test_lambda_kwx_args_kwargs(): +def test_lambda_kwx_args_kwargs(check_ast): check_ast("lambda x=10, *args, **kwargs: 42") -def test_lambda_x_kwy_args_kwargs(): +def test_lambda_x_kwy_args_kwargs(check_ast): check_ast("lambda x, y=42, *args, **kwargs: 42") -def test_lambda_x_args_y_kwargs(): +def test_lambda_x_args_y_kwargs(check_ast): check_ast("lambda x, *args, y, **kwargs: 42") -def test_lambda_x_args_kwy_kwargs(): +def test_lambda_x_args_kwy_kwargs(check_ast): check_ast("lambda x, *args, y=42, **kwargs: 42") -def test_lambda_args_y_kwargs(): +def test_lambda_args_y_kwargs(check_ast): check_ast("lambda *args, y, **kwargs: 42") -def test_lambda_star_x(): +def test_lambda_star_x(check_ast): check_ast("lambda *, x: 42") -def test_lambda_star_x_y(): +def test_lambda_star_x_y(check_ast): check_ast("lambda *, x, y: 42") -def test_lambda_star_x_kwargs(): +def test_lambda_star_x_kwargs(check_ast): check_ast("lambda *, x, **kwargs: 42") -def test_lambda_star_kwx_kwargs(): +def test_lambda_star_kwx_kwargs(check_ast): check_ast("lambda *, x=42, **kwargs: 42") -def test_lambda_x_star_y(): +def test_lambda_x_star_y(check_ast): check_ast("lambda x, *, y: 42") -def test_lambda_x_y_star_z(): +def test_lambda_x_y_star_z(check_ast): check_ast("lambda x, y, *, z: 42") -def test_lambda_x_kwy_star_y(): +def test_lambda_x_kwy_star_y(check_ast): check_ast("lambda x, y=42, *, z: 42") -def test_lambda_x_kwy_star_kwy(): +def test_lambda_x_kwy_star_kwy(check_ast): check_ast("lambda x, y=42, *, z=65: 42") -def test_lambda_x_star_y_kwargs(): +def test_lambda_x_star_y_kwargs(check_ast): check_ast("lambda x, *, y, **kwargs: 42") @skip_if_pre_3_8 -def test_lambda_x_divide_y_star_z_kwargs(): +def test_lambda_x_divide_y_star_z_kwargs(check_ast): check_ast("lambda x, /, y, *, z, **kwargs: 42") -def test_call_range(): +def test_call_range(check_ast): check_ast("range(6)") -def test_call_range_comma(): +def test_call_range_comma(check_ast): check_ast("range(6,)") -def test_call_range_x_y(): +def test_call_range_x_y(check_ast): check_ast("range(6, 10)") -def test_call_range_x_y_comma(): +def test_call_range_x_y_comma(check_ast): check_ast("range(6, 10,)") -def test_call_range_x_y_z(): +def test_call_range_x_y_z(check_ast): check_ast("range(6, 10, 2)") -def test_call_dict_kwx(): +def test_call_dict_kwx(check_ast): check_ast("dict(start=10)") -def test_call_dict_kwx_comma(): +def test_call_dict_kwx_comma(check_ast): check_ast("dict(start=10,)") -def test_call_dict_kwx_kwy(): +def test_call_dict_kwx_kwy(check_ast): check_ast("dict(start=10, stop=42)") -def test_call_tuple_gen(): +def test_call_tuple_gen(check_ast): check_ast("tuple(x for x in [1, 2, 3])") -def test_call_tuple_genifs(): +def test_call_tuple_genifs(check_ast): check_ast("tuple(x for x in [1, 2, 3] if x < 3)") -def test_call_range_star(): +def test_call_range_star(check_ast): check_ast("range(*[1, 2, 3])") -def test_call_range_x_star(): +def test_call_range_x_star(check_ast): check_ast("range(1, *[2, 3])") -def test_call_int(): +def test_call_int(check_ast): check_ast('int(*["42"], base=8)') -def test_call_int_base_dict(): +def test_call_int_base_dict(check_ast): check_ast('int(*["42"], **{"base": 8})') -def test_call_dict_kwargs(): +def test_call_dict_kwargs(check_ast): check_ast('dict(**{"base": 8})') -def test_call_list_many_star_args(): +def test_call_list_many_star_args(check_ast): check_ast("min(*[1, 2], 3, *[4, 5])") -def test_call_list_many_starstar_args(): +def test_call_list_many_starstar_args(check_ast): check_ast('dict(**{"a": 2}, v=3, **{"c": 5})') -def test_call_list_many_star_and_starstar_args(): +def test_call_list_many_star_and_starstar_args(check_ast): check_ast('x(*[("a", 2)], *[("v", 3)], **{"c": 5})', False) -def test_call_alot(): +def test_call_alot(check_ast): check_ast("x(1, *args, **kwargs)", False) -def test_call_alot_next(): +def test_call_alot_next(check_ast): check_ast("x(x=1, *args, **kwargs)", False) -def test_call_alot_next_next(): +def test_call_alot_next_next(check_ast): check_ast("x(x=1, *args, y=42, **kwargs)", False) -def test_getattr(): +def test_getattr(check_ast): check_ast("list.append") -def test_getattr_getattr(): +def test_getattr_getattr(check_ast): check_ast("list.append.__str__") -def test_dict_tuple_key(): +def test_dict_tuple_key(check_ast): check_ast("{(42, 1): 65}") -def test_dict_tuple_key_get(): +def test_dict_tuple_key_get(check_ast): check_ast("{(42, 1): 65}[42, 1]") -def test_dict_tuple_key_get_3(): +def test_dict_tuple_key_get_3(check_ast): check_ast("{(42, 1, 3): 65}[42, 1, 3]") -def test_pipe_op(): +def test_pipe_op(check_ast): check_ast("{42} | {65}") -def test_pipe_op_two(): +def test_pipe_op_two(check_ast): check_ast("{42} | {65} | {1}") -def test_pipe_op_three(): +def test_pipe_op_three(check_ast): check_ast("{42} | {65} | {1} | {7}") -def test_xor_op(): +def test_xor_op(check_ast): check_ast("{42} ^ {65}") -def test_xor_op_two(): +def test_xor_op_two(check_ast): check_ast("{42} ^ {65} ^ {1}") -def test_xor_op_three(): +def test_xor_op_three(check_ast): check_ast("{42} ^ {65} ^ {1} ^ {7}") -def test_xor_pipe(): +def test_xor_pipe(check_ast): check_ast("{42} ^ {65} | {1}") -def test_amp_op(): +def test_amp_op(check_ast): check_ast("{42} & {65}") -def test_amp_op_two(): +def test_amp_op_two(check_ast): check_ast("{42} & {65} & {1}") -def test_amp_op_three(): +def test_amp_op_three(check_ast): check_ast("{42} & {65} & {1} & {7}") -def test_lshift_op(): +def test_lshift_op(check_ast): check_ast("42 << 65") -def test_lshift_op_two(): +def test_lshift_op_two(check_ast): check_ast("42 << 65 << 1") -def test_lshift_op_three(): +def test_lshift_op_three(check_ast): check_ast("42 << 65 << 1 << 7") -def test_rshift_op(): +def test_rshift_op(check_ast): check_ast("42 >> 65") -def test_rshift_op_two(): +def test_rshift_op_two(check_ast): check_ast("42 >> 65 >> 1") -def test_rshift_op_three(): +def test_rshift_op_three(check_ast): check_ast("42 >> 65 >> 1 >> 7") @skip_if_pre_3_8 -def test_named_expr(): +def test_named_expr(check_ast): check_ast("(x := 42)") @skip_if_pre_3_8 -def test_named_expr_list(): +def test_named_expr_list(check_ast): check_ast("[x := 42, x + 1, x + 2]") @@ -1288,405 +1312,405 @@ def test_named_expr_list(): # -def test_equals(): +def test_equals(check_stmts): check_stmts("x = 42") -def test_equals_semi(): +def test_equals_semi(check_stmts): check_stmts("x = 42;") -def test_x_y_equals_semi(): +def test_x_y_equals_semi(check_stmts): check_stmts("x = y = 42") -def test_equals_two(): +def test_equals_two(check_stmts): check_stmts("x = 42; y = 65") -def test_equals_two_semi(): +def test_equals_two_semi(check_stmts): check_stmts("x = 42; y = 65;") -def test_equals_three(): +def test_equals_three(check_stmts): check_stmts("x = 42; y = 65; z = 6") -def test_equals_three_semi(): +def test_equals_three_semi(check_stmts): check_stmts("x = 42; y = 65; z = 6;") -def test_plus_eq(): +def test_plus_eq(check_stmts): check_stmts("x = 42; x += 65") -def test_sub_eq(): +def test_sub_eq(check_stmts): check_stmts("x = 42; x -= 2") -def test_times_eq(): +def test_times_eq(check_stmts): check_stmts("x = 42; x *= 2") -def test_matmult_eq(): +def test_matmult_eq(check_stmts): check_stmts("x @= y", False) -def test_div_eq(): +def test_div_eq(check_stmts): check_stmts("x = 42; x /= 2") -def test_floordiv_eq(): +def test_floordiv_eq(check_stmts): check_stmts("x = 42; x //= 2") -def test_pow_eq(): +def test_pow_eq(check_stmts): check_stmts("x = 42; x **= 2") -def test_mod_eq(): +def test_mod_eq(check_stmts): check_stmts("x = 42; x %= 2") -def test_xor_eq(): +def test_xor_eq(check_stmts): check_stmts("x = 42; x ^= 2") -def test_ampersand_eq(): +def test_ampersand_eq(check_stmts): check_stmts("x = 42; x &= 2") -def test_bitor_eq(): +def test_bitor_eq(check_stmts): check_stmts("x = 42; x |= 2") -def test_lshift_eq(): +def test_lshift_eq(check_stmts): check_stmts("x = 42; x <<= 2") -def test_rshift_eq(): +def test_rshift_eq(check_stmts): check_stmts("x = 42; x >>= 2") -def test_bare_unpack(): +def test_bare_unpack(check_stmts): check_stmts("x, y = 42, 65") -def test_lhand_group_unpack(): +def test_lhand_group_unpack(check_stmts): check_stmts("(x, y) = 42, 65") -def test_rhand_group_unpack(): +def test_rhand_group_unpack(check_stmts): check_stmts("x, y = (42, 65)") -def test_grouped_unpack(): +def test_grouped_unpack(check_stmts): check_stmts("(x, y) = (42, 65)") -def test_double_grouped_unpack(): +def test_double_grouped_unpack(check_stmts): check_stmts("(x, y) = (z, a) = (7, 8)") -def test_double_ungrouped_unpack(): +def test_double_ungrouped_unpack(check_stmts): check_stmts("x, y = z, a = 7, 8") -def test_stary_eq(): +def test_stary_eq(check_stmts): check_stmts("*y, = [1, 2, 3]") -def test_stary_x(): +def test_stary_x(check_stmts): check_stmts("*y, x = [1, 2, 3]") -def test_tuple_x_stary(): +def test_tuple_x_stary(check_stmts): check_stmts("(x, *y) = [1, 2, 3]") -def test_list_x_stary(): +def test_list_x_stary(check_stmts): check_stmts("[x, *y] = [1, 2, 3]") -def test_bare_x_stary(): +def test_bare_x_stary(check_stmts): check_stmts("x, *y = [1, 2, 3]") -def test_bare_x_stary_z(): +def test_bare_x_stary_z(check_stmts): check_stmts("x, *y, z = [1, 2, 2, 3]") -def test_equals_list(): +def test_equals_list(check_stmts): check_stmts("x = [42]; x[0] = 65") -def test_equals_dict(): +def test_equals_dict(check_stmts): check_stmts("x = {42: 65}; x[42] = 3") -def test_equals_attr(): +def test_equals_attr(check_stmts): check_stmts("class X(object):\n pass\nx = X()\nx.a = 65") -def test_equals_annotation(): +def test_equals_annotation(check_stmts): check_stmts("x : int = 42") -def test_equals_annotation_empty(): +def test_equals_annotation_empty(check_stmts): check_stmts("x : int") -def test_dict_keys(): +def test_dict_keys(check_stmts): check_stmts('x = {"x": 1}\nx.keys()') -def test_assert_msg(): +def test_assert_msg(check_stmts): check_stmts('assert True, "wow mom"') -def test_assert(): +def test_assert(check_stmts): check_stmts("assert True") -def test_pass(): +def test_pass(check_stmts): check_stmts("pass") -def test_del(): +def test_del(check_stmts): check_stmts("x = 42; del x") -def test_del_comma(): +def test_del_comma(check_stmts): check_stmts("x = 42; del x,") -def test_del_two(): +def test_del_two(check_stmts): check_stmts("x = 42; y = 65; del x, y") -def test_del_two_comma(): +def test_del_two_comma(check_stmts): check_stmts("x = 42; y = 65; del x, y,") -def test_del_with_parens(): +def test_del_with_parens(check_stmts): check_stmts("x = 42; y = 65; del (x, y)") -def test_raise(): +def test_raise(check_stmts): check_stmts("raise", False) -def test_raise_x(): +def test_raise_x(check_stmts): check_stmts("raise TypeError", False) -def test_raise_x_from(): +def test_raise_x_from(check_stmts): check_stmts("raise TypeError from x", False) -def test_import_x(): +def test_import_x(check_stmts): check_stmts("import x", False) -def test_import_xy(): +def test_import_xy(check_stmts): check_stmts("import x.y", False) -def test_import_xyz(): +def test_import_xyz(check_stmts): check_stmts("import x.y.z", False) -def test_from_x_import_y(): +def test_from_x_import_y(check_stmts): check_stmts("from x import y", False) -def test_from_dot_import_y(): +def test_from_dot_import_y(check_stmts): check_stmts("from . import y", False) -def test_from_dotx_import_y(): +def test_from_dotx_import_y(check_stmts): check_stmts("from .x import y", False) -def test_from_dotdotx_import_y(): +def test_from_dotdotx_import_y(check_stmts): check_stmts("from ..x import y", False) -def test_from_dotdotdotx_import_y(): +def test_from_dotdotdotx_import_y(check_stmts): check_stmts("from ...x import y", False) -def test_from_dotdotdotdotx_import_y(): +def test_from_dotdotdotdotx_import_y(check_stmts): check_stmts("from ....x import y", False) -def test_from_import_x_y(): +def test_from_import_x_y(check_stmts): check_stmts("import x, y", False) -def test_from_import_x_y_z(): +def test_from_import_x_y_z(check_stmts): check_stmts("import x, y, z", False) -def test_from_dot_import_x_y(): +def test_from_dot_import_x_y(check_stmts): check_stmts("from . import x, y", False) -def test_from_dot_import_x_y_z(): +def test_from_dot_import_x_y_z(check_stmts): check_stmts("from . import x, y, z", False) -def test_from_dot_import_group_x_y(): +def test_from_dot_import_group_x_y(check_stmts): check_stmts("from . import (x, y)", False) -def test_import_x_as_y(): +def test_import_x_as_y(check_stmts): check_stmts("import x as y", False) -def test_import_xy_as_z(): +def test_import_xy_as_z(check_stmts): check_stmts("import x.y as z", False) -def test_import_x_y_as_z(): +def test_import_x_y_as_z(check_stmts): check_stmts("import x, y as z", False) -def test_import_x_as_y_z(): +def test_import_x_as_y_z(check_stmts): check_stmts("import x as y, z", False) -def test_import_x_as_y_z_as_a(): +def test_import_x_as_y_z_as_a(check_stmts): check_stmts("import x as y, z as a", False) -def test_from_dot_import_x_as_y(): +def test_from_dot_import_x_as_y(check_stmts): check_stmts("from . import x as y", False) -def test_from_x_import_star(): +def test_from_x_import_star(check_stmts): check_stmts("from x import *", False) -def test_from_x_import_group_x_y_z(): +def test_from_x_import_group_x_y_z(check_stmts): check_stmts("from x import (x, y, z)", False) -def test_from_x_import_group_x_y_z_comma(): +def test_from_x_import_group_x_y_z_comma(check_stmts): check_stmts("from x import (x, y, z,)", False) -def test_from_x_import_y_as_z(): +def test_from_x_import_y_as_z(check_stmts): check_stmts("from x import y as z", False) -def test_from_x_import_y_as_z_a_as_b(): +def test_from_x_import_y_as_z_a_as_b(check_stmts): check_stmts("from x import y as z, a as b", False) -def test_from_dotx_import_y_as_z_a_as_b_c_as_d(): +def test_from_dotx_import_y_as_z_a_as_b_c_as_d(check_stmts): check_stmts("from .x import y as z, a as b, c as d", False) -def test_continue(): +def test_continue(check_stmts): check_stmts("continue", False) -def test_break(): +def test_break(check_stmts): check_stmts("break", False) -def test_global(): +def test_global(check_stmts): check_stmts("global x", False) -def test_global_xy(): +def test_global_xy(check_stmts): check_stmts("global x, y", False) -def test_nonlocal_x(): +def test_nonlocal_x(check_stmts): check_stmts("nonlocal x", False) -def test_nonlocal_xy(): +def test_nonlocal_xy(check_stmts): check_stmts("nonlocal x, y", False) -def test_yield(): +def test_yield(check_stmts): check_stmts("yield", False) -def test_yield_x(): +def test_yield_x(check_stmts): check_stmts("yield x", False) -def test_yield_x_comma(): +def test_yield_x_comma(check_stmts): check_stmts("yield x,", False) -def test_yield_x_y(): +def test_yield_x_y(check_stmts): check_stmts("yield x, y", False) @skip_if_pre_3_8 -def test_yield_x_starexpr(): +def test_yield_x_starexpr(check_stmts): check_stmts("yield x, *[y, z]", False) -def test_yield_from_x(): +def test_yield_from_x(check_stmts): check_stmts("yield from x", False) -def test_return(): +def test_return(check_stmts): check_stmts("return", False) -def test_return_x(): +def test_return_x(check_stmts): check_stmts("return x", False) -def test_return_x_comma(): +def test_return_x_comma(check_stmts): check_stmts("return x,", False) -def test_return_x_y(): +def test_return_x_y(check_stmts): check_stmts("return x, y", False) @skip_if_pre_3_8 -def test_return_x_starexpr(): +def test_return_x_starexpr(check_stmts): check_stmts("return x, *[y, z]", False) -def test_if_true(): +def test_if_true(check_stmts): check_stmts("if True:\n pass") -def test_if_true_twolines(): +def test_if_true_twolines(check_stmts): check_stmts("if True:\n pass\n pass") -def test_if_true_twolines_deindent(): +def test_if_true_twolines_deindent(check_stmts): check_stmts("if True:\n pass\n pass\npass") -def test_if_true_else(): +def test_if_true_else(check_stmts): check_stmts("if True:\n pass\nelse: \n pass") -def test_if_true_x(): +def test_if_true_x(check_stmts): check_stmts("if True:\n x = 42") -def test_if_switch(): +def test_if_switch(check_stmts): check_stmts("x = 42\nif x == 1:\n pass") -def test_if_switch_elif1_else(): +def test_if_switch_elif1_else(check_stmts): check_stmts("x = 42\nif x == 1:\n pass\n" "elif x == 2:\n pass\nelse:\n pass") -def test_if_switch_elif2_else(): +def test_if_switch_elif2_else(check_stmts): check_stmts( "x = 42\nif x == 1:\n pass\n" "elif x == 2:\n pass\n" @@ -1696,380 +1720,380 @@ def test_if_switch_elif2_else(): ) -def test_if_nested(): +def test_if_nested(check_stmts): check_stmts("x = 42\nif x == 1:\n pass\n if x == 4:\n pass") -def test_while(): +def test_while(check_stmts): check_stmts("while False:\n pass") -def test_while_else(): +def test_while_else(check_stmts): check_stmts("while False:\n pass\nelse:\n pass") -def test_for(): +def test_for(check_stmts): check_stmts("for x in range(6):\n pass") -def test_for_zip(): +def test_for_zip(check_stmts): check_stmts('for x, y in zip(range(6), "123456"):\n pass') -def test_for_idx(): +def test_for_idx(check_stmts): check_stmts("x = [42]\nfor x[0] in range(3):\n pass") -def test_for_zip_idx(): +def test_for_zip_idx(check_stmts): check_stmts('x = [42]\nfor x[0], y in zip(range(6), "123456"):\n' " pass") -def test_for_attr(): +def test_for_attr(check_stmts): check_stmts("for x.a in range(3):\n pass", False) -def test_for_zip_attr(): +def test_for_zip_attr(check_stmts): check_stmts('for x.a, y in zip(range(6), "123456"):\n pass', False) -def test_for_else(): +def test_for_else(check_stmts): check_stmts("for x in range(6):\n pass\nelse: pass") -def test_async_for(): +def test_async_for(check_stmts): check_stmts("async def f():\n async for x in y:\n pass\n", False) -def test_with(): +def test_with(check_stmts): check_stmts("with x:\n pass", False) -def test_with_as(): +def test_with_as(check_stmts): check_stmts("with x as y:\n pass", False) -def test_with_xy(): +def test_with_xy(check_stmts): check_stmts("with x, y:\n pass", False) -def test_with_x_as_y_z(): +def test_with_x_as_y_z(check_stmts): check_stmts("with x as y, z:\n pass", False) -def test_with_x_as_y_a_as_b(): +def test_with_x_as_y_a_as_b(check_stmts): check_stmts("with x as y, a as b:\n pass", False) -def test_with_in_func(): +def test_with_in_func(check_stmts): check_stmts("def f():\n with x:\n pass\n") -def test_async_with(): +def test_async_with(check_stmts): check_stmts("async def f():\n async with x as y:\n pass\n", False) -def test_try(): +def test_try(check_stmts): check_stmts("try:\n pass\nexcept:\n pass", False) -def test_try_except_t(): +def test_try_except_t(check_stmts): check_stmts("try:\n pass\nexcept TypeError:\n pass", False) -def test_try_except_t_as_e(): +def test_try_except_t_as_e(check_stmts): check_stmts("try:\n pass\nexcept TypeError as e:\n pass", False) -def test_try_except_t_u(): +def test_try_except_t_u(check_stmts): check_stmts("try:\n pass\nexcept (TypeError, SyntaxError):\n pass", False) -def test_try_except_t_u_as_e(): +def test_try_except_t_u_as_e(check_stmts): check_stmts("try:\n pass\nexcept (TypeError, SyntaxError) as e:\n pass", False) -def test_try_except_t_except_u(): +def test_try_except_t_except_u(check_stmts): check_stmts( "try:\n pass\nexcept TypeError:\n pass\n" "except SyntaxError as f:\n pass", False, ) -def test_try_except_else(): +def test_try_except_else(check_stmts): check_stmts("try:\n pass\nexcept:\n pass\nelse: pass", False) -def test_try_except_finally(): +def test_try_except_finally(check_stmts): check_stmts("try:\n pass\nexcept:\n pass\nfinally: pass", False) -def test_try_except_else_finally(): +def test_try_except_else_finally(check_stmts): check_stmts( "try:\n pass\nexcept:\n pass\nelse:\n pass" "\nfinally: pass", False ) -def test_try_finally(): +def test_try_finally(check_stmts): check_stmts("try:\n pass\nfinally: pass", False) -def test_func(): +def test_func(check_stmts): check_stmts("def f():\n pass") -def test_func_ret(): +def test_func_ret(check_stmts): check_stmts("def f():\n return") -def test_func_ret_42(): +def test_func_ret_42(check_stmts): check_stmts("def f():\n return 42") -def test_func_ret_42_65(): +def test_func_ret_42_65(check_stmts): check_stmts("def f():\n return 42, 65") -def test_func_rarrow(): +def test_func_rarrow(check_stmts): check_stmts("def f() -> int:\n pass") -def test_func_x(): +def test_func_x(check_stmts): check_stmts("def f(x):\n return x") -def test_func_kwx(): +def test_func_kwx(check_stmts): check_stmts("def f(x=42):\n return x") -def test_func_x_y(): +def test_func_x_y(check_stmts): check_stmts("def f(x, y):\n return x") -def test_func_x_y_z(): +def test_func_x_y_z(check_stmts): check_stmts("def f(x, y, z):\n return x") -def test_func_x_kwy(): +def test_func_x_kwy(check_stmts): check_stmts("def f(x, y=42):\n return x") -def test_func_kwx_kwy(): +def test_func_kwx_kwy(check_stmts): check_stmts("def f(x=65, y=42):\n return x") -def test_func_kwx_kwy_kwz(): +def test_func_kwx_kwy_kwz(check_stmts): check_stmts("def f(x=65, y=42, z=1):\n return x") -def test_func_x_comma(): +def test_func_x_comma(check_stmts): check_stmts("def f(x,):\n return x") -def test_func_x_y_comma(): +def test_func_x_y_comma(check_stmts): check_stmts("def f(x, y,):\n return x") -def test_func_x_y_z_comma(): +def test_func_x_y_z_comma(check_stmts): check_stmts("def f(x, y, z,):\n return x") -def test_func_x_kwy_comma(): +def test_func_x_kwy_comma(check_stmts): check_stmts("def f(x, y=42,):\n return x") -def test_func_kwx_kwy_comma(): +def test_func_kwx_kwy_comma(check_stmts): check_stmts("def f(x=65, y=42,):\n return x") -def test_func_kwx_kwy_kwz_comma(): +def test_func_kwx_kwy_kwz_comma(check_stmts): check_stmts("def f(x=65, y=42, z=1,):\n return x") -def test_func_args(): +def test_func_args(check_stmts): check_stmts("def f(*args):\n return 42") -def test_func_args_x(): +def test_func_args_x(check_stmts): check_stmts("def f(*args, x):\n return 42") -def test_func_args_x_y(): +def test_func_args_x_y(check_stmts): check_stmts("def f(*args, x, y):\n return 42") -def test_func_args_x_kwy(): +def test_func_args_x_kwy(check_stmts): check_stmts("def f(*args, x, y=10):\n return 42") -def test_func_args_kwx_y(): +def test_func_args_kwx_y(check_stmts): check_stmts("def f(*args, x=10, y):\n return 42") -def test_func_args_kwx_kwy(): +def test_func_args_kwx_kwy(check_stmts): check_stmts("def f(*args, x=42, y=65):\n return 42") -def test_func_x_args(): +def test_func_x_args(check_stmts): check_stmts("def f(x, *args):\n return 42") -def test_func_x_args_y(): +def test_func_x_args_y(check_stmts): check_stmts("def f(x, *args, y):\n return 42") -def test_func_x_args_y_z(): +def test_func_x_args_y_z(check_stmts): check_stmts("def f(x, *args, y, z):\n return 42") -def test_func_kwargs(): +def test_func_kwargs(check_stmts): check_stmts("def f(**kwargs):\n return 42") -def test_func_x_kwargs(): +def test_func_x_kwargs(check_stmts): check_stmts("def f(x, **kwargs):\n return 42") -def test_func_x_y_kwargs(): +def test_func_x_y_kwargs(check_stmts): check_stmts("def f(x, y, **kwargs):\n return 42") -def test_func_x_kwy_kwargs(): +def test_func_x_kwy_kwargs(check_stmts): check_stmts("def f(x, y=42, **kwargs):\n return 42") -def test_func_args_kwargs(): +def test_func_args_kwargs(check_stmts): check_stmts("def f(*args, **kwargs):\n return 42") -def test_func_x_args_kwargs(): +def test_func_x_args_kwargs(check_stmts): check_stmts("def f(x, *args, **kwargs):\n return 42") -def test_func_x_y_args_kwargs(): +def test_func_x_y_args_kwargs(check_stmts): check_stmts("def f(x, y, *args, **kwargs):\n return 42") -def test_func_kwx_args_kwargs(): +def test_func_kwx_args_kwargs(check_stmts): check_stmts("def f(x=10, *args, **kwargs):\n return 42") -def test_func_x_kwy_args_kwargs(): +def test_func_x_kwy_args_kwargs(check_stmts): check_stmts("def f(x, y=42, *args, **kwargs):\n return 42") -def test_func_x_args_y_kwargs(): +def test_func_x_args_y_kwargs(check_stmts): check_stmts("def f(x, *args, y, **kwargs):\n return 42") -def test_func_x_args_kwy_kwargs(): +def test_func_x_args_kwy_kwargs(check_stmts): check_stmts("def f(x, *args, y=42, **kwargs):\n return 42") -def test_func_args_y_kwargs(): +def test_func_args_y_kwargs(check_stmts): check_stmts("def f(*args, y, **kwargs):\n return 42") -def test_func_star_x(): +def test_func_star_x(check_stmts): check_stmts("def f(*, x):\n return 42") -def test_func_star_x_y(): +def test_func_star_x_y(check_stmts): check_stmts("def f(*, x, y):\n return 42") -def test_func_star_x_kwargs(): +def test_func_star_x_kwargs(check_stmts): check_stmts("def f(*, x, **kwargs):\n return 42") -def test_func_star_kwx_kwargs(): +def test_func_star_kwx_kwargs(check_stmts): check_stmts("def f(*, x=42, **kwargs):\n return 42") -def test_func_x_star_y(): +def test_func_x_star_y(check_stmts): check_stmts("def f(x, *, y):\n return 42") -def test_func_x_y_star_z(): +def test_func_x_y_star_z(check_stmts): check_stmts("def f(x, y, *, z):\n return 42") -def test_func_x_kwy_star_y(): +def test_func_x_kwy_star_y(check_stmts): check_stmts("def f(x, y=42, *, z):\n return 42") -def test_func_x_kwy_star_kwy(): +def test_func_x_kwy_star_kwy(check_stmts): check_stmts("def f(x, y=42, *, z=65):\n return 42") -def test_func_x_star_y_kwargs(): +def test_func_x_star_y_kwargs(check_stmts): check_stmts("def f(x, *, y, **kwargs):\n return 42") @skip_if_pre_3_8 -def test_func_x_divide(): +def test_func_x_divide(check_stmts): check_stmts("def f(x, /):\n return 42") @skip_if_pre_3_8 -def test_func_x_divide_y_star_z_kwargs(): +def test_func_x_divide_y_star_z_kwargs(check_stmts): check_stmts("def f(x, /, y, *, z, **kwargs):\n return 42") -def test_func_tx(): +def test_func_tx(check_stmts): check_stmts("def f(x:int):\n return x") -def test_func_txy(): +def test_func_txy(check_stmts): check_stmts("def f(x:int, y:float=10.0):\n return x") -def test_class(): +def test_class(check_stmts): check_stmts("class X:\n pass") -def test_class_obj(): +def test_class_obj(check_stmts): check_stmts("class X(object):\n pass") -def test_class_int_flt(): +def test_class_int_flt(check_stmts): check_stmts("class X(int, object):\n pass") -def test_class_obj_kw(): +def test_class_obj_kw(check_stmts): # technically valid syntax, though it will fail to compile check_stmts("class X(object=5):\n pass", False) -def test_decorator(): +def test_decorator(check_stmts): check_stmts("@g\ndef f():\n pass", False) -def test_decorator_2(): +def test_decorator_2(check_stmts): check_stmts("@h\n@g\ndef f():\n pass", False) -def test_decorator_call(): +def test_decorator_call(check_stmts): check_stmts("@g()\ndef f():\n pass", False) -def test_decorator_call_args(): +def test_decorator_call_args(check_stmts): check_stmts("@g(x, y=10)\ndef f():\n pass", False) -def test_decorator_dot_call_args(): +def test_decorator_dot_call_args(check_stmts): check_stmts("@h.g(x, y=10)\ndef f():\n pass", False) -def test_decorator_dot_dot_call_args(): +def test_decorator_dot_dot_call_args(check_stmts): check_stmts("@i.h.g(x, y=10)\ndef f():\n pass", False) -def test_broken_prompt_func(): +def test_broken_prompt_func(check_stmts): code = "def prompt():\n" " return '{user}'.format(\n" " user='me')\n" check_stmts(code, False) -def test_class_with_methods(): +def test_class_with_methods(check_stmts): code = ( "class Test:\n" " def __init__(self):\n" @@ -2080,7 +2104,7 @@ def test_class_with_methods(): check_stmts(code, False) -def test_nested_functions(): +def test_nested_functions(check_stmts): code = ( "def test(x):\n" " def test2(y):\n" @@ -2090,7 +2114,7 @@ def test_nested_functions(): check_stmts(code, False) -def test_function_blank_line(): +def test_function_blank_line(check_stmts): code = ( "def foo():\n" " ascii_art = [\n" @@ -2109,35 +2133,35 @@ def test_function_blank_line(): check_stmts(code, False) -def test_async_func(): +def test_async_func(check_stmts): check_stmts("async def f():\n pass\n") -def test_async_decorator(): +def test_async_decorator(check_stmts): check_stmts("@g\nasync def f():\n pass", False) -def test_async_await(): +def test_async_await(check_stmts): check_stmts("async def f():\n await fut\n", False) @skip_if_pre_3_8 -def test_named_expr_args(): +def test_named_expr_args(check_stmts): check_stmts("id(x := 42)") @skip_if_pre_3_8 -def test_named_expr_if(): +def test_named_expr_if(check_stmts): check_stmts("if (x := 42) > 0:\n x += 1") @skip_if_pre_3_8 -def test_named_expr_elif(): +def test_named_expr_elif(check_stmts): check_stmts("if False:\n pass\nelif x := 42:\n x += 1") @skip_if_pre_3_8 -def test_named_expr_while(): +def test_named_expr_while(check_stmts): check_stmts("y = 42\nwhile (x := y) < 43:\n y += 1") @@ -2146,7 +2170,7 @@ def test_named_expr_while(): # -def test_path_literal(): +def test_path_literal(check_xonsh_ast): check_xonsh_ast({}, 'p"/foo"', False) check_xonsh_ast({}, 'pr"/foo"', False) check_xonsh_ast({}, 'rp"/foo"', False) @@ -2154,7 +2178,7 @@ def test_path_literal(): check_xonsh_ast({}, 'Rp"/foo"', False) -def test_path_fstring_literal(): +def test_path_fstring_literal(check_xonsh_ast): check_xonsh_ast({}, 'pf"/foo"', False) check_xonsh_ast({}, 'fp"/foo"', False) check_xonsh_ast({}, 'pF"/foo"', False) @@ -2165,39 +2189,39 @@ def test_path_fstring_literal(): check_xonsh_ast({}, 'Fp"/foo{1+1}"', False) -def test_dollar_name(): +def test_dollar_name(check_xonsh_ast): check_xonsh_ast({"WAKKA": 42}, "$WAKKA") -def test_dollar_py(): +def test_dollar_py(check_xonsh): check_xonsh({"WAKKA": 42}, 'x = "WAKKA"; y = ${x}') -def test_dollar_py_test(): +def test_dollar_py_test(check_xonsh_ast): check_xonsh_ast({"WAKKA": 42}, '${None or "WAKKA"}') -def test_dollar_py_recursive_name(): +def test_dollar_py_recursive_name(check_xonsh_ast): check_xonsh_ast({"WAKKA": 42, "JAWAKA": "WAKKA"}, "${$JAWAKA}") -def test_dollar_py_test_recursive_name(): +def test_dollar_py_test_recursive_name(check_xonsh_ast): check_xonsh_ast({"WAKKA": 42, "JAWAKA": "WAKKA"}, "${None or $JAWAKA}") -def test_dollar_py_test_recursive_test(): +def test_dollar_py_test_recursive_test(check_xonsh_ast): check_xonsh_ast({"WAKKA": 42, "JAWAKA": "WAKKA"}, '${${"JAWA" + $JAWAKA[-2:]}}') -def test_dollar_name_set(): +def test_dollar_name_set(check_xonsh): check_xonsh({"WAKKA": 42}, "$WAKKA = 42") -def test_dollar_py_set(): +def test_dollar_py_set(check_xonsh): check_xonsh({"WAKKA": 42}, 'x = "WAKKA"; ${x} = 65') -def test_dollar_sub(): +def test_dollar_sub(check_xonsh_ast): check_xonsh_ast({}, "$(ls)", False) @@ -2209,29 +2233,29 @@ def test_dollar_sub(): "$( ls )", ], ) -def test_dollar_sub_space(expr): +def test_dollar_sub_space(expr, check_xonsh_ast): check_xonsh_ast({}, expr, False) -def test_ls_dot(): +def test_ls_dot(check_xonsh_ast): check_xonsh_ast({}, "$(ls .)", False) -def test_lambda_in_atparens(): +def test_lambda_in_atparens(check_xonsh_ast): check_xonsh_ast( {}, '$(echo hello | @(lambda a, s=None: "hey!") foo bar baz)', False ) -def test_generator_in_atparens(): +def test_generator_in_atparens(check_xonsh_ast): check_xonsh_ast({}, "$(echo @(i**2 for i in range(20)))", False) -def test_bare_tuple_in_atparens(): +def test_bare_tuple_in_atparens(check_xonsh_ast): check_xonsh_ast({}, '$(echo @("a", 7))', False) -def test_nested_madness(): +def test_nested_madness(check_xonsh_ast): check_xonsh_ast( {}, "$(@$(which echo) ls | @(lambda a, s=None: $(@(s.strip()) @(a[1]))) foo -la baz)", @@ -2239,39 +2263,39 @@ def test_nested_madness(): ) -def test_atparens_intoken(): +def test_atparens_intoken(check_xonsh_ast): check_xonsh_ast({}, "![echo /x/@(y)/z]", False) -def test_ls_dot_nesting(): +def test_ls_dot_nesting(check_xonsh_ast): check_xonsh_ast({}, '$(ls @(None or "."))', False) -def test_ls_dot_nesting_var(): +def test_ls_dot_nesting_var(check_xonsh): check_xonsh({}, 'x = "."; $(ls @(None or x))', False) -def test_ls_dot_str(): +def test_ls_dot_str(check_xonsh_ast): check_xonsh_ast({}, '$(ls ".")', False) -def test_ls_nest_ls(): +def test_ls_nest_ls(check_xonsh_ast): check_xonsh_ast({}, "$(ls $(ls))", False) -def test_ls_nest_ls_dashl(): +def test_ls_nest_ls_dashl(check_xonsh_ast): check_xonsh_ast({}, "$(ls $(ls) -l)", False) -def test_ls_envvar_strval(): +def test_ls_envvar_strval(check_xonsh_ast): check_xonsh_ast({"WAKKA": "."}, "$(ls $WAKKA)", False) -def test_ls_envvar_listval(): +def test_ls_envvar_listval(check_xonsh_ast): check_xonsh_ast({"WAKKA": [".", "."]}, "$(ls $WAKKA)", False) -def test_bang_sub(): +def test_bang_sub(check_xonsh_ast): check_xonsh_ast({}, "!(ls)", False) @@ -2283,194 +2307,194 @@ def test_bang_sub(): "!( ls )", ], ) -def test_bang_sub_space(expr): +def test_bang_sub_space(expr, check_xonsh_ast): check_xonsh_ast({}, expr, False) -def test_bang_ls_dot(): +def test_bang_ls_dot(check_xonsh_ast): check_xonsh_ast({}, "!(ls .)", False) -def test_bang_ls_dot_nesting(): +def test_bang_ls_dot_nesting(check_xonsh_ast): check_xonsh_ast({}, '!(ls @(None or "."))', False) -def test_bang_ls_dot_nesting_var(): +def test_bang_ls_dot_nesting_var(check_xonsh): check_xonsh({}, 'x = "."; !(ls @(None or x))', False) -def test_bang_ls_dot_str(): +def test_bang_ls_dot_str(check_xonsh_ast): check_xonsh_ast({}, '!(ls ".")', False) -def test_bang_ls_nest_ls(): +def test_bang_ls_nest_ls(check_xonsh_ast): check_xonsh_ast({}, "!(ls $(ls))", False) -def test_bang_ls_nest_ls_dashl(): +def test_bang_ls_nest_ls_dashl(check_xonsh_ast): check_xonsh_ast({}, "!(ls $(ls) -l)", False) -def test_bang_ls_envvar_strval(): +def test_bang_ls_envvar_strval(check_xonsh_ast): check_xonsh_ast({"WAKKA": "."}, "!(ls $WAKKA)", False) -def test_bang_ls_envvar_listval(): +def test_bang_ls_envvar_listval(check_xonsh_ast): check_xonsh_ast({"WAKKA": [".", "."]}, "!(ls $WAKKA)", False) -def test_bang_envvar_args(): +def test_bang_envvar_args(check_xonsh_ast): check_xonsh_ast({"LS": "ls"}, "!($LS .)", False) -def test_question(): +def test_question(check_xonsh_ast): check_xonsh_ast({}, "range?") -def test_dobquestion(): +def test_dobquestion(check_xonsh_ast): check_xonsh_ast({}, "range??") -def test_question_chain(): +def test_question_chain(check_xonsh_ast): check_xonsh_ast({}, "range?.index?") -def test_ls_regex(): +def test_ls_regex(check_xonsh_ast): check_xonsh_ast({}, "$(ls `[Ff]+i*LE` -l)", False) -def test_backtick(): +def test_backtick(check_xonsh_ast): check_xonsh_ast({}, "print(`.*`)", False) -def test_ls_regex_octothorpe(): +def test_ls_regex_octothorpe(check_xonsh_ast): check_xonsh_ast({}, "$(ls `#[Ff]+i*LE` -l)", False) -def test_ls_explicitregex(): +def test_ls_explicitregex(check_xonsh_ast): check_xonsh_ast({}, "$(ls r`[Ff]+i*LE` -l)", False) -def test_rbacktick(): +def test_rbacktick(check_xonsh_ast): check_xonsh_ast({}, "print(r`.*`)", False) -def test_ls_explicitregex_octothorpe(): +def test_ls_explicitregex_octothorpe(check_xonsh_ast): check_xonsh_ast({}, "$(ls r`#[Ff]+i*LE` -l)", False) -def test_ls_glob(): +def test_ls_glob(check_xonsh_ast): check_xonsh_ast({}, "$(ls g`[Ff]+i*LE` -l)", False) -def test_gbacktick(): +def test_gbacktick(check_xonsh_ast): check_xonsh_ast({}, "print(g`.*`)", False) -def test_pbacktrick(): +def test_pbacktrick(check_xonsh_ast): check_xonsh_ast({}, "print(p`.*`)", False) -def test_pgbacktick(): +def test_pgbacktick(check_xonsh_ast): check_xonsh_ast({}, "print(pg`.*`)", False) -def test_prbacktick(): +def test_prbacktick(check_xonsh_ast): check_xonsh_ast({}, "print(pr`.*`)", False) -def test_ls_glob_octothorpe(): +def test_ls_glob_octothorpe(check_xonsh_ast): check_xonsh_ast({}, "$(ls g`#[Ff]+i*LE` -l)", False) -def test_ls_customsearch(): +def test_ls_customsearch(check_xonsh_ast): check_xonsh_ast({}, "$(ls @foo`[Ff]+i*LE` -l)", False) -def test_custombacktick(): +def test_custombacktick(check_xonsh_ast): check_xonsh_ast({}, "print(@foo`.*`)", False) -def test_ls_customsearch_octothorpe(): +def test_ls_customsearch_octothorpe(check_xonsh_ast): check_xonsh_ast({}, "$(ls @foo`#[Ff]+i*LE` -l)", False) -def test_injection(): +def test_injection(check_xonsh_ast): check_xonsh_ast({}, "$[@$(which python)]", False) -def test_rhs_nested_injection(): +def test_rhs_nested_injection(check_xonsh_ast): check_xonsh_ast({}, "$[ls @$(dirname @$(which python))]", False) -def test_merged_injection(): +def test_merged_injection(check_xonsh_ast): tree = check_xonsh_ast({}, "![a@$(echo 1 2)b]", False, return_obs=True) assert isinstance(tree, AST) func = tree.body.args[0].right.func assert func.attr == "list_of_list_of_strs_outer_product" -def test_backtick_octothorpe(): +def test_backtick_octothorpe(check_xonsh_ast): check_xonsh_ast({}, "print(`#.*`)", False) -def test_uncaptured_sub(): +def test_uncaptured_sub(check_xonsh_ast): check_xonsh_ast({}, "$[ls]", False) -def test_hiddenobj_sub(): +def test_hiddenobj_sub(check_xonsh_ast): check_xonsh_ast({}, "![ls]", False) -def test_slash_envarv_echo(): +def test_slash_envarv_echo(check_xonsh_ast): check_xonsh_ast({}, "![echo $HOME/place]", False) -def test_echo_double_eq(): +def test_echo_double_eq(check_xonsh_ast): check_xonsh_ast({}, "![echo yo==yo]", False) -def test_bang_two_cmds_one_pipe(): +def test_bang_two_cmds_one_pipe(check_xonsh_ast): check_xonsh_ast({}, "!(ls | grep wakka)", False) -def test_bang_three_cmds_two_pipes(): +def test_bang_three_cmds_two_pipes(check_xonsh_ast): check_xonsh_ast({}, "!(ls | grep wakka | grep jawaka)", False) -def test_bang_one_cmd_write(): +def test_bang_one_cmd_write(check_xonsh_ast): check_xonsh_ast({}, "!(ls > x.py)", False) -def test_bang_one_cmd_append(): +def test_bang_one_cmd_append(check_xonsh_ast): check_xonsh_ast({}, "!(ls >> x.py)", False) -def test_bang_two_cmds_write(): +def test_bang_two_cmds_write(check_xonsh_ast): check_xonsh_ast({}, "!(ls | grep wakka > x.py)", False) -def test_bang_two_cmds_append(): +def test_bang_two_cmds_append(check_xonsh_ast): check_xonsh_ast({}, "!(ls | grep wakka >> x.py)", False) -def test_bang_cmd_background(): +def test_bang_cmd_background(check_xonsh_ast): check_xonsh_ast({}, "!(emacs ugggh &)", False) -def test_bang_cmd_background_nospace(): +def test_bang_cmd_background_nospace(check_xonsh_ast): check_xonsh_ast({}, "!(emacs ugggh&)", False) -def test_bang_git_quotes_no_space(): +def test_bang_git_quotes_no_space(check_xonsh_ast): check_xonsh_ast({}, '![git commit -am "wakka"]', False) -def test_bang_git_quotes_space(): +def test_bang_git_quotes_space(check_xonsh_ast): check_xonsh_ast({}, '![git commit -am "wakka jawaka"]', False) -def test_bang_git_two_quotes_space(): +def test_bang_git_two_quotes_space(check_xonsh): check_xonsh( {}, '![git commit -am "wakka jawaka"]\n' '![git commit -am "flock jawaka"]\n', @@ -2478,7 +2502,7 @@ def test_bang_git_two_quotes_space(): ) -def test_bang_git_two_quotes_space_space(): +def test_bang_git_two_quotes_space_space(check_xonsh): check_xonsh( {}, '![git commit -am "wakka jawaka" ]\n' @@ -2487,83 +2511,83 @@ def test_bang_git_two_quotes_space_space(): ) -def test_bang_ls_quotes_3_space(): +def test_bang_ls_quotes_3_space(check_xonsh_ast): check_xonsh_ast({}, '![ls "wakka jawaka baraka"]', False) -def test_two_cmds_one_pipe(): +def test_two_cmds_one_pipe(check_xonsh_ast): check_xonsh_ast({}, "$(ls | grep wakka)", False) -def test_three_cmds_two_pipes(): +def test_three_cmds_two_pipes(check_xonsh_ast): check_xonsh_ast({}, "$(ls | grep wakka | grep jawaka)", False) -def test_two_cmds_one_and_brackets(): +def test_two_cmds_one_and_brackets(check_xonsh_ast): check_xonsh_ast({}, "![ls me] and ![grep wakka]", False) -def test_three_cmds_two_ands(): +def test_three_cmds_two_ands(check_xonsh_ast): check_xonsh_ast({}, "![ls] and ![grep wakka] and ![grep jawaka]", False) -def test_two_cmds_one_doubleamps(): +def test_two_cmds_one_doubleamps(check_xonsh_ast): check_xonsh_ast({}, "![ls] && ![grep wakka]", False) -def test_three_cmds_two_doubleamps(): +def test_three_cmds_two_doubleamps(check_xonsh_ast): check_xonsh_ast({}, "![ls] && ![grep wakka] && ![grep jawaka]", False) -def test_two_cmds_one_or(): +def test_two_cmds_one_or(check_xonsh_ast): check_xonsh_ast({}, "![ls] or ![grep wakka]", False) -def test_three_cmds_two_ors(): +def test_three_cmds_two_ors(check_xonsh_ast): check_xonsh_ast({}, "![ls] or ![grep wakka] or ![grep jawaka]", False) -def test_two_cmds_one_doublepipe(): +def test_two_cmds_one_doublepipe(check_xonsh_ast): check_xonsh_ast({}, "![ls] || ![grep wakka]", False) -def test_three_cmds_two_doublepipe(): +def test_three_cmds_two_doublepipe(check_xonsh_ast): check_xonsh_ast({}, "![ls] || ![grep wakka] || ![grep jawaka]", False) -def test_one_cmd_write(): +def test_one_cmd_write(check_xonsh_ast): check_xonsh_ast({}, "$(ls > x.py)", False) -def test_one_cmd_append(): +def test_one_cmd_append(check_xonsh_ast): check_xonsh_ast({}, "$(ls >> x.py)", False) -def test_two_cmds_write(): +def test_two_cmds_write(check_xonsh_ast): check_xonsh_ast({}, "$(ls | grep wakka > x.py)", False) -def test_two_cmds_append(): +def test_two_cmds_append(check_xonsh_ast): check_xonsh_ast({}, "$(ls | grep wakka >> x.py)", False) -def test_cmd_background(): +def test_cmd_background(check_xonsh_ast): check_xonsh_ast({}, "$(emacs ugggh &)", False) -def test_cmd_background_nospace(): +def test_cmd_background_nospace(check_xonsh_ast): check_xonsh_ast({}, "$(emacs ugggh&)", False) -def test_git_quotes_no_space(): +def test_git_quotes_no_space(check_xonsh_ast): check_xonsh_ast({}, '$[git commit -am "wakka"]', False) -def test_git_quotes_space(): +def test_git_quotes_space(check_xonsh_ast): check_xonsh_ast({}, '$[git commit -am "wakka jawaka"]', False) -def test_git_two_quotes_space(): +def test_git_two_quotes_space(check_xonsh): check_xonsh( {}, '$[git commit -am "wakka jawaka"]\n' '$[git commit -am "flock jawaka"]\n', @@ -2571,7 +2595,7 @@ def test_git_two_quotes_space(): ) -def test_git_two_quotes_space_space(): +def test_git_two_quotes_space_space(check_xonsh): check_xonsh( {}, '$[git commit -am "wakka jawaka" ]\n' @@ -2580,36 +2604,36 @@ def test_git_two_quotes_space_space(): ) -def test_ls_quotes_3_space(): +def test_ls_quotes_3_space(check_xonsh_ast): check_xonsh_ast({}, '$[ls "wakka jawaka baraka"]', False) -def test_leading_envvar_assignment(): +def test_leading_envvar_assignment(check_xonsh_ast): check_xonsh_ast({}, "![$FOO='foo' $BAR=2 echo r'$BAR']", False) -def test_echo_comma(): +def test_echo_comma(check_xonsh_ast): check_xonsh_ast({}, "![echo ,]", False) -def test_echo_internal_comma(): +def test_echo_internal_comma(check_xonsh_ast): check_xonsh_ast({}, "![echo 1,2]", False) -def test_comment_only(): +def test_comment_only(check_xonsh_ast): check_xonsh_ast({}, "# hello") -def test_echo_slash_question(): +def test_echo_slash_question(check_xonsh_ast): check_xonsh_ast({}, "![echo /?]", False) -def test_bad_quotes(): +def test_bad_quotes(check_xonsh_ast): with pytest.raises(SyntaxError): check_xonsh_ast({}, '![echo """hello]', False) -def test_redirect(): +def test_redirect(check_xonsh_ast): assert check_xonsh_ast({}, "$[cat < input.txt]", False) assert check_xonsh_ast({}, "$[< input.txt cat]", False) @@ -2625,7 +2649,7 @@ def test_redirect(): "![(if True:\n ls\nelse:\n echo not true)]", ], ) -def test_use_subshell(case): +def test_use_subshell(case, check_xonsh_ast): check_xonsh_ast({}, case, False, debug_level=0) @@ -2639,26 +2663,26 @@ def test_use_subshell(case): "![< /path/to/input.txt > /path/to/output.txt]", ], ) -def test_redirect_abspath(case): +def test_redirect_abspath(case, check_xonsh_ast): assert check_xonsh_ast({}, case, False) @pytest.mark.parametrize("case", ["", "o", "out", "1"]) -def test_redirect_output(case): +def test_redirect_output(case, check_xonsh_ast): assert check_xonsh_ast({}, f'$[echo "test" {case}> test.txt]', False) assert check_xonsh_ast({}, f'$[< input.txt echo "test" {case}> test.txt]', False) assert check_xonsh_ast({}, f'$[echo "test" {case}> test.txt < input.txt]', False) @pytest.mark.parametrize("case", ["e", "err", "2"]) -def test_redirect_error(case): +def test_redirect_error(case, check_xonsh_ast): assert check_xonsh_ast({}, f'$[echo "test" {case}> test.txt]', False) assert check_xonsh_ast({}, f'$[< input.txt echo "test" {case}> test.txt]', False) assert check_xonsh_ast({}, f'$[echo "test" {case}> test.txt < input.txt]', False) @pytest.mark.parametrize("case", ["a", "all", "&"]) -def test_redirect_all(case): +def test_redirect_all(case, check_xonsh_ast): assert check_xonsh_ast({}, f'$[echo "test" {case}> test.txt]', False) assert check_xonsh_ast({}, f'$[< input.txt echo "test" {case}> test.txt]', False) assert check_xonsh_ast({}, f'$[echo "test" {case}> test.txt < input.txt]', False) @@ -2681,7 +2705,7 @@ def test_redirect_all(case): ], ) @pytest.mark.parametrize("o", ["", "o", "out", "1"]) -def test_redirect_error_to_output(r, o): +def test_redirect_error_to_output(r, o, check_xonsh_ast): assert check_xonsh_ast({}, f'$[echo "test" {r} {o}> test.txt]', False) assert check_xonsh_ast({}, f'$[< input.txt echo "test" {r} {o}> test.txt]', False) assert check_xonsh_ast({}, f'$[echo "test" {r} {o}> test.txt < input.txt]', False) @@ -2704,13 +2728,13 @@ def test_redirect_error_to_output(r, o): ], ) @pytest.mark.parametrize("e", ["e", "err", "2"]) -def test_redirect_output_to_error(r, e): +def test_redirect_output_to_error(r, e, check_xonsh_ast): assert check_xonsh_ast({}, f'$[echo "test" {r} {e}> test.txt]', False) assert check_xonsh_ast({}, f'$[< input.txt echo "test" {r} {e}> test.txt]', False) assert check_xonsh_ast({}, f'$[echo "test" {r} {e}> test.txt < input.txt]', False) -def test_macro_call_empty(): +def test_macro_call_empty(check_xonsh_ast): assert check_xonsh_ast({}, "f!()", False) @@ -2748,7 +2772,7 @@ MACRO_ARGS = [ @pytest.mark.parametrize("s", MACRO_ARGS) -def test_macro_call_one_arg(s): +def test_macro_call_one_arg(check_xonsh_ast, s): f = f"f!({s})" tree = check_xonsh_ast({}, f, False, return_obs=True) assert isinstance(tree, AST) @@ -2758,7 +2782,7 @@ def test_macro_call_one_arg(s): @pytest.mark.parametrize("s,t", itertools.product(MACRO_ARGS[::2], MACRO_ARGS[1::2])) -def test_macro_call_two_args(s, t): +def test_macro_call_two_args(check_xonsh_ast, s, t): f = f"f!({s}, {t})" tree = check_xonsh_ast({}, f, False, return_obs=True) assert isinstance(tree, AST) @@ -2771,7 +2795,7 @@ def test_macro_call_two_args(s, t): @pytest.mark.parametrize( "s,t,u", itertools.product(MACRO_ARGS[::3], MACRO_ARGS[1::3], MACRO_ARGS[2::3]) ) -def test_macro_call_three_args(s, t, u): +def test_macro_call_three_args(check_xonsh_ast, s, t, u): f = f"f!({s}, {t}, {u})" tree = check_xonsh_ast({}, f, False, return_obs=True) assert isinstance(tree, AST) @@ -2783,7 +2807,7 @@ def test_macro_call_three_args(s, t, u): @pytest.mark.parametrize("s", MACRO_ARGS) -def test_macro_call_one_trailing(s): +def test_macro_call_one_trailing(check_xonsh_ast, s): f = f"f!({s},)" tree = check_xonsh_ast({}, f, False, return_obs=True) assert isinstance(tree, AST) @@ -2793,7 +2817,7 @@ def test_macro_call_one_trailing(s): @pytest.mark.parametrize("s", MACRO_ARGS) -def test_macro_call_one_trailing_space(s): +def test_macro_call_one_trailing_space(check_xonsh_ast, s): f = f"f!( {s}, )" tree = check_xonsh_ast({}, f, False, return_obs=True) assert isinstance(tree, AST) @@ -2807,7 +2831,7 @@ SUBPROC_MACRO_OC = [("!(", ")"), ("$(", ")"), ("![", "]"), ("$[", "]")] @pytest.mark.parametrize("opener, closer", SUBPROC_MACRO_OC) @pytest.mark.parametrize("body", ["echo!", "echo !", "echo ! "]) -def test_empty_subprocbang(opener, closer, body): +def test_empty_subprocbang(opener, closer, body, check_xonsh_ast): tree = check_xonsh_ast({}, opener + body + closer, False, return_obs=True) assert isinstance(tree, AST) cmd = tree.body.args[0].elts @@ -2817,7 +2841,7 @@ def test_empty_subprocbang(opener, closer, body): @pytest.mark.parametrize("opener, closer", SUBPROC_MACRO_OC) @pytest.mark.parametrize("body", ["echo!x", "echo !x", "echo !x", "echo ! x"]) -def test_single_subprocbang(opener, closer, body): +def test_single_subprocbang(opener, closer, body, check_xonsh_ast): tree = check_xonsh_ast({}, opener + body + closer, False, return_obs=True) assert isinstance(tree, AST) cmd = tree.body.args[0].elts @@ -2829,7 +2853,7 @@ def test_single_subprocbang(opener, closer, body): @pytest.mark.parametrize( "body", ["echo -n!x", "echo -n!x", "echo -n !x", "echo -n ! x"] ) -def test_arg_single_subprocbang(opener, closer, body): +def test_arg_single_subprocbang(opener, closer, body, check_xonsh_ast): tree = check_xonsh_ast({}, opener + body + closer, False, return_obs=True) assert isinstance(tree, AST) cmd = tree.body.args[0].elts @@ -2842,7 +2866,9 @@ def test_arg_single_subprocbang(opener, closer, body): @pytest.mark.parametrize( "body", ["echo -n!x", "echo -n!x", "echo -n !x", "echo -n ! x"] ) -def test_arg_single_subprocbang_nested(opener, closer, ipener, iloser, body): +def test_arg_single_subprocbang_nested( + opener, closer, ipener, iloser, body, check_xonsh_ast +): tree = check_xonsh_ast({}, opener + body + closer, False, return_obs=True) assert isinstance(tree, AST) cmd = tree.body.args[0].elts @@ -2873,7 +2899,7 @@ def test_arg_single_subprocbang_nested(opener, closer, ipener, iloser, body): 'timeit!"!)"', ], ) -def test_many_subprocbang(opener, closer, body): +def test_many_subprocbang(opener, closer, body, check_xonsh_ast): tree = check_xonsh_ast({}, opener + body + closer, False, return_obs=True) assert isinstance(tree, AST) cmd = tree.body.args[0].elts @@ -2902,7 +2928,7 @@ WITH_BANG_RAWSUITES = [ @pytest.mark.parametrize("body", WITH_BANG_RAWSUITES) -def test_withbang_single_suite(body): +def test_withbang_single_suite(body, check_xonsh_ast): code = "with! x:\n{}".format(textwrap.indent(body, " ")) tree = check_xonsh_ast({}, code, False, return_obs=True, mode="exec") assert isinstance(tree, AST) @@ -2917,7 +2943,7 @@ def test_withbang_single_suite(body): @pytest.mark.parametrize("body", WITH_BANG_RAWSUITES) -def test_withbang_as_single_suite(body): +def test_withbang_as_single_suite(body, check_xonsh_ast): code = "with! x as y:\n{}".format(textwrap.indent(body, " ")) tree = check_xonsh_ast({}, code, False, return_obs=True, mode="exec") assert isinstance(tree, AST) @@ -2933,7 +2959,7 @@ def test_withbang_as_single_suite(body): @pytest.mark.parametrize("body", WITH_BANG_RAWSUITES) -def test_withbang_single_suite_trailing(body): +def test_withbang_single_suite_trailing(body, check_xonsh_ast): code = "with! x:\n{}\nprint(x)\n".format(textwrap.indent(body, " ")) tree = check_xonsh_ast( {}, @@ -2963,7 +2989,7 @@ WITH_BANG_RAWSIMPLE = [ @pytest.mark.parametrize("body", WITH_BANG_RAWSIMPLE) -def test_withbang_single_simple(body): +def test_withbang_single_simple(body, check_xonsh_ast): code = f"with! x: {body}\n" tree = check_xonsh_ast({}, code, False, return_obs=True, mode="exec") assert isinstance(tree, AST) @@ -2978,7 +3004,7 @@ def test_withbang_single_simple(body): @pytest.mark.parametrize("body", WITH_BANG_RAWSIMPLE) -def test_withbang_single_simple_opt(body): +def test_withbang_single_simple_opt(body, check_xonsh_ast): code = f"with! x as y: {body}\n" tree = check_xonsh_ast({}, code, False, return_obs=True, mode="exec") assert isinstance(tree, AST) @@ -2994,7 +3020,7 @@ def test_withbang_single_simple_opt(body): @pytest.mark.parametrize("body", WITH_BANG_RAWSUITES) -def test_withbang_as_many_suite(body): +def test_withbang_as_many_suite(body, check_xonsh_ast): code = "with! x as a, y as b, z as c:\n{}" code = code.format(textwrap.indent(body, " ")) tree = check_xonsh_ast({}, code, False, return_obs=True, mode="exec") @@ -3011,7 +3037,7 @@ def test_withbang_as_many_suite(body): assert s == body -def test_subproc_raw_str_literal(): +def test_subproc_raw_str_literal(check_xonsh_ast): tree = check_xonsh_ast({}, "!(echo '$foo')", run=False, return_obs=True) assert isinstance(tree, AST) subproc = tree.body @@ -3028,34 +3054,34 @@ def test_subproc_raw_str_literal(): # test invalid expressions -def test_syntax_error_del_literal(): +def test_syntax_error_del_literal(parser): with pytest.raises(SyntaxError): - PARSER.parse("del 7") + parser.parse("del 7") -def test_syntax_error_del_constant(): +def test_syntax_error_del_constant(parser): with pytest.raises(SyntaxError): - PARSER.parse("del True") + parser.parse("del True") -def test_syntax_error_del_emptytuple(): +def test_syntax_error_del_emptytuple(parser): with pytest.raises(SyntaxError): - PARSER.parse("del ()") + parser.parse("del ()") -def test_syntax_error_del_call(): +def test_syntax_error_del_call(parser): with pytest.raises(SyntaxError): - PARSER.parse("del foo()") + parser.parse("del foo()") -def test_syntax_error_del_lambda(): +def test_syntax_error_del_lambda(parser): with pytest.raises(SyntaxError): - PARSER.parse('del lambda x: "yay"') + parser.parse('del lambda x: "yay"') -def test_syntax_error_del_ifexp(): +def test_syntax_error_del_ifexp(parser): with pytest.raises(SyntaxError): - PARSER.parse("del x if y else z") + parser.parse("del x if y else z") @pytest.mark.parametrize( @@ -3067,56 +3093,56 @@ def test_syntax_error_del_ifexp(): "{k:v for k,v in d.items()}", ], ) -def test_syntax_error_del_comps(exp): +def test_syntax_error_del_comps(parser, exp): with pytest.raises(SyntaxError): - PARSER.parse(f"del {exp}") + parser.parse(f"del {exp}") @pytest.mark.parametrize("exp", ["x + y", "x and y", "-x"]) -def test_syntax_error_del_ops(exp): +def test_syntax_error_del_ops(parser, exp): with pytest.raises(SyntaxError): - PARSER.parse(f"del {exp}") + parser.parse(f"del {exp}") @pytest.mark.parametrize("exp", ["x > y", "x > y == z"]) -def test_syntax_error_del_cmp(exp): +def test_syntax_error_del_cmp(parser, exp): with pytest.raises(SyntaxError): - PARSER.parse(f"del {exp}") + parser.parse(f"del {exp}") -def test_syntax_error_lonely_del(): +def test_syntax_error_lonely_del(parser): with pytest.raises(SyntaxError): - PARSER.parse("del") + parser.parse("del") -def test_syntax_error_assign_literal(): +def test_syntax_error_assign_literal(parser): with pytest.raises(SyntaxError): - PARSER.parse("7 = x") + parser.parse("7 = x") -def test_syntax_error_assign_constant(): +def test_syntax_error_assign_constant(parser): with pytest.raises(SyntaxError): - PARSER.parse("True = 8") + parser.parse("True = 8") -def test_syntax_error_assign_emptytuple(): +def test_syntax_error_assign_emptytuple(parser): with pytest.raises(SyntaxError): - PARSER.parse("() = x") + parser.parse("() = x") -def test_syntax_error_assign_call(): +def test_syntax_error_assign_call(parser): with pytest.raises(SyntaxError): - PARSER.parse("foo() = x") + parser.parse("foo() = x") -def test_syntax_error_assign_lambda(): +def test_syntax_error_assign_lambda(parser): with pytest.raises(SyntaxError): - PARSER.parse('lambda x: "yay" = y') + parser.parse('lambda x: "yay" = y') -def test_syntax_error_assign_ifexp(): +def test_syntax_error_assign_ifexp(parser): with pytest.raises(SyntaxError): - PARSER.parse("x if y else z = 8") + parser.parse("x if y else z = 8") @pytest.mark.parametrize( @@ -3128,51 +3154,51 @@ def test_syntax_error_assign_ifexp(): "{k:v for k,v in d.items()}", ], ) -def test_syntax_error_assign_comps(exp): +def test_syntax_error_assign_comps(parser, exp): with pytest.raises(SyntaxError): - PARSER.parse(f"{exp} = z") + parser.parse(f"{exp} = z") @pytest.mark.parametrize("exp", ["x + y", "x and y", "-x"]) -def test_syntax_error_assign_ops(exp): +def test_syntax_error_assign_ops(parser, exp): with pytest.raises(SyntaxError): - PARSER.parse(f"{exp} = z") + parser.parse(f"{exp} = z") @pytest.mark.parametrize("exp", ["x > y", "x > y == z"]) -def test_syntax_error_assign_cmp(exp): +def test_syntax_error_assign_cmp(parser, exp): with pytest.raises(SyntaxError): - PARSER.parse(f"{exp} = a") + parser.parse(f"{exp} = a") -def test_syntax_error_augassign_literal(): +def test_syntax_error_augassign_literal(parser): with pytest.raises(SyntaxError): - PARSER.parse("7 += x") + parser.parse("7 += x") -def test_syntax_error_augassign_constant(): +def test_syntax_error_augassign_constant(parser): with pytest.raises(SyntaxError): - PARSER.parse("True += 8") + parser.parse("True += 8") -def test_syntax_error_augassign_emptytuple(): +def test_syntax_error_augassign_emptytuple(parser): with pytest.raises(SyntaxError): - PARSER.parse("() += x") + parser.parse("() += x") -def test_syntax_error_augassign_call(): +def test_syntax_error_augassign_call(parser): with pytest.raises(SyntaxError): - PARSER.parse("foo() += x") + parser.parse("foo() += x") -def test_syntax_error_augassign_lambda(): +def test_syntax_error_augassign_lambda(parser): with pytest.raises(SyntaxError): - PARSER.parse('lambda x: "yay" += y') + parser.parse('lambda x: "yay" += y') -def test_syntax_error_augassign_ifexp(): +def test_syntax_error_augassign_ifexp(parser): with pytest.raises(SyntaxError): - PARSER.parse("x if y else z += 8") + parser.parse("x if y else z += 8") @pytest.mark.parametrize( @@ -3184,64 +3210,64 @@ def test_syntax_error_augassign_ifexp(): "{k:v for k,v in d.items()}", ], ) -def test_syntax_error_augassign_comps(exp): +def test_syntax_error_augassign_comps(parser, exp): with pytest.raises(SyntaxError): - PARSER.parse(f"{exp} += z") + parser.parse(f"{exp} += z") @pytest.mark.parametrize("exp", ["x + y", "x and y", "-x"]) -def test_syntax_error_augassign_ops(exp): +def test_syntax_error_augassign_ops(parser, exp): with pytest.raises(SyntaxError): - PARSER.parse(f"{exp} += z") + parser.parse(f"{exp} += z") @pytest.mark.parametrize("exp", ["x > y", "x > y +=+= z"]) -def test_syntax_error_augassign_cmp(exp): +def test_syntax_error_augassign_cmp(parser, exp): with pytest.raises(SyntaxError): - PARSER.parse(f"{exp} += a") + parser.parse(f"{exp} += a") -def test_syntax_error_bar_kwonlyargs(): +def test_syntax_error_bar_kwonlyargs(parser): with pytest.raises(SyntaxError): - PARSER.parse("def spam(*):\n pass\n", mode="exec") + parser.parse("def spam(*):\n pass\n", mode="exec") @skip_if_pre_3_8 -def test_syntax_error_bar_posonlyargs(): +def test_syntax_error_bar_posonlyargs(parser): with pytest.raises(SyntaxError): - PARSER.parse("def spam(/):\n pass\n", mode="exec") + parser.parse("def spam(/):\n pass\n", mode="exec") @skip_if_pre_3_8 -def test_syntax_error_bar_posonlyargs_no_comma(): +def test_syntax_error_bar_posonlyargs_no_comma(parser): with pytest.raises(SyntaxError): - PARSER.parse("def spam(x /, y):\n pass\n", mode="exec") + parser.parse("def spam(x /, y):\n pass\n", mode="exec") -def test_syntax_error_nondefault_follows_default(): +def test_syntax_error_nondefault_follows_default(parser): with pytest.raises(SyntaxError): - PARSER.parse("def spam(x=1, y):\n pass\n", mode="exec") + parser.parse("def spam(x=1, y):\n pass\n", mode="exec") @skip_if_pre_3_8 -def test_syntax_error_posonly_nondefault_follows_default(): +def test_syntax_error_posonly_nondefault_follows_default(parser): with pytest.raises(SyntaxError): - PARSER.parse("def spam(x, y=1, /, z):\n pass\n", mode="exec") + parser.parse("def spam(x, y=1, /, z):\n pass\n", mode="exec") -def test_syntax_error_lambda_nondefault_follows_default(): +def test_syntax_error_lambda_nondefault_follows_default(parser): with pytest.raises(SyntaxError): - PARSER.parse("lambda x=1, y: x", mode="exec") + parser.parse("lambda x=1, y: x", mode="exec") @skip_if_pre_3_8 -def test_syntax_error_lambda_posonly_nondefault_follows_default(): +def test_syntax_error_lambda_posonly_nondefault_follows_default(parser): with pytest.raises(SyntaxError): - PARSER.parse("lambda x, y=1, /, z: x", mode="exec") + parser.parse("lambda x, y=1, /, z: x", mode="exec") -def test_get_repo_url(): - PARSER.parse( +def test_get_repo_url(parser): + parser.parse( "def get_repo_url():\n" " raw = $(git remote get-url --push origin).rstrip()\n" " return raw.replace('https://github.com/', '')\n" diff --git a/tests/test_pipelines.py b/tests/test_pipelines.py index 9cf0b56fc..fa1e0dfe7 100644 --- a/tests/test_pipelines.py +++ b/tests/test_pipelines.py @@ -8,22 +8,23 @@ import pytest 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): +def patched_events(monkeypatch, xonsh_events, xonsh_session): from xonsh.jobs import tasks tasks.clear() # needed for ci tests monkeypatch.setitem( - XSH.env, "RAISE_SUBPROC_ERROR", False + xonsh_session.env, "RAISE_SUBPROC_ERROR", False ) # for the failing `grep` commands - monkeypatch.setitem(XSH.env, "XONSH_CAPTURE_ALWAYS", True) # capture output of ![] + monkeypatch.setitem( + xonsh_session.env, "XONSH_CAPTURE_ALWAYS", True + ) # capture output of ![] if ON_WINDOWS: monkeypatch.setattr( - XSH, + xonsh_session, "aliases", { "echo": "cmd /c echo".split(), diff --git a/tests/test_ptk_highlight.py b/tests/test_ptk_highlight.py index d4352edba..07c13f458 100644 --- a/tests/test_ptk_highlight.py +++ b/tests/test_ptk_highlight.py @@ -1,6 +1,5 @@ """Test XonshLexer for pygments""" -import gc import pytest from pygments.token import ( @@ -16,55 +15,51 @@ from pygments.token import ( ) from tools import skip_if_on_windows -from xonsh.platform import ON_WINDOWS -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 from tools import DummyShell -@pytest.fixture(autouse=True) -def load_command_cache(xession): - gc.collect() - XSH.unload() - XSH.load() - if ON_WINDOWS: - for key in ("cd", "bash"): - xession.aliases[key] = lambda *args, **kwargs: None +@pytest.fixture +def xsh(xession, monkeypatch): + for key in ("cd", "bash"): + monkeypatch.setitem(xession.aliases, key, lambda *args, **kwargs: None) -def check_token(code, tokens): - """Make sure that all tokens appears in code in order""" - lx = XonshLexer() - tks = list(lx.get_tokens(code)) +@pytest.fixture() +def check_token(xsh): + def factory(code, tokens): + """Make sure that all tokens appears in code in order""" + lx = XonshLexer() + tks = list(lx.get_tokens(code)) - for tk in tokens: - while tks: - if tk == tks[0]: + for tk in tokens: + while tks: + if tk == tks[0]: + break + tks = tks[1:] + else: + msg = f"Token {tk!r} missing: {list(lx.get_tokens(code))!r}" + pytest.fail(msg) break - tks = tks[1:] - else: - msg = f"Token {tk!r} missing: {list(lx.get_tokens(code))!r}" - pytest.fail(msg) - break + + return factory -@skip_if_on_windows -def test_ls(): - check_token("ls -al", [(Name.Builtin, "ls")]) - - -@skip_if_on_windows -def test_bin_ls(): - check_token("/bin/ls -al", [(Name.Builtin, "/bin/ls")]) - - -@skip_if_on_windows -def test_py_print(): - check_token( - 'print("hello")', - [ +_cases = { + "ls": { + "ls -al": [ + (Name.Builtin, "ls"), + ], + }, + "ls-bin": { + "/bin/ls -al": [ + (Name.Builtin, "/bin/ls"), + ], + }, + "print": { + 'print("hello")': [ (Name.Builtin, "print"), (Punctuation, "("), (Literal.String.Double, '"'), @@ -72,46 +67,44 @@ def test_py_print(): (Literal.String.Double, '"'), (Punctuation, ")"), (Text, "\n"), + ] + }, + "invalid-cmd": { + "non-existance-cmd -al": [ + (Name, "non"), ], - ) - - -@skip_if_on_windows -def test_invalid_cmd(): - check_token("non-existance-cmd -al", [(Name, "non")]) # parse as python - check_token( - "![non-existance-cmd -al]", [(Error, "non-existance-cmd")] - ) # parse as error - check_token("for i in range(10):", [(Keyword, "for")]) # as py keyword - check_token("(1, )", [(Punctuation, "("), (Number.Integer, "1")]) - - -@skip_if_on_windows -def test_multi_cmd(): - check_token( - "cd && cd", [(Name.Builtin, "cd"), (Operator, "&&"), (Name.Builtin, "cd")] - ) - check_token( - "cd || non-existance-cmd", - [(Name.Builtin, "cd"), (Operator, "||"), (Error, "non-existance-cmd")], - ) - - -@skip_if_on_windows -def test_nested(): - check_token( - 'echo @("hello")', - [ + "![non-existance-cmd -al]": [ + (Error, "non-existance-cmd"), + ], + "for i in range(10):": [ + (Keyword, "for"), + ], + "(1, )": [ + (Punctuation, "("), + (Number.Integer, "1"), + ], + }, + "multi-cmd": { + "cd && cd": [ + (Name.Builtin, "cd"), + (Operator, "&&"), + (Name.Builtin, "cd"), + ], + "cd || non-existance-cmd": [ + (Name.Builtin, "cd"), + (Operator, "||"), + (Error, "non-existance-cmd"), + ], + }, + "nested": { + 'echo @("hello")': [ (Name.Builtin, "echo"), (Keyword, "@"), (Punctuation, "("), (String.Double, "hello"), (Punctuation, ")"), ], - ) - check_token( - "print($(cd))", - [ + "print($(cd))": [ (Name.Builtin, "print"), (Punctuation, "("), (Keyword, "$"), @@ -121,10 +114,7 @@ def test_nested(): (Punctuation, ")"), (Text, "\n"), ], - ) - check_token( - r'print(![echo "])\""])', - [ + r'print(![echo "])\""])': [ (Name.Builtin, "print"), (Punctuation, "("), (Keyword, "!"), @@ -136,7 +126,53 @@ def test_nested(): (Punctuation, ")"), (Text, "\n"), ], - ) + }, + "subproc-args": { + "cd 192.168.0.1": [ + (Text, "192.168.0.1"), + ], + }, + "backtick": { + r"echo g`.*\w+`": [ + (String.Affix, "g"), + (String.Backtick, "`"), + (String.Regex, "."), + (String.Regex, "*"), + (String.Escape, r"\w"), + ], + }, + "macro": { + r"g!(42, *, 65)": [ + (Name, "g"), + (Keyword, "!"), + (Punctuation, "("), + (Number.Integer, "42"), + ], + r"echo! hello world": [ + (Name.Builtin, "echo"), + (Keyword, "!"), + (String, "hello world"), + ], + r"bash -c ! export var=42; echo $var": [ + (Name.Builtin, "bash"), + (Text, "-c"), + (Keyword, "!"), + (String, "export var=42; echo $var"), + ], + }, +} + + +def _convert_cases(): + for title, input_dict in _cases.items(): + for idx, item in enumerate(input_dict.items()): + yield pytest.param(*item, id=f"{title}-{idx}") + + +@pytest.mark.parametrize("inp, expected", list(_convert_cases())) +@skip_if_on_windows +def test_xonsh_lexer(inp, expected, check_token): + check_token(inp, expected) # can't seem to get thie test to import pyghooks and define on_lscolors_change handler like live code does. @@ -160,8 +196,7 @@ def xonsh_builtins_ls_colors(xession, events_fxt): @skip_if_on_windows -def test_path(tmpdir, xonsh_builtins_ls_colors): - +def test_path(tmpdir, xonsh_builtins_ls_colors, check_token): test_dir = str(tmpdir.mkdir("xonsh-test-highlight-path")) check_token(f"cd {test_dir}", [(Name.Builtin, "cd"), (Color.BOLD_BLUE, test_dir)]) check_token( @@ -175,7 +210,7 @@ def test_path(tmpdir, xonsh_builtins_ls_colors): @skip_if_on_windows -def test_color_on_lscolors_change(tmpdir, xonsh_builtins_ls_colors): +def test_color_on_lscolors_change(tmpdir, xonsh_builtins_ls_colors, check_token): """Verify colorizer returns Token.Text if file type not defined in LS_COLORS""" lsc = xonsh_builtins_ls_colors.env["LS_COLORS"] @@ -188,43 +223,3 @@ def test_color_on_lscolors_change(tmpdir, xonsh_builtins_ls_colors): del lsc["di"] check_token(f"cd {test_dir}", [(Name.Builtin, "cd"), (Text, test_dir)]) - - -@skip_if_on_windows -def test_subproc_args(): - check_token("cd 192.168.0.1", [(Text, "192.168.0.1")]) - - -@skip_if_on_windows -def test_backtick(): - check_token( - r"echo g`.*\w+`", - [ - (String.Affix, "g"), - (String.Backtick, "`"), - (String.Regex, "."), - (String.Regex, "*"), - (String.Escape, r"\w"), - ], - ) - - -@skip_if_on_windows -def test_macro(): - check_token( - r"g!(42, *, 65)", - [(Name, "g"), (Keyword, "!"), (Punctuation, "("), (Number.Integer, "42")], - ) - check_token( - r"echo! hello world", - [(Name.Builtin, "echo"), (Keyword, "!"), (String, "hello world")], - ) - check_token( - r"bash -c ! export var=42; echo $var", - [ - (Name.Builtin, "bash"), - (Text, "-c"), - (Keyword, "!"), - (String, "export var=42; echo $var"), - ], - ) diff --git a/tests/test_ptk_shell.py b/tests/test_ptk_shell.py index 296920046..b4e075ed1 100644 --- a/tests/test_ptk_shell.py +++ b/tests/test_ptk_shell.py @@ -32,7 +32,7 @@ def test_prompt_toolkit_version_checks( exp_shell_type, warn_snip, monkeypatch, - xonsh_builtins, + xession, ): mocked_warn = "" diff --git a/tests/test_pyghooks.py b/tests/test_pyghooks.py index 1bbe4b5bd..819245b0c 100644 --- a/tests/test_pyghooks.py +++ b/tests/test_pyghooks.py @@ -23,18 +23,24 @@ from xonsh.environ import LsColors @pytest.fixture -def xs_LS_COLORS(xession): +def xs_LS_COLORS(xession, os_env, monkeypatch): """Xonsh environment including LS_COLORS""" - e = xession.env + + # original env is needed on windows. since it will skip enhanced coloring + # for some emulators + monkeypatch.setattr(xession, "env", os_env) + lsc = LsColors(LsColors.default_settings) xession.env["LS_COLORS"] = lsc + + # todo: a separate test for this as True + xession.env["INTENSIFY_COLORS_ON_WIN"] = False + xession.shell.shell_type = "prompt_toolkit" xession.shell.shell.styler = XonshStyle() # default style yield xession - xession.env = e - DEFAULT_STYLES = { # Reset diff --git a/tests/test_shell.py b/tests/test_shell.py index 524ce755f..4f50db982 100644 --- a/tests/test_shell.py +++ b/tests/test_shell.py @@ -1,7 +1,6 @@ """Testing for ``xonsh.shell.Shell``""" import os -from xonsh.environ import Env from xonsh.shell import Shell from xonsh.history.json import JsonHistory from xonsh.history.sqlite import SqliteHistory @@ -32,12 +31,14 @@ def test_shell_with_json_history(xession, xonsh_execer, tmpdir_factory): ) h.flush() - xession.env = Env( - XONSH_DATA_DIR=tempdir, - XONSH_INTERACTIVE=True, - XONSH_HISTORY_BACKEND="json", - XONSH_HISTORY_FILE=history_file, - # XONSH_DEBUG=1 # to show errors + xession.env.update( + dict( + XONSH_DATA_DIR=tempdir, + XONSH_INTERACTIVE=True, + XONSH_HISTORY_BACKEND="json", + XONSH_HISTORY_FILE=history_file, + # XONSH_DEBUG=1 # to show errors + ) ) Shell(xonsh_execer, shell_type="none") @@ -69,12 +70,14 @@ def test_shell_with_sqlite_history(xession, xonsh_execer, tmpdir_factory): ) h.flush() - xession.env = Env( - XONSH_DATA_DIR=tempdir, - XONSH_INTERACTIVE=True, - XONSH_HISTORY_BACKEND="sqlite", - XONSH_HISTORY_FILE=history_file, - # XONSH_DEBUG=1 # to show errors + xession.env.update( + dict( + XONSH_DATA_DIR=tempdir, + XONSH_INTERACTIVE=True, + XONSH_HISTORY_BACKEND="sqlite", + XONSH_HISTORY_FILE=history_file, + # XONSH_DEBUG=1 # to show errors + ) ) Shell(xonsh_execer, shell_type="none") @@ -86,7 +89,7 @@ def test_shell_with_dummy_history_in_not_interactive(xession, xonsh_execer): """ Check that shell use Dummy history in not interactive mode. """ - xession.env = Env(XONSH_INTERACTIVE=False) + xession.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 be63bfd36..596b41260 100644 --- a/tests/test_tools.py +++ b/tests/test_tools.py @@ -90,7 +90,6 @@ from xonsh.tools import ( expand_case_matching, expandvars, ) -from xonsh.environ import Env from tools import skip_if_on_windows @@ -536,7 +535,7 @@ mom""" @pytest.mark.parametrize("src, idx, exp_line, exp_n", LOGICAL_LINE_CASES) -def test_get_logical_line(src, idx, exp_line, exp_n, xonsh_builtins): +def test_get_logical_line(src, idx, exp_line, exp_n, xession): lines = src.splitlines() line, n, start = get_logical_line(lines, idx) assert exp_line == line @@ -544,7 +543,7 @@ def test_get_logical_line(src, idx, exp_line, exp_n, xonsh_builtins): @pytest.mark.parametrize("src, idx, exp_line, exp_n", LOGICAL_LINE_CASES) -def test_replace_logical_line(src, idx, exp_line, exp_n, xonsh_builtins): +def test_replace_logical_line(src, idx, exp_line, exp_n, xession): lines = src.splitlines() logical = exp_line while idx > 0 and lines[idx - 1].endswith("\\"): @@ -1651,10 +1650,9 @@ def test_expand_case_matching(inp, exp): ) 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} + xession.env.update( + dict({"foo": "bar", "spam": "eggs", "a_bool": True, "an_int": 42, "none": None}) ) - xession.env = env assert expandvars(inp) == exp @@ -1699,9 +1697,8 @@ def test_expand_path(expand_user, inp, expand_env_vars, exp_end, xession): 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 - xession.env = env + xession.env.update({"foo": "bar", "a_bool": True, "an_int": 42, "none": None}) + xession.env["EXPAND_ENV_VARS"] = expand_env_vars path = expand_path(inp, expand_user=expand_user) diff --git a/tests/test_vox.py b/tests/test_vox.py index 3353057ba..7f996d8db 100644 --- a/tests/test_vox.py +++ b/tests/test_vox.py @@ -99,7 +99,7 @@ def test_activate_non_vox_venv(xession, vox, record_events, tmpdir): Create a virtual environment using Python's built-in venv module (not in VIRTUALENV_HOME) and verify that vox can activate it correctly. """ - xession.env.setdefault("PATH", []) + xession.env["PATH"] = [] record_events("vox_on_activate", "vox_on_deactivate") @@ -286,9 +286,8 @@ def patched_cmd_cache(xession, vox, venvs, monkeypatch): def no_change(self, *_): return False, False, False - monkeypatch.setattr(cc, "_update_if_changed", types.MethodType(no_change, cc)) + monkeypatch.setattr(cc, "_check_changes", types.MethodType(no_change, cc)) monkeypatch.setattr(cc, "_update_cmds_cache", types.MethodType(no_change, cc)) - monkeypatch.setattr(cc, "cache_file", None) bins = {path: (path, False) for path in _PY_BINS} cc._cmds_cache.update(bins) yield cc diff --git a/tests/test_xonfig.py b/tests/test_xonfig.py index 21c202561..9605757d9 100644 --- a/tests/test_xonfig.py +++ b/tests/test_xonfig.py @@ -15,7 +15,7 @@ from xonsh.tools import ON_WINDOWS from xonsh.xonfig import xonfig_main -def test_xonfg_help(capsys, xonsh_builtins): +def test_xonfg_help(capsys, xession): """verify can invoke it, and usage knows about all the options""" with pytest.raises(SystemExit): xonfig_main(["-h"]) @@ -46,7 +46,7 @@ def test_xonfg_help(capsys, xonsh_builtins): ), ], # NOQA E231 ) -def test_xonfig_info(args, xonsh_builtins): +def test_xonfig_info(args, xession): """info works, and reports no jupyter if none in environment""" capout = xonfig_main(args) assert capout.startswith("+---") @@ -89,7 +89,7 @@ def fake_lib(monkeypatch): del sys.modules[m] -def test_xonfig_kernel_with_jupyter(monkeypatch, capsys, fake_lib, xonsh_builtins): +def test_xonfig_kernel_with_jupyter(monkeypatch, capsys, fake_lib, xession): cap_args = None cap_spec = None @@ -129,6 +129,6 @@ def test_xonfig_kernel_with_jupyter(monkeypatch, capsys, fake_lib, xonsh_builtin assert cap_spec["argv"][2] == "xonsh.jupyter_kernel" -def test_xonfig_kernel_no_jupyter(capsys, xonsh_builtins): +def test_xonfig_kernel_no_jupyter(capsys, xession): with pytest.raises(ImportError): rc = xonfig_main(["jupyter-kernel"]) # noqa F841 diff --git a/tests/tools.py b/tests/tools.py index e24e61da5..4f1560e98 100644 --- a/tests/tools.py +++ b/tests/tools.py @@ -1,17 +1,15 @@ """Tests the xonsh lexer.""" +import copy import os import sys import ast import platform import subprocess -import contextlib +import threading from collections import defaultdict -from collections.abc import MutableMapping import pytest -from xonsh.built_ins import XSH -from xonsh.environ import Env from xonsh.base_shell import BaseShell @@ -24,9 +22,6 @@ ON_CONDA = True in [ conda in pytest.__file__.lower() for conda in ["conda", "anaconda", "miniconda"] ] ON_TRAVIS = "TRAVIS" in os.environ and "CI" in os.environ -ON_AZURE_PIPELINES = os.environ.get("TF_BUILD", "") == "True" -print("ON_AZURE_PIPELINES", repr(ON_AZURE_PIPELINES)) -print("os.environ['TF_BUILD']", repr(os.environ.get("TF_BUILD", ""))) TEST_DIR = os.path.dirname(__file__) # pytest skip decorators @@ -40,10 +35,6 @@ skip_if_on_msys = pytest.mark.skipif( skip_if_on_windows = pytest.mark.skipif(ON_WINDOWS, reason="Unix stuff") -skip_if_on_azure_pipelines = pytest.mark.skipif( - ON_AZURE_PIPELINES, reason="not suitable for azure" -) - skip_if_on_unix = pytest.mark.skipif(not ON_WINDOWS, reason="Windows stuff") skip_if_on_darwin = pytest.mark.skipif(ON_DARWIN, reason="not Mac friendly") @@ -94,103 +85,6 @@ class DummyHistory: pass -class DummyEnv(MutableMapping): - - DEFAULTS = { - "XONSH_DEBUG": 1, - "XONSH_COLOR_STYLE": "default", - "VC_BRANCH_TIMEOUT": 1, - } - - def __init__(self, *args, **kwargs): - self._d = self.DEFAULTS.copy() - self._d.update(dict(*args, **kwargs)) - - def detype(self): - return {k: str(v) for k, v in self._d.items()} - - def __getitem__(self, k): - if k is ...: - return self - else: - return self._d[k] - - def __setitem__(self, k, v): - assert k is not ... - self._d[k] = v - - def __delitem__(self, k): - assert k is not ... - del self._d[k] - - def __len__(self): - return len(self._d) - - def __iter__(self): - yield from self._d - - @contextlib.contextmanager - def swap(self, other=None, **kwargs): - old = {} - # single positional argument should be a dict-like object - if other is not None: - for k, v in other.items(): - old[k] = self.get(k, NotImplemented) - self[k] = v - # kwargs could also have been sent in - for k, v in kwargs.items(): - old[k] = self.get(k, NotImplemented) - self[k] = v - yield self - # restore the values - for k, v in old.items(): - if v is NotImplemented: - del self[k] - else: - self[k] = v - - @staticmethod - def get_swapped_values(): - return {} - - @staticmethod - def set_swapped_values(_): - pass - - def is_manually_set(self, key): - return False - - -# -# Execer tools -# - - -def check_exec(input, **kwargs): - XSH.execer.exec(input, **kwargs) - return True - - -def check_eval(input): - XSH.env = Env( - { - "AUTO_CD": False, - "XONSH_ENCODING": "utf-8", - "XONSH_ENCODING_ERRORS": "strict", - "PATH": [], - } - ) - if ON_WINDOWS: - XSH.env["PATHEXT"] = [".COM", ".EXE", ".BAT", ".CMD"] - XSH.execer.eval(input) - return True - - -def check_parse(input): - tree = XSH.execer.parse(input, ctx=None) - return tree - - # # Parser tools # @@ -245,3 +139,17 @@ def completions_from_result(results): if results is None: return set() return results + + +def copy_env(old): + from xonsh.environ import Env, InternalEnvironDict + + env: Env = copy.copy(old) + internal = InternalEnvironDict() + internal._global = env._d._global.copy() + internal._thread_local = threading.local() + + env._d = internal + env._vars = env._vars.copy() + env._detyped = None + return env diff --git a/xonsh/commands_cache.py b/xonsh/commands_cache.py index b7c2e5091..d424a4fee 100644 --- a/xonsh/commands_cache.py +++ b/xonsh/commands_cache.py @@ -5,6 +5,7 @@ A background predictor is a function that accepts a single argument list and returns whether or not the process can be run in the background (returns True) or must be run the foreground (returns False). """ +import functools import os import pickle import sys @@ -39,15 +40,24 @@ class CommandsCache(cabc.Mapping): self.threadable_predictors = default_threadable_predictors() self._loaded_pickled = False - # Path to the cache-file where all commands/aliases are cached for pre-loading""" - env = XSH.env - self.cache_file = ( - (Path(env["XONSH_DATA_DIR"]).joinpath(self.CACHE_FILE).resolve()) - if env is not None - and "XONSH_DATA_DIR" in env - and env.get("COMMANDS_CACHE_SAVE_INTERMEDIATE") - else None - ) + # force it to load from env by setting it to None + self._cache_file = None + + @property + def cache_file(self): + """Keeping a property that lies on instance-attribute""" + env = XSH.env or {} + # Path to the cache-file where all commands/aliases are cached for pre-loading + if self._cache_file is None: + if "XONSH_DATA_DIR" in env and env.get("COMMANDS_CACHE_SAVE_INTERMEDIATE"): + self._cache_file = ( + Path(env["XONSH_DATA_DIR"]).joinpath(self.CACHE_FILE).resolve() + ) + else: + # set a falsy value other than None + self._cache_file = "" + + return self._cache_file def __contains__(self, key): self.update_cache() @@ -98,7 +108,7 @@ class CommandsCache(cabc.Mapping): if os.path.isdir(p): yield p - def _update_if_changed(self, paths: tp.Tuple[str, ...], aliases): + def _check_changes(self, paths: tp.Tuple[str, ...], aliases): # did PATH change? path_hash = hash(paths) yield path_hash == self._path_checksum @@ -120,20 +130,20 @@ class CommandsCache(cabc.Mapping): return self._cmds_cache def update_cache(self): - env = XSH.env - path = [] if env is None else XSH.env.get("PATH", []) - path_immut = tuple(CommandsCache.remove_dups(path)) + env = XSH.env or {} + paths = tuple(CommandsCache.remove_dups(env.get("PATH") or [])) # in case it is empty or unset alss = {} if XSH.aliases is None else XSH.aliases ( - has_path_changed, - has_alias_changed, - has_any_path_updated, - ) = tuple(self._update_if_changed(path_immut, alss)) - if has_path_changed and has_any_path_updated: - if not has_alias_changed: + no_new_paths, + no_new_alias, + no_new_bins, + ) = tuple(self._check_changes(paths, alss)) + + if no_new_paths and no_new_bins: + if not no_new_alias: # only aliases have changed for cmd, alias in alss.items(): key = cmd.upper() if ON_WINDOWS else cmd if key in self._cmds_cache: @@ -153,26 +163,41 @@ class CommandsCache(cabc.Mapping): # also start a thread that updates the cache in the bg worker = threading.Thread( target=self._update_cmds_cache, - args=[path_immut, alss], + args=[paths, alss], daemon=True, ) worker.start() else: - self._update_cmds_cache(path_immut, alss) + self._update_cmds_cache(paths, alss) + return self._cmds_cache + + @staticmethod + @functools.lru_cache(maxsize=10) + def _get_all_cmds(paths: tp.Sequence[str]): + """Cache results when possible + + This will be helpful especially during tests where the PATH will be the same mostly. + """ + + def _getter(): + for path in reversed(paths): + # iterate backwards so that entries at the front of PATH overwrite + # entries at the back. + for cmd in executables_in(path): + yield cmd, os.path.join(path, cmd) + + return dict(_getter()) def _update_cmds_cache( self, paths: tp.Sequence[str], aliases: tp.Dict[str, str] ) -> tp.Dict[str, tp.Any]: """Update the cmds_cache variable in background without slowing down parseLexer""" env = XSH.env or {} # type: ignore - allcmds = {} - for path in reversed(paths): - # iterate backwards so that entries at the front of PATH overwrite - # entries at the back. - for cmd in executables_in(path): - key = cmd.upper() if ON_WINDOWS else cmd - allcmds[key] = (os.path.join(path, cmd), aliases.get(key, None)) + + for cmd, path in self._get_all_cmds(paths).items(): + key = cmd.upper() if ON_WINDOWS else cmd + allcmds[key] = (path, aliases.get(key, None)) warn_cnt = env.get("COMMANDS_CACHE_SIZE_WARNING") if warn_cnt and len(allcmds) > warn_cnt: @@ -185,6 +210,7 @@ class CommandsCache(cabc.Mapping): if cmd not in allcmds: key = cmd.upper() if ON_WINDOWS else cmd allcmds[key] = (cmd, True) # type: ignore + return self.set_cmds_cache(allcmds) def get_cached_commands(self) -> tp.Dict[str, str]: diff --git a/xonsh/execer.py b/xonsh/execer.py index 478e67abc..22b338ed7 100644 --- a/xonsh/execer.py +++ b/xonsh/execer.py @@ -26,7 +26,6 @@ class Execer: filename="", debug_level=0, parser_args=None, - unload=True, scriptcache=True, cacheall=False, ): @@ -50,7 +49,6 @@ class Execer: self.filename = filename self._default_filename = filename self.debug_level = debug_level - self.unload = unload self.scriptcache = scriptcache self.cacheall = cacheall self.ctxtransformer = CtxAwareTransformer(self.parser) diff --git a/xonsh/prompt/cwd.py b/xonsh/prompt/cwd.py index ad891b2be..1e8bb6297 100644 --- a/xonsh/prompt/cwd.py +++ b/xonsh/prompt/cwd.py @@ -8,21 +8,16 @@ import xonsh.platform as xp from xonsh.built_ins import XSH -def _replace_home(x): - if xp.ON_WINDOWS: - home = XSH.env["HOMEDRIVE"] + XSH.env["HOMEPATH"][0] - if x.startswith(home): - x = x.replace(home, "~", 1) +def _replace_home(x: str): + home = os.path.expanduser("~") + if x.startswith(home): + x = x.replace(home, "~", 1) - if XSH.env.get("FORCE_POSIX_PATHS"): + if xp.ON_WINDOWS: + if XSH.env.get("FORCE_POSIX_PATHS") and os.altsep: x = x.replace(os.sep, os.altsep) - return x - else: - home = XSH.env["HOME"] - if x.startswith(home): - x = x.replace(home, "~", 1) - return x + return x def _replace_home_cwd(): diff --git a/xonsh/pyghooks.py b/xonsh/pyghooks.py index 0bb5e3cf0..d6f1fda58 100644 --- a/xonsh/pyghooks.py +++ b/xonsh/pyghooks.py @@ -2,7 +2,6 @@ import os import re import sys -import builtins import stat from collections import ChainMap from collections.abc import MutableMapping @@ -268,7 +267,7 @@ def partial_color_tokenize(template): These sub-strings maybe templates themselves. """ if XSH.shell is not None: - styles = __xonsh__.shell.shell.styler.styles + styles = XSH.shell.shell.styler.styles else: styles = None color = Color.DEFAULT @@ -1651,16 +1650,12 @@ class XonshLexer(Python3Lexer): def __init__(self, *args, **kwargs): # If the lexer is loaded as a pygment plugin, we have to mock # __xonsh__.env and __xonsh__.commands_cache - if not hasattr(builtins, "__xonsh__"): - from argparse import Namespace - - builtins.__xonsh__ = Namespace() if not hasattr(XSH, "env"): XSH.env = {} if ON_WINDOWS: pathext = os_environ.get("PATHEXT", [".EXE", ".BAT", ".CMD"]) XSH.env["PATHEXT"] = pathext.split(os.pathsep) - if not getattr(XSH, "commands_cache", None): + if getattr(XSH, "commands_cache", None) is None: XSH.commands_cache = CommandsCache() _ = XSH.commands_cache.all_commands # NOQA super().__init__(*args, **kwargs) diff --git a/xonsh/tools.py b/xonsh/tools.py index 3a739c905..10fecb06a 100644 --- a/xonsh/tools.py +++ b/xonsh/tools.py @@ -541,10 +541,12 @@ 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(xsh, "env") and xsh.env.get("XONSH_INTERACTIVE", False): - return " \\" - else: - return "\\" + if ON_WINDOWS: + env = getattr(xsh, "env", None) or {} + if env.get("XONSH_INTERACTIVE", False): + return " \\" + + return "\\" def get_logical_line(lines, idx): diff --git a/xontrib/voxapi.py b/xontrib/voxapi.py index d6bd7f1a2..21461da51 100644 --- a/xontrib/voxapi.py +++ b/xontrib/voxapi.py @@ -434,7 +434,7 @@ class Vox(collections.abc.Mapping): def _get_vox_default_interpreter(): """Return the interpreter set by the $VOX_DEFAULT_INTERPRETER if set else sys.executable""" - default = "python" + default = "python3" if default in XSH.commands_cache: default = XSH.commands_cache.locate_binary(default) else: