Skip to content

Commit 1be1628

Browse files
authored
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
1 parent b653c02 commit 1be1628

4 files changed

Lines changed: 55 additions & 5 deletions

File tree

‎Lib/test/test_cmd_line.py‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1369,7 +1369,6 @@ def test_presite(self):
13691369
proc = assert_python_ok("-X", f"presite={entrypoint}", "-c", "pass")
13701370
self.assertEqual(proc.out.rstrip(), b"presite func")
13711371

1372-
@unittest.expectedFailure # TODO: RUSTPYTHON; explicit PYTHONHOME startup path configuration and fatal encodings failure reporting are not implemented
13731372
def test_dump_path_config(self):
13741373
# gh-151253: At the first import (import encodings) during Python
13751374
# startup, if the import fails, dump the Python path configuration.

‎crates/vm/src/vm/mod.rs‎

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ pub struct VirtualMachine {
111111
pub state: PyRc<PyGlobalState>,
112112
pub initialized: bool,
113113
pub(crate) import_bootstrap_complete: bool,
114+
startup_error: Option<PyBaseExceptionRef>,
114115
recursion_depth: Cell<usize>,
115116
/// Depth of native recursion that pushes no Python frame, counted only
116117
/// where the stack pointer cannot be read. Everywhere else the native
@@ -1372,6 +1373,7 @@ impl VirtualMachine {
13721373
state,
13731374
initialized: false,
13741375
import_bootstrap_complete: false,
1376+
startup_error: None,
13751377
recursion_depth: Cell::new(0),
13761378
#[cfg(any(miri, target_env = "musl"))]
13771379
native_recursion_depth: Cell::new(0),
@@ -1409,6 +1411,9 @@ impl VirtualMachine {
14091411
#[cfg(feature = "encodings")]
14101412
fn import_encodings(&mut self) -> PyResult<()> {
14111413
self.import("encodings", 0).map_err(|import_err| {
1414+
if self.state.config.settings.home.is_some() {
1415+
return import_err;
1416+
}
14121417
let rustpythonpath_env = crate::host_env::os::var("RUSTPYTHONPATH").ok();
14131418
let pythonpath_env = crate::host_env::os::var("PYTHONPATH").ok();
14141419
let env_set = rustpythonpath_env.as_ref().is_some() || pythonpath_env.as_ref().is_some();
@@ -1668,10 +1673,14 @@ impl VirtualMachine {
16681673
#[cfg(feature = "encodings")]
16691674
if _expect_stdlib {
16701675
if let Err(e) = self.import_encodings() {
1671-
eprintln!(
1672-
"encodings initialization failed. Only utf-8 encoding will be supported."
1673-
);
1674-
self.print_exception(&e);
1676+
if self.state.config.settings.home.is_some() {
1677+
self.startup_error = Some(e);
1678+
} else {
1679+
eprintln!(
1680+
"encodings initialization failed. Only utf-8 encoding will be supported."
1681+
);
1682+
self.print_exception(&e);
1683+
}
16751684
}
16761685
} else {
16771686
// Here may not be the best place to give general `path_list` advice,
@@ -1686,6 +1695,46 @@ impl VirtualMachine {
16861695
self.initialized = true;
16871696
}
16881697

1698+
/// Report an invalid explicit standard-library configuration to a command-line
1699+
/// host. Embedding applications may continue using the bootstrap codecs without calling this.
1700+
pub fn check_stdlib_initialization(&self) -> PyResult<()> {
1701+
let Some(error) = &self.startup_error else {
1702+
return Ok(());
1703+
};
1704+
let settings = &self.state.config.settings;
1705+
let paths = &self.state.config.paths;
1706+
let repr = |value: &str| {
1707+
self.ctx
1708+
.new_str(value)
1709+
.repr(self)
1710+
.unwrap_or_else(|_| "?".to_owned())
1711+
};
1712+
eprintln!("Python path configuration:");
1713+
eprintln!(
1714+
" PYTHONHOME = {}",
1715+
settings
1716+
.home
1717+
.as_deref()
1718+
.map_or_else(|| "(not set)".to_owned(), repr)
1719+
);
1720+
eprintln!(" isolated = {}", u8::from(settings.isolated));
1721+
eprintln!(" environment = {}", u8::from(!settings.ignore_environment));
1722+
eprintln!(" sys.executable = {}", repr(&paths.executable));
1723+
eprintln!(" sys.prefix = {}", repr(&paths.prefix));
1724+
eprintln!(" sys.exec_prefix = {}", repr(&paths.exec_prefix));
1725+
eprintln!(" sys.path = [");
1726+
for path in &paths.module_search_paths {
1727+
eprintln!(" {},", repr(path));
1728+
}
1729+
eprintln!(" ]");
1730+
// A startup import failure is fatal even if the imported module raised
1731+
// SystemExit(0) or SystemExit(None). Keep its exception as the cause,
1732+
// without passing its exit code to ordinary user-code finalization.
1733+
let startup_error = self.new_runtime_error("Failed to import encodings module");
1734+
startup_error.set_cause(Some(error.clone()));
1735+
Err(startup_error)
1736+
}
1737+
16891738
/// Apply configured global lazy imports after startup imports, including site.
16901739
/// Hosts that perform their own main-module setup can call this at that boundary.
16911740
pub fn apply_startup_lazy_imports(&self) {

‎crates/vm/src/vm/thread.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1481,6 +1481,7 @@ impl VirtualMachine {
14811481
state: self.state.clone(),
14821482
initialized: self.initialized,
14831483
import_bootstrap_complete: self.import_bootstrap_complete,
1484+
startup_error: self.startup_error.clone(),
14841485
recursion_depth: Cell::new(0),
14851486
#[cfg(any(miri, target_env = "musl"))]
14861487
native_recursion_depth: Cell::new(0),

‎src/lib.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@ fn run_rustpython(vm: &VirtualMachine, run_mode: RunMode) -> u32 {
314314

315315
// pymain_run_python
316316
fn pymain_run_python(vm: &VirtualMachine, run_mode: RunMode) -> PyResult<u32> {
317+
vm.check_stdlib_initialization()?;
317318
let scope = vm.new_scope_with_main()?;
318319

319320
// The native warnings state already holds the default filters. Import the

0 commit comments

Comments
 (0)