@@ -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 ) {
0 commit comments