Don't modify XONSHRC and XONSHRC_DIR during startup (#4408)

* xonshrc_context: return loaded instead of context, don't touch env

This function returned the context, but the return value is not used by
the sole call site (and would inconsistently be either the env or ctx
depending on other arguments). Redefine the function to return what was
loaded.

The function will also no longer touch the environment variables
XONSHRC, XONSHRC_DIR or LOADED_RC_FILES.

* XonshSession: add rc_files list, and set in start_services

* LOADED_RC_FILES: drop completely

* xonfig: add RC files

* test_main: update tests for changes to XONSHRC{,_DIR}

* news: add entry for xonshrc changes
This commit is contained in:
Gordon Ball 2021-08-17 17:01:41 +02:00 committed by GitHub
parent 1919b7dc80
commit 14c2c3ce62
Failed to generate hash of commit
6 changed files with 53 additions and 53 deletions

30
news/xonshrc-env-4394.rst Normal file
View file

@ -0,0 +1,30 @@
**Added:**
* <news item>
**Changed:**
* The environment variables ``XONSHRC`` and ``XONSHRC_DIR`` are no longer updated by xonsh on
startup according to which files were actually loaded. This caused problems if xonsh is called
recursively, as the child shells would inherit the modified startup environment of the parent.
These variables will now be left untouched, and the actual RC files loaded (according to those
variables and command line arguments) can be seen in the output of ``xonfig``.
**Deprecated:**
* <news item>
**Removed:**
* The environment variable ``LOADED_RC_FILES`` is no longer set. It contained a list of booleans
as to which RC files had been successfully loaded, but it required knowledge of the RC loading
internals to interpret which status corresponded to which file. As above, the (successfully)
loaded RC files are now shown in ``xonfig``.
**Fixed:**
* <news item>
**Security:**
* <news item>

View file

@ -61,7 +61,7 @@ def test_premain_custom_rc(shell, tmpdir, monkeypatch, xession):
f.write("print('hi')")
args = xonsh.main.premain(["--rc", f.strpath])
assert args.mode == XonshMode.interactive
assert f.strpath in xession.env.get("XONSHRC")
assert f.strpath in xession.rc_files
@pytest.mark.skipif(
@ -80,11 +80,7 @@ def test_rc_with_modules(shell, tmpdir, monkeypatch, capsys, xession):
rc.write("from my_python_module import *\nfrom my_xonsh_module import *")
xonsh.main.premain(["--rc", rc.strpath])
assert rc.strpath in xession.env.get("XONSHRC")
assert (
xession.env.get("LOADED_RC_FILES")[xession.env.get("XONSHRC").index(rc.strpath)]
is True
)
assert rc.strpath in xession.rc_files
stdout, stderr = capsys.readouterr()
assert "Hello,\nWorld!" in stdout
@ -252,7 +248,7 @@ def test_rcdir_ignored_with_rc(shell, tmpdir, monkeypatch, capsys, xession):
stdout, stderr = capsys.readouterr()
assert "RCDIR" not in stdout
assert "RCFILE" in stdout
assert not xession.env.get("XONSHRC_DIR")
assert str(rcdir.join("rcd.xsh")) not in xession.rc_files
@pytest.mark.skipif(ON_WINDOWS, reason="See https://github.com/xonsh/xonsh/issues/3936")
@ -266,11 +262,7 @@ def test_rc_with_modified_path(shell, tmpdir, monkeypatch, capsys, xession):
rc.write(f"import sys\nsys.path.append('{tmpdir.strpath}')\nprint('Hello, World!')")
xonsh.main.premain(["--rc", rc.strpath])
assert rc.strpath in xession.env.get("XONSHRC")
assert (
xession.env.get("LOADED_RC_FILES")[xession.env.get("XONSHRC").index(rc.strpath)]
is True
)
assert rc.strpath in xession.rc_files
stdout, stderr = capsys.readouterr()
assert "Hello, World!" in stdout
@ -291,11 +283,7 @@ def test_rc_with_failing_module(shell, tmpdir, monkeypatch, capsys, xession):
rc.write("from my_failing_module import *")
xonsh.main.premain(["--rc", rc.strpath])
assert rc.strpath in xession.env.get("XONSHRC")
assert (
xession.env.get("LOADED_RC_FILES")[xession.env.get("XONSHRC").index(rc.strpath)]
is False
)
assert rc.strpath not in xession.rc_files
stdout, stderr = capsys.readouterr()
assert len(stdout) == 0
@ -324,7 +312,7 @@ def test_force_interactive_custom_rc_with_script(shell, tmpdir, monkeypatch, xes
f.write("print('hi')")
args = xonsh.main.premain(["-i", "--rc", f.strpath, "tests/sample.xsh"])
assert args.mode == XonshMode.interactive
assert f.strpath in xession.env.get("XONSHRC")
assert f.strpath in xession.rc_files
def test_custom_rc_with_script(shell, tmpdir):
@ -339,8 +327,7 @@ def test_custom_rc_with_script(shell, tmpdir):
def test_premain_no_rc(shell, tmpdir, xession):
xonsh.main.premain(["--no-rc", "-i"])
assert not xession.env.get("XONSHRC")
assert not xession.env.get("XONSHRC_DIR")
assert len(xession.rc_files) == 0
@pytest.mark.parametrize(

View file

@ -534,6 +534,7 @@ class XonshSession:
self.history = None
self.shell = None
self.env = None
self.rc_files = None
def load(self, execer=None, ctx=None, **kwargs):
"""Loads the session with default values.

View file

@ -60,11 +60,8 @@ from xonsh.tools import (
csv_to_set,
set_to_csv,
is_int,
is_bool_seq,
to_bool_or_int,
bool_or_int_to_str,
csv_to_bool_seq,
bool_seq_to_csv,
DefaultNotGiven,
print_exception,
intensify_colors_on_win_setter,
@ -813,17 +810,6 @@ class GeneralSetting(Xettings):
if hasattr(locale, "LC_MESSAGES"):
LC_MESSAGES = Var.for_locale("LC_MESSAGES")
LOADED_RC_FILES = Var(
is_bool_seq,
csv_to_bool_seq,
bool_seq_to_csv,
(),
"Whether or not any of the xonsh run control files were loaded at "
"startup. This is a sequence of bools in Python that is converted "
"to a CSV list in string form, ie ``[True, False]`` becomes "
"``'True,False'``.",
is_configurable=False,
)
OLDPWD = Var.with_default(
".",
"Used to represent a previous present working directory.",
@ -2176,39 +2162,34 @@ def xonshrc_context(
rcfiles=None, rcdirs=None, execer=None, ctx=None, env=None, login=True
):
"""
Attempts to read in all xonshrc files and return the context.
The xonsh environment here is updated to reflect which RC files and
directory locations will have been loaded (if they existed). The updated
environment vars might be different (or empty) depending on CLI options
(--rc, --no-rc) or whether the session is interactive.
Attempts to read in all xonshrc files (and search xonshrc directories),
and returns the list of rc file paths successfully loaded, in the order
of loading.
"""
loaded = env["LOADED_RC_FILES"] = []
loaded = []
ctx = {} if ctx is None else ctx
if rcfiles is None and rcdirs is None:
return env
orig_thread = env.get("THREAD_SUBPROCS")
env["THREAD_SUBPROCS"] = None
if rcfiles is not None:
env["XONSHRC"] = tuple(rcfiles)
for rcfile in rcfiles:
if not os.path.isfile(rcfile):
loaded.append(False)
continue
status = xonsh_script_run_control(
rcfile, ctx, env, execer=execer, login=login
)
loaded.append(status)
if os.path.isfile(rcfile):
status = xonsh_script_run_control(
rcfile, ctx, env, execer=execer, login=login
)
if status:
loaded.append(rcfile)
if rcdirs is not None:
env["XONSHRC_DIR"] = tuple(rcdirs)
for rcdir in rcdirs:
if os.path.isdir(rcdir):
for rcfile in sorted(glob.glob(os.path.join(rcdir, "*.xsh"))):
status = xonsh_script_run_control(
rcfile, ctx, env, execer=execer, login=login
)
if status:
loaded.append(rcfile)
if env["THREAD_SUBPROCS"] is None:
env["THREAD_SUBPROCS"] = orig_thread
return ctx
return loaded
def windows_foreign_env_fixes(ctx):

View file

@ -320,7 +320,7 @@ def start_services(shell_kwargs, args, pre_env=None):
rcd = env.get("XONSHRC_DIR")
events.on_pre_rc.fire()
xonshrc_context(
XSH.rc_files = xonshrc_context(
rcfiles=rc, rcdirs=rcd, execer=execer, ctx=ctx, env=env, login=login
)
events.on_post_rc.fire()

View file

@ -552,6 +552,7 @@ def _info(ns):
data.extend([("on jupyter", jup_ksm is not None), ("jupyter kernel", jup_kernel)])
data.extend([("xontrib", xontribs_loaded())])
data.extend([("RC file", XSH.rc_files)])
formatter = _xonfig_format_json if ns.json else _xonfig_format_human
s = formatter(data)