Report fatal explicit-home startup failures (#9227)

* Report fatal explicit-home encodings initialization failures

Retain explicit standard-library initialization errors for the command-line host, preserving default embedding fallback and the original exception cause.

Assisted-by: OpenAI Codex: model version unavailable

* Enable canonical fatal startup path configuration coverage

Retire the verified expected failure through update_lib, preserving the explicit local path-environment adaptation and all other markers.

Assisted-by: OpenAI Codex: model version unavailable
This commit is contained in:
youknowdot authored and GitHub committed 2026-10-20 09:27:23 +09:00
1 parent b653c02741
commit 1be1628666
4 files changed
+55 -5

No files matched your search

-1
View File
@@ -1369,7 +1369,6 @@ class CmdLineTest(unittest.TestCase):
proc = assert_python_ok("-X", f"presite={entrypoint}", "-c", "pass")
self.assertEqual(proc.out.rstrip(), b"presite func")
@unittest.expectedFailure # TODO: RUSTPYTHON; explicit PYTHONHOME startup path configuration and fatal encodings failure reporting are not implemented
def test_dump_path_config(self):
# gh-151253: At the first import (import encodings) during Python
# startup, if the import fails, dump the Python path configuration.
+53 -4
View File
@@ -111,6 +111,7 @@ pub struct VirtualMachine {
pub state: PyRc<PyGlobalState>,
pub initialized: bool,
pub(crate) import_bootstrap_complete: bool,
startup_error: Option<PyBaseExceptionRef>,
recursion_depth: Cell<usize>,
/// Depth of native recursion that pushes no Python frame, counted only
/// where the stack pointer cannot be read. Everywhere else the native
@@ -1372,6 +1373,7 @@ impl VirtualMachine {
state,
initialized: false,
import_bootstrap_complete: false,
startup_error: None,
recursion_depth: Cell::new(0),
#[cfg(any(miri, target_env = "musl"))]
native_recursion_depth: Cell::new(0),
@@ -1409,6 +1411,9 @@ impl VirtualMachine {
#[cfg(feature = "encodings")]
fn import_encodings(&mut self) -> PyResult<()> {
self.import("encodings", 0).map_err(|import_err| {
if self.state.config.settings.home.is_some() {
return import_err;
}
let rustpythonpath_env = crate::host_env::os::var("RUSTPYTHONPATH").ok();
let pythonpath_env = crate::host_env::os::var("PYTHONPATH").ok();
let env_set = rustpythonpath_env.as_ref().is_some() || pythonpath_env.as_ref().is_some();
@@ -1668,10 +1673,14 @@ impl VirtualMachine {
#[cfg(feature = "encodings")]
if _expect_stdlib {
if let Err(e) = self.import_encodings() {
eprintln!(
"encodings initialization failed. Only utf-8 encoding will be supported."
);
self.print_exception(&e);
if self.state.config.settings.home.is_some() {
self.startup_error = Some(e);
} else {
eprintln!(
"encodings initialization failed. Only utf-8 encoding will be supported."
);
self.print_exception(&e);
}
}
} else {
// Here may not be the best place to give general `path_list` advice,
@@ -1686,6 +1695,46 @@ impl VirtualMachine {
self.initialized = true;
}
/// Report an invalid explicit standard-library configuration to a command-line
/// host. Embedding applications may continue using the bootstrap codecs without calling this.
pub fn check_stdlib_initialization(&self) -> PyResult<()> {
let Some(error) = &self.startup_error else {
return Ok(());
};
let settings = &self.state.config.settings;
let paths = &self.state.config.paths;
let repr = |value: &str| {
self.ctx
.new_str(value)
.repr(self)
.unwrap_or_else(|_| "?".to_owned())
};
eprintln!("Python path configuration:");
eprintln!(
" PYTHONHOME = {}",
settings
.home
.as_deref()
.map_or_else(|| "(not set)".to_owned(), repr)
);
eprintln!(" isolated = {}", u8::from(settings.isolated));
eprintln!(" environment = {}", u8::from(!settings.ignore_environment));
eprintln!(" sys.executable = {}", repr(&paths.executable));
eprintln!(" sys.prefix = {}", repr(&paths.prefix));
eprintln!(" sys.exec_prefix = {}", repr(&paths.exec_prefix));
eprintln!(" sys.path = [");
for path in &paths.module_search_paths {
eprintln!(" {},", repr(path));
}
eprintln!(" ]");
// A startup import failure is fatal even if the imported module raised
// SystemExit(0) or SystemExit(None). Keep its exception as the cause,
// without passing its exit code to ordinary user-code finalization.
let startup_error = self.new_runtime_error("Failed to import encodings module");
startup_error.set_cause(Some(error.clone()));
Err(startup_error)
}
/// Apply configured global lazy imports after startup imports, including site.
/// Hosts that perform their own main-module setup can call this at that boundary.
pub fn apply_startup_lazy_imports(&self) {
+1
View File
@@ -1481,6 +1481,7 @@ impl VirtualMachine {
state: self.state.clone(),
initialized: self.initialized,
import_bootstrap_complete: self.import_bootstrap_complete,
startup_error: self.startup_error.clone(),
recursion_depth: Cell::new(0),
#[cfg(any(miri, target_env = "musl"))]
native_recursion_depth: Cell::new(0),
+1
View File
@@ -314,6 +314,7 @@ fn run_rustpython(vm: &VirtualMachine, run_mode: RunMode) -> u32 {
// pymain_run_python
fn pymain_run_python(vm: &VirtualMachine, run_mode: RunMode) -> PyResult<u32> {
vm.check_stdlib_initialization()?;
let scope = vm.new_scope_with_main()?;
// The native warnings state already holds the default filters. Import the