Skip to content

Commit 64c66e0

Browse files
youknowonefanninpm
andauthored
Fix encodings related error messages to be less confusing (RustPython#5049)
* Move cwd setup to interpreter code * rework import encodings failure message * try import_encodings only when `path_list` is set * std::mem::take instead of drain(..).collect() * Add empty path_list warnings to import_encodings * Prepend current working directory when !safe_path Co-authored-by: fanninpm <fanninpm@miamioh.edu>
1 parent 4ba2892 commit 64c66e0

File tree

4 files changed

+50
-22
lines changed

4 files changed

+50
-22
lines changed

src/interpreter.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,7 @@ pub fn init_stdlib(vm: &mut VirtualMachine) {
8484
let state = PyRc::get_mut(&mut vm.state).unwrap();
8585
let settings = &mut state.settings;
8686

87-
#[allow(clippy::needless_collect)] // false positive
88-
let path_list: Vec<_> = settings.path_list.drain(..).collect();
87+
let path_list = std::mem::take(&mut settings.path_list);
8988

9089
// BUILDTIME_RUSTPYTHONPATH should be set when distributing
9190
if let Some(paths) = option_env!("BUILDTIME_RUSTPYTHONPATH") {

src/lib.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,17 @@ fn run_rustpython(vm: &VirtualMachine, run_mode: RunMode, quiet: bool) -> PyResu
165165

166166
let scope = setup_main_module(vm)?;
167167

168-
let site_result = vm.import("site", None, 0);
168+
if !vm.state.settings.safe_path {
169+
// TODO: The prepending path depends on running mode
170+
// See https://docs.python.org/3/using/cmdline.html#cmdoption-P
171+
vm.run_code_string(
172+
vm.new_scope_with_builtins(),
173+
"import sys; sys.path.insert(0, '')",
174+
"<embedded>".to_owned(),
175+
)?;
176+
}
169177

178+
let site_result = vm.import("site", None, 0);
170179
if site_result.is_err() {
171180
warn!(
172181
"Failed to import site, consider adding the Lib directory to your RUSTPYTHONPATH \

vm/src/vm/mod.rs

+36-15
Original file line numberDiff line numberDiff line change
@@ -223,18 +223,30 @@ impl VirtualMachine {
223223
#[cfg(feature = "encodings")]
224224
fn import_encodings(&mut self) -> PyResult<()> {
225225
self.import("encodings", None, 0).map_err(|import_err| {
226-
let msg = if !self.state.settings.path_list.iter().any(|s| s == "PYTHONPATH" || s == "RUSTPYTHONPATH"){
227-
"Could not import encodings. Is your RUSTPYTHONPATH or PYTHONPATH set? If you don't have \
228-
access to a consistent external environment (e.g. if you're embedding \
229-
rustpython in another application), try enabling the freeze-stdlib feature"
230-
.to_owned()
226+
let rustpythonpath_env = std::env::var("RUSTPYTHONPATH").ok();
227+
let pythonpath_env = std::env::var("PYTHONPATH").ok();
228+
let env_set = rustpythonpath_env.as_ref().is_some() || pythonpath_env.as_ref().is_some();
229+
let path_contains_env = self.state.settings.path_list.iter().any(|s| {
230+
Some(s.as_str()) == rustpythonpath_env.as_deref() || Some(s.as_str()) == pythonpath_env.as_deref()
231+
});
232+
233+
let guide_message = if !env_set {
234+
"Neither RUSTPYTHONPATH nor PYTHONPATH is set. Try setting one of them to the stdlib directory."
235+
} else if path_contains_env {
236+
"RUSTPYTHONPATH or PYTHONPATH is set, but it doesn't contain the encodings library. If you are customizing the RustPython vm/interpreter, try adding the stdlib directory to the path. If you are developing the RustPython interpreter, it might be a bug during development."
231237
} else {
232-
"Could not import encodings. Try adding your path to Setting struct's path_list field. If you don't have \
233-
access to a consistent external environment (e.g. if you're embedding \
234-
rustpython in another application), try enabling the freeze-stdlib feature"
235-
.to_owned()
238+
"RUSTPYTHONPATH or PYTHONPATH is set, but it wasn't loaded to `Settings::path_list`. If you are going to customize the RustPython vm/interpreter, those environment variables are not loaded in the Settings struct by default. Please try creating a customized instance of the Settings struct. If you are developing the RustPython interpreter, it might be a bug during development."
236239
};
237240

241+
let msg = format!(
242+
"RustPython could not import the encodings module. It usually means something went wrong. Please carefully read the following messages and follow the steps.\n\
243+
\n\
244+
{guide_message}\n\
245+
If you don't have access to a consistent external environment (e.g. targeting wasm, embedding \
246+
rustpython in another application), try enabling the `freeze-stdlib` feature.\n\
247+
If this is intended and you want to exclude the encodings module from your interpreter, please remove the `encodings` feature from `rustpython-vm` crate."
248+
);
249+
238250
let err = self.new_runtime_error(msg);
239251
err.set_cause(Some(import_err));
240252
err
@@ -267,9 +279,6 @@ impl VirtualMachine {
267279
panic!("Double Initialize Error");
268280
}
269281

270-
// add the current directory to sys.path
271-
self.state_mut().settings.path_list.insert(0, "".to_owned());
272-
273282
stdlib::builtins::init_module(self, &self.builtins);
274283
stdlib::sys::init_module(self, &self.sys_module, &self.builtins);
275284

@@ -327,9 +336,21 @@ impl VirtualMachine {
327336
}
328337

329338
#[cfg(feature = "encodings")]
330-
if let Err(e) = self.import_encodings() {
331-
eprintln!("encodings initialization failed. Only utf-8 encoding will be supported.");
332-
self.print_exception(e);
339+
if cfg!(feature = "freeze-stdlib") || !self.state.settings.path_list.is_empty() {
340+
if let Err(e) = self.import_encodings() {
341+
eprintln!(
342+
"encodings initialization failed. Only utf-8 encoding will be supported."
343+
);
344+
self.print_exception(e);
345+
}
346+
} else {
347+
// Here may not be the best place to give general `path_list` advice,
348+
// but bare rustpython_vm::VirtualMachine users skipped proper settings must hit here while properly setup vm never enters here.
349+
eprintln!(
350+
"feature `encodings` is enabled but `settings.path_list` is empty. \
351+
Please add the library path to `settings.path_list`. If you intended to disable the entire standard library (including the `encodings` feature), please also make sure to disable the `encodings` feature.\n\
352+
Tip: You may also want to add `\"\"` to `settings.path_list` in order to enable importing from the current working directory."
353+
);
333354
}
334355

335356
self.initialized = true;

vm/src/vm/setting.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,9 @@ pub struct Settings {
8989
}
9090

9191
impl Settings {
92-
pub fn with_path(path: String) -> Self {
93-
let mut settings = Self::default();
94-
settings.path_list.push(path);
95-
settings
92+
pub fn with_path(mut self, path: String) -> Self {
93+
self.path_list.push(path);
94+
self
9695
}
9796
}
9897

0 commit comments

Comments
 (0)