diff --git a/crates/erg_common/python_util.rs b/crates/erg_common/python_util.rs index d18e8e1f7..894210298 100644 --- a/crates/erg_common/python_util.rs +++ b/crates/erg_common/python_util.rs @@ -596,13 +596,33 @@ fn get_poetry_virtualenv_path() -> Option { let out = if cfg!(windows) { Command::new("cmd") .arg("/C") - .arg("poetry env info -p") + .args(["poetry", "env", "info", "-p"]) .output() .ok()? } else { Command::new("sh") .arg("-c") - .arg("poetry env info -p") + .args(["poetry", "env", "info", "-p"]) + .output() + .ok()? + }; + let path = String::from_utf8(out.stdout).ok()?; + Path::new(path.trim()) + .exists() + .then_some(path.trim().to_string()) +} + +fn get_uv_python_venv_path() -> Option { + let out = if cfg!(windows) { + Command::new("cmd") + .arg("/C") + .args(["uv", "python", "find"]) + .output() + .ok()? + } else { + Command::new("sh") + .arg("-c") + .args(["uv", "python", "find"]) .output() .ok()? }; @@ -616,19 +636,32 @@ pub fn _opt_which_python() -> Result { if let Some(path) = which_python_from_toml() { return Ok(path); } - if Path::new("./.venv/bin/python").is_file() { - let path = canonicalize("./.venv/bin/python").unwrap(); + let venv_path = if cfg!(windows) { + r".venv\Scripts\python.exe" + } else { + ".venv/bin/python" + }; + if Path::new(&venv_path).is_file() { + let path = canonicalize(venv_path).unwrap(); return Ok(path.to_string_lossy().to_string()); - } else if let Some(path) = get_poetry_virtualenv_path() { + } + if let Some(path) = get_poetry_virtualenv_path() { return Ok(format!("{path}/bin/python")); } - let (cmd, python) = if cfg!(windows) { - ("where", "python") + if let Some(path) = get_uv_python_venv_path() { + return Ok(path); + } + let out = if cfg!(windows) { + Command::new("cmd") + .arg("/C") + .arg("where") + .arg("python") + .output() } else { - ("which", "python3") + Command::new("sh").arg("-c").arg("which python3").output() }; - let Ok(out) = Command::new(cmd).arg(python).output() else { - return Err(format!("{}: {python} not found", fn_name_full!())); + let Ok(out) = out else { + return Err(format!("{}: python not found", fn_name_full!())); }; let Ok(res) = String::from_utf8(out.stdout) else { return Err(format!( @@ -638,7 +671,7 @@ pub fn _opt_which_python() -> Result { }; let res = res.split('\n').next().unwrap_or("").replace('\r', ""); if res.is_empty() { - return Err(format!("{}: {python} not found", fn_name_full!())); + return Err(format!("{}: python not found", fn_name_full!())); } else if res.contains("pyenv") && cfg!(windows) { // because pyenv-win does not support `-c` option return Err("cannot use pyenv-win".into()); diff --git a/crates/erg_compiler/codegen.rs b/crates/erg_compiler/codegen.rs index b4ec235d2..9c5d31e63 100644 --- a/crates/erg_compiler/codegen.rs +++ b/crates/erg_compiler/codegen.rs @@ -3976,6 +3976,34 @@ impl PyCodeGenerator { self.emit_import_all_instr(erg_std_mod); } + fn load_encoding_utf8(&mut self) { + let no_std = self.cfg.no_std; + self.cfg.no_std = true; + self.load_sys_encoding(); + self.cfg.no_std = no_std; + } + + fn load_sys_encoding(&mut self) { + self.load_reconfigure(); + self.emit_load_name_instr(Identifier::private("#stdout")); + self.emit_load_method_instr(Identifier::static_public("reconfigure"), BoundAttr); + self.emit_load_const("utf-8"); + let kws = vec![ValueObj::Str("encoding".into())]; + if self.py_version.minor >= Some(11) { + let idx = self.register_const(kws); + self.write_instr(Opcode311::KW_NAMES); + self.write_arg(idx); + self.emit_precall_and_call(1); + self.stack_dec(); + } else { + self.emit_load_const(kws); + self.write_instr(Opcode310::CALL_FUNCTION_KW); + self.write_arg(1); + self.stack_dec_n(2); + } + self.emit_pop_top(); + } + fn load_record_type(&mut self) { self.emit_global_import_items( Identifier::static_public("collections"), @@ -4002,6 +4030,16 @@ impl PyCodeGenerator { ); } + fn load_reconfigure(&mut self) { + self.emit_global_import_items( + Identifier::static_public("sys"), + vec![( + Identifier::static_public("stdout"), + Some(Identifier::private("#stdout")), + )], + ); + } + fn load_union(&mut self) { self.emit_global_import_items( Identifier::static_public("_erg_type"), @@ -4062,6 +4100,9 @@ impl PyCodeGenerator { if !self.cfg.no_std && !self.prelude_loaded { self.load_prelude(); } + if !self.cfg.no_std && !self.cfg.input.is_repl() { + self.load_encoding_utf8(); + } for chunk in hir.module.into_iter() { self.emit_chunk(chunk); // TODO: discard diff --git a/tests/test.rs b/tests/test.rs index a33429397..342538fb8 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -183,12 +183,7 @@ fn exec_fib() -> Result<(), ()> { #[test] fn exec_helloworld() -> Result<(), ()> { - // HACK: When running the test with Windows, the exit code is 1 (the cause is unknown) - if cfg!(windows) && env_python_version().unwrap().minor >= Some(8) { - expect_end_with("examples/helloworld.er", 0, 1) - } else { - expect_success("examples/helloworld.er", 0) - } + expect_success("examples/helloworld.er", 0) } #[test]