Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Fix syntax_non_utf8 test to not depend on locale encoding
Use explicit encoding='latin-1' so the test works regardless of
the system locale (e.g. C/POSIX locale uses ASCII by default).
  • Loading branch information
youknowone committed Feb 22, 2026
commit 4ef242fd55bbc1ea5806314adf4fc9052b39a996
1 change: 1 addition & 0 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@
// "stat"
"FIRMLINK",
// CPython internal names
"PYTHONUTF",
"sysdict",
"settraceallthreads",
"setprofileallthreads"
Expand Down
25 changes: 8 additions & 17 deletions crates/vm/src/stdlib/_winapi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,9 +279,9 @@ mod _winapi {
}
si_attr!(dwFlags);
si_attr!(wShowWindow);
si_attr!(hStdInput, usize);
si_attr!(hStdOutput, usize);
si_attr!(hStdError, usize);
si_attr!(hStdInput, isize);
si_attr!(hStdOutput, isize);
si_attr!(hStdError, isize);

let mut env = args
.env_mapping
Expand Down Expand Up @@ -1160,7 +1160,7 @@ mod _winapi {
initial_state: bool,
name: Option<PyStrRef>,
vm: &VirtualMachine,
) -> PyResult<Option<WinHandle>> {
) -> PyResult<WinHandle> {
use windows_sys::Win32::System::Threading::CreateEventW as WinCreateEventW;

let _ = security_attributes; // Ignored, always NULL
Expand All @@ -1177,15 +1177,11 @@ mod _winapi {
)
};

if handle == windows_sys::Win32::Foundation::INVALID_HANDLE_VALUE {
return Err(vm.new_last_os_error());
}

if handle.is_null() {
return Ok(None);
return Err(vm.new_last_os_error());
}

Ok(Some(WinHandle(handle)))
Ok(WinHandle(handle))
}

/// SetEvent - Set the specified event object to the signaled state.
Expand Down Expand Up @@ -1944,9 +1940,7 @@ mod _winapi {
} else {
hr as u32
};
return Err(
std::io::Error::from_raw_os_error(err as i32).to_pyexception(vm),
);
return Err(std::io::Error::from_raw_os_error(err as i32).to_pyexception(vm));
}
Ok(())
}
Expand All @@ -1967,6 +1961,7 @@ mod _winapi {
if err != 0 {
return Err(vm.new_os_error(err as i32));
}
scopeguard::defer! { unsafe { RegCloseKey(hkcr) }; }

let mut i: u32 = 0;
let mut entries: Vec<(String, String)> = Vec::new();
Expand All @@ -1993,7 +1988,6 @@ mod _winapi {
break;
}
if err != 0 && err != windows_sys::Win32::Foundation::ERROR_MORE_DATA {
unsafe { RegCloseKey(hkcr) };
return Err(vm.new_os_error(err as i32));
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

Expand All @@ -2013,7 +2007,6 @@ mod _winapi {
continue;
}
if err != 0 {
unsafe { RegCloseKey(hkcr) };
return Err(vm.new_os_error(err as i32));
}

Expand Down Expand Up @@ -2057,8 +2050,6 @@ mod _winapi {
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

unsafe { RegCloseKey(hkcr) };

// Process remaining entries
for (mime_type, ext) in entries {
on_type_read.call((vm.ctx.new_str(mime_type), vm.ctx.new_str(ext)), vm)?;
Expand Down
6 changes: 5 additions & 1 deletion crates/vm/src/stdlib/sys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1588,7 +1588,11 @@ mod sys {
hash_randomization: settings.hash_seed.is_none() as u8,
isolated: settings.isolated as u8,
dev_mode: settings.dev_mode,
utf8_mode: settings.utf8_mode,
utf8_mode: if settings.utf8_mode < 0 {
1
} else {
settings.utf8_mode as u8
},
int_max_str_digits: settings.int_max_str_digits,
safe_path: settings.safe_path,
warn_default_encoding: settings.warn_default_encoding as u8,
Expand Down
4 changes: 2 additions & 2 deletions crates/vm/src/vm/setting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ pub struct Settings {
pub stdio_encoding: Option<String>,
/// PYTHONIOENCODING - stdio error handler
pub stdio_errors: Option<String>,
pub utf8_mode: u8,
pub utf8_mode: i8,
Comment thread
coderabbitai[bot] marked this conversation as resolved.
/// --check-hash-based-pycs
pub check_hash_pycs_mode: CheckHashPycsMode,

Expand Down Expand Up @@ -211,7 +211,7 @@ impl Default for Settings {
allow_external_library: cfg!(feature = "importlib"),
stdio_encoding: None,
stdio_errors: None,
utf8_mode: 0,
utf8_mode: -1,
int_max_str_digits: 4300,
#[cfg(feature = "flame-it")]
profile_output: None,
Expand Down
2 changes: 1 addition & 1 deletion extra_tests/snippets/syntax_non_utf8.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
dir_path = os.path.dirname(os.path.realpath(__file__))

with assert_raises(SyntaxError):
with open(os.path.join(dir_path , "non_utf8.txt")) as f:
with open(os.path.join(dir_path , "non_utf8.txt"), encoding="latin-1") as f:
eval(f.read())
18 changes: 14 additions & 4 deletions src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,10 +260,13 @@ pub fn parse_opts() -> Result<(Settings, RunMode), lexopt::Error> {

settings.check_hash_pycs_mode = args.check_hash_based_pycs;

if let Some(val) = get_env("PYTHONUTF8") {
settings.utf8_mode = match val.to_str() {
Some("1") | Some("") => 1,
Some("0") => 0,
if let Some(val) = get_env("PYTHONUTF8")
&& let Some(val_str) = val.to_str()
&& !val_str.is_empty()
{
settings.utf8_mode = match val_str {
"1" => 1,
"0" => 0,
_ => {
error!(
"Fatal Python error: config_init_utf8_mode: \
Expand Down Expand Up @@ -335,6 +338,13 @@ pub fn parse_opts() -> Result<(Settings, RunMode), lexopt::Error> {
});
settings.xoptions.extend(xopts);

// Resolve utf8_mode if not explicitly set by PYTHONUTF8 or -X utf8.
// Default to UTF-8 mode since RustPython's locale encoding detection
// is incomplete. Users can set PYTHONUTF8=0 or -X utf8=0 to disable.
if settings.utf8_mode < 0 {
settings.utf8_mode = 1;
}

settings.warn_default_encoding =
settings.warn_default_encoding || env_bool("PYTHONWARNDEFAULTENCODING");
settings.faulthandler = settings.faulthandler || env_bool("PYTHONFAULTHANDLER");
Expand Down
Loading