From 06aca868a288bd462a7dba39dcd91397aabc0a84 Mon Sep 17 00:00:00 2001 From: Andy Kipp Date: Fri, 14 Jun 2024 07:39:16 +0200 Subject: [PATCH] Fix #5491: more tests (#5498) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix #5491: * fix condition * added more well organized tests ## For community ⬇️ **Please click the 👍 reaction instead of leaving a `+1` or 👍 comment** --------- Co-authored-by: a <1@1.1> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- docs/xonshrc.rst | 1 + tests/test_integrations.py | 179 +++++++++++++++++-------------------- xonsh/main.py | 2 +- 3 files changed, 82 insertions(+), 100 deletions(-) diff --git a/docs/xonshrc.rst b/docs/xonshrc.rst index e53231393..e9b9c22d8 100644 --- a/docs/xonshrc.rst +++ b/docs/xonshrc.rst @@ -24,6 +24,7 @@ In addition: * Use ``xonsh --no-rc`` to prevent using control files. * Use ``xonsh --rc snail.xsh`` to run only a certain control file. * Use ``xonsh -i script.xsh`` to run xonsh in interactive mode with loading all possible control files. +* Use ``xonsh --rc rc1.xsh rc2.xsh -- script.xsh`` to run scripts with multiple control files. The options set per user override settings in the system-wide control file. diff --git a/tests/test_integrations.py b/tests/test_integrations.py index 2fc87fd8b..fa2d038bd 100644 --- a/tests/test_integrations.py +++ b/tests/test_integrations.py @@ -40,6 +40,16 @@ skip_if_no_sleep = pytest.mark.skipif( shutil.which("sleep") is None, reason="sleep command not on PATH" ) +base_env = { + "PATH": PATH, + "XONSH_DEBUG": "0", + "XONSH_SHOW_TRACEBACK": "1", + "RAISE_SUBPROC_ERROR": "0", + "FOREIGN_ALIASES_SUPPRESS_SKIP_MESSAGE": "1", + "PROMPT": "", + "TERM": "linux", # disable ansi escape codes +} + def run_xonsh( cmd, @@ -52,35 +62,31 @@ def run_xonsh( path=None, args=None, timeout=20, - add_env=None, + env=None, ): - env = dict(os.environ) - if path is None: - env["PATH"] = PATH - else: - env["PATH"] = path - env["XONSH_DEBUG"] = "0" # was "1" - env["XONSH_SHOW_TRACEBACK"] = "1" - env["RAISE_SUBPROC_ERROR"] = "0" - env["FOREIGN_ALIASES_SUPPRESS_SKIP_MESSAGE"] = "1" - env["PROMPT"] = "" - # disable ansi escape codes - env["TERM"] = "linux" - - if add_env: - env |= add_env + # Env + popen_env = dict(os.environ) + popen_env |= base_env + if path: + popen_env["PATH"] = path + if env: + popen_env |= env + # Args xonsh = shutil.which("xonsh", path=PATH) popen_args = [xonsh] + if not args: popen_args += ["--no-rc"] else: popen_args += args + if interactive: popen_args.append("-i") if cmd and isinstance(cmd, str) and not cmd.endswith("\n"): # In interactive mode we need to emulate "Press Enter". cmd += "\n" + if single_command: popen_args += ["-c", cmd] input = None @@ -89,7 +95,7 @@ def run_xonsh( proc = sp.Popen( popen_args, - env=env, + env=popen_env, stdin=stdin, stdout=stdout, stderr=stderr, @@ -1349,102 +1355,77 @@ def test_alias_stability_exception(): assert "Bad file descriptor" not in out -@pytest.mark.flaky(reruns=3, reruns_delay=2) -def test_rc_no_xonshrc_for_non_interactive(tmpdir): - """Testing no ``~/.xonshrc`` execution in non-interactive commands (#5491).""" - rc_dir = tmpdir.mkdir("rc_dir") - user_home_dir = tmpdir.mkdir("user_home") - user_not_home_dir = tmpdir.mkdir("user_not_home") - - (rc_dir / "rc_dir.xsh").write_text("echo RC_DIR", encoding="utf8") - (user_home_dir / ".xonshrc").write_text("echo RC_HOME", encoding="utf8") - (script := user_home_dir / "script.xsh").write_text("echo SCRIPT", encoding="utf8") - user_home_rc_path_crossplatform = str( - (Path(user_home_dir) / ".xonshrc").expanduser() +@pytest.mark.parametrize( + "cmd,exp", + [ + ["-i", ".*CONFIG_XONSH_RC_XSH.*HOME_XONSHRC.*CONFIG_XONSH_RCD.*"], + ["--rc rc.xsh", ".*RCXSH.*"], + ["-i --rc rc.xsh", ".*RCXSH.*"], + ["-c print('CMD')", ".*CONFIG_XONSH_RC_XSH.*CONFIG_XONSH_RCD.*CMD.*"], + [ + "-i -c print('CMD')", + ".*CONFIG_XONSH_RC_XSH.*HOME_XONSHRC.*CONFIG_XONSH_RCD.*CMD.*", + ], + ["script.xsh", ".*CONFIG_XONSH_RC_XSH.*CONFIG_XONSH_RCD.*SCRIPT.*"], + [ + "-i script.xsh", + ".*CONFIG_XONSH_RC_XSH.*HOME_XONSHRC.*CONFIG_XONSH_RCD.*SCRIPT.*", + ], + ["--rc rc.xsh -- script.xsh", ".*RCXSH.*SCRIPT.*"], + ["-i --rc rc.xsh -- script.xsh", ".*RCXSH.*SCRIPT.*"], + ["--no-rc --rc rc.xsh -- script.xsh", ".*SCRIPT.*"], + ["-i --no-rc --rc rc.xsh -- script.xsh", ".*SCRIPT.*"], + ], +) +# @pytest.mark.flaky(reruns=3, reruns_delay=2) +def test_xonshrc(tmpdir, cmd, exp): + # ~/.xonshrc + home = tmpdir.mkdir("home") + (home / ".xonshrc").write_text("echo HOME_XONSHRC", encoding="utf8") + home_xonsh_rc_path = str( # crossplatform path + (Path(home) / ".xonshrc").expanduser() ) - (user_not_home_rc := user_not_home_dir / "rc.xsh").write_text( - "echo RC_NOT_HOME", encoding="utf8" - ) - xonshrc_files = [str(user_not_home_rc), str(user_home_rc_path_crossplatform)] - xonshrc_dir = [str(rc_dir)] - # Here `eval()` is needed in Windows case where the path contains `:` symbol (e.g. `C:\\path`) and treated as list delimiter. + # ~/.config/xonsh/rc.xsh + home_config_xonsh = tmpdir.mkdir("home_config_xonsh") + (home_config_xonsh_rc_xsh := home_config_xonsh / "rc.xsh").write_text( + "echo CONFIG_XONSH_RC_XSH", encoding="utf8" + ) + + # ~/.config/xonsh/rc.d/ + home_config_xonsh_rcd = tmpdir.mkdir("home_config_xonsh_rcd") + (home_config_xonsh_rcd / "rcd1.xsh").write_text( + "echo CONFIG_XONSH_RCD", encoding="utf8" + ) + + # ~/home/rc.xsh + (rc_xsh := home / "rc.xsh").write_text("echo RCXSH", encoding="utf8") + (script_xsh := home / "script.xsh").write_text("echo SCRIPT_XSH", encoding="utf8") + + # Construct $XONSHRC and $XONSHRC_DIR + xonshrc_files = [str(home_config_xonsh_rc_xsh), str(home_xonsh_rc_path)] + xonshrc_dir = [str(home_config_xonsh_rcd)] + args = [ - f'-DHOME="{str(user_home_dir)}"', + f'-DHOME="{str(home)}"', f'-DXONSHRC="{os.pathsep.join(xonshrc_files)}"', f'-DXONSHRC_DIR="{os.pathsep.join(xonshrc_dir)}"', ] - cmd = "print(42+42)" - add_env = {"HOME": str(user_home_dir)} + env = {"HOME": str(home)} + + cmd = cmd.replace("rc.xsh", str(rc_xsh)).replace("script.xsh", str(script_xsh)) + args = args + cmd.split() # xonsh out, err, ret = run_xonsh( cmd=None, - stdin=None, - single_command=False, - interactive=True, args=args, - add_env=add_env, + env=env, ) - exp = ".*RC_NOT_HOME.*RC_HOME.*RC_DIR.*" + exp = exp assert re.match( exp, out, re.MULTILINE | re.DOTALL, - ), f"Expected: {exp!r},\nResult: {out!r},\nargs={args!r}" - - # xonsh -c "cmd" - out, err, ret = run_xonsh(cmd=cmd, interactive=False, args=args, add_env=add_env) - exp = ".*RC_NOT_HOME.*RC_DIR.*84.*" - assert re.match( - exp, - out, - re.MULTILINE | re.DOTALL, - ), f"Expected: {exp!r},\nResult: {out!r},\nargs={args!r}" - - # xonsh -i -c "cmd" - out, err, ret = run_xonsh( - cmd=cmd + "\n", interactive=True, args=args, add_env=add_env - ) - - exp = ".*RC_NOT_HOME.*RC_HOME.*RC_DIR.*" - if not ON_WINDOWS: - # On Windows we well have `NoConsoleScreenBufferError` in interactive mode so avoid checking interactive output of the command. - exp += "84.*" - - assert re.match( - exp, - out, - re.MULTILINE | re.DOTALL, - ), f"Expected: {exp!r},\nResult: {out!r},\nargs={args!r}" - - # xonsh script.xsh - out, err, ret = run_xonsh( - cmd=cmd + "\n", - interactive=False, - single_command=False, - args=args + ["--", script], - add_env=add_env, - ) - exp = ".*RC_NOT_HOME.*RC_DIR.*SCRIPT.*" - assert re.match( - exp, - out, - re.MULTILINE | re.DOTALL, - ), f"Expected: {exp!r},\nResult: {out!r},\nargs={args!r}" - - # xonsh -i script.xsh - out, err, ret = run_xonsh( - cmd=None, - interactive=False, - single_command=False, - args=args + ["-i", "--", script], - add_env=add_env, - ) - exp = ".*RC_NOT_HOME.*RC_HOME.*RC_DIR.*SCRIPT.*" - assert re.match( - exp, - out, - re.MULTILINE | re.DOTALL, - ), f"Expected: {exp!r},\nResult: {out!r},\nargs={args!r}" + ), f"Case: xonsh {cmd},\nExpected: {exp!r},\nResult: {out!r},\nargs={args!r}" diff --git a/xonsh/main.py b/xonsh/main.py index 1c917cc1f..478ff944a 100644 --- a/xonsh/main.py +++ b/xonsh/main.py @@ -309,7 +309,7 @@ def _get_rc_files(shell_kwargs: dict, args, env): rc = env.get("XONSHRC") rcd = env.get("XONSHRC_DIR") - if not env.get("XONSH_INTERACTIVE", False) or not args.force_interactive: + if not env.get("XONSH_INTERACTIVE", False): """ Home based ``~/.xonshrc`` file has special meaning and history. The ecosystem around shells treats this kind of files as the place where interactive tools can add configs. To avoid unintended and unexpected affection