validation: dedicated venv + fix python_bin override timing
eval_proc was started before -d/GUI defines reached gd, so ``-d python_bin=...`` and the GUI ``python_bin`` preference were silently ignored by the very subprocess that runs ``<| ... |>`` evals (and only took effect for later items once the discovery cache had already been seeded with the system interpreter). apply_overrides() is now applied before eval_process_init(), and bins._resolve()'s cache is keyed by (name, override) so a later param.yaml change re-resolves on the next lookup. The validation suite now ships a wrapper (run.sh / run.bat) that creates a dedicated venv in the system temp dir and pins it via ``-d python_bin=...``. A new ``venv`` item asserts the override took effect for both eval_proc and py_func paths, with a ``sys.prefix != sys.base_prefix`` marker to catch the case where the override happens to be a system interpreter (path-equality alone would miss it, the venv's ``bin/python3`` being a symlink to the host). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,7 @@ from interpreter.utils.test_init import (
|
||||
env_init,
|
||||
prepare_global,
|
||||
update_global,
|
||||
apply_overrides,
|
||||
set_standard_gd_keys,
|
||||
test_run_init,
|
||||
test_run_header,
|
||||
@@ -210,6 +211,19 @@ class TestProcess(Process):
|
||||
|
||||
env_init()
|
||||
|
||||
# Apply GUI defaults and CLI defines to the global dict
|
||||
# *before* eval_proc starts: bins.python_bin() reads
|
||||
# ``python_bin`` from gd on its very first call (during
|
||||
# eval_process_init) and caches the result. Without this,
|
||||
# ``-d python_bin=...`` and the GUI ``python_bin`` preference
|
||||
# would only take effect for items spawned *after* the cache
|
||||
# was already populated with the auto-discovered interpreter,
|
||||
# i.e. they would silently be ignored for eval_proc itself.
|
||||
# _load_initial_params re-applies the same overrides after
|
||||
# ``prepare_global()`` clears gd, so the gd value stays in
|
||||
# sync with the cached path.
|
||||
apply_overrides(self.__defs, self.__gui_defaults)
|
||||
|
||||
# Creation of the python evaluation process for loading of the complete test
|
||||
eval_proc = eval_process_init(api_request, 10, test_dir)
|
||||
eval_proc.start()
|
||||
|
||||
@@ -202,16 +202,24 @@ _SPECS = {
|
||||
"lua": ("Lua 5.1+", "lua_bin", _LUA_CANDIDATES, _is_lua51),
|
||||
}
|
||||
|
||||
# Cached per (name, override) so that runtime changes to gd[gd_key] —
|
||||
# e.g. ``python_bin`` set from a YAML config file loaded *after*
|
||||
# eval_proc has already resolved its own interpreter — are picked up by
|
||||
# the next lookup instead of returning the stale, auto-discovered path.
|
||||
# Long-lived subprocesses (eval_proc) keep whatever they captured at
|
||||
# construction time, but every new PyProcessBase / FuncExecEngine spawned
|
||||
# afterwards sees the current override.
|
||||
_resolved = {}
|
||||
|
||||
|
||||
def _resolve(name):
|
||||
if name in _resolved:
|
||||
return _resolved[name]
|
||||
|
||||
display, gd_key, candidates, validator = _SPECS[name]
|
||||
override = tm.gd(gd_key, "") or ""
|
||||
|
||||
cached = _resolved.get(name)
|
||||
if cached is not None and cached[0] == override:
|
||||
return cached[1]
|
||||
|
||||
path = ""
|
||||
if override:
|
||||
# Absolute path: accept as-is (user knows exactly what they want).
|
||||
@@ -239,7 +247,7 @@ def _resolve(name):
|
||||
path = p
|
||||
break
|
||||
|
||||
_resolved[name] = path
|
||||
_resolved[name] = (override, path)
|
||||
return path
|
||||
|
||||
|
||||
|
||||
@@ -165,11 +165,14 @@ def env_init():
|
||||
_constants_init()
|
||||
|
||||
|
||||
def update_global(config_files, defines, gui_defaults, silent=False):
|
||||
"""Global dict updated with the content of the config file and a dict provided.
|
||||
this function returns the resulting dict.
|
||||
def apply_overrides(defines, gui_defaults):
|
||||
"""Push GUI defaults then CLI defines into the global dict.
|
||||
|
||||
Extracted from update_global so it can be called *before* eval_proc
|
||||
starts: interpreter overrides (python_bin, lua_bin) must be visible
|
||||
to bins.python_bin() on its first lookup, which happens during
|
||||
eval_process_init.
|
||||
"""
|
||||
# GUI preferences applied first
|
||||
for k, v in gui_defaults.items():
|
||||
try:
|
||||
val = ast.literal_eval(v)
|
||||
@@ -177,7 +180,6 @@ def update_global(config_files, defines, gui_defaults, silent=False):
|
||||
val = v
|
||||
tm.setgd(k, val)
|
||||
|
||||
# Then command line defines
|
||||
for k, v in defines.items():
|
||||
try:
|
||||
val = ast.literal_eval(v)
|
||||
@@ -185,6 +187,14 @@ def update_global(config_files, defines, gui_defaults, silent=False):
|
||||
val = v
|
||||
tm.setgd(k, val)
|
||||
|
||||
|
||||
def update_global(config_files, defines, gui_defaults, silent=False):
|
||||
"""Global dict updated with the content of the config file and a dict provided.
|
||||
this function returns the resulting dict.
|
||||
"""
|
||||
# GUI preferences applied first, then command line defines
|
||||
apply_overrides(defines, gui_defaults)
|
||||
|
||||
# Then the configuration files
|
||||
# load global dic before test item
|
||||
_feed_gd_with_params(config_files, silent)
|
||||
|
||||
Reference in New Issue
Block a user