From 752c0f68fd76b76aa85552be33a880fac65745e7 Mon Sep 17 00:00:00 2001 From: "Jeong, YunWon" Date: Fri, 12 Dec 2025 20:12:30 +0900 Subject: [PATCH] fix windows locale --- Lib/test/test_locale.py | 1 - crates/stdlib/src/locale.rs | 43 +++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_locale.py b/Lib/test/test_locale.py index 9e1f46f64..71d03f3a3 100644 --- a/Lib/test/test_locale.py +++ b/Lib/test/test_locale.py @@ -511,7 +511,6 @@ class TestRealLocales(unittest.TestCase): self.skipTest(f"setlocale(LC_CTYPE, {loc!r}) failed: {exc!r}") self.assertEqual(loc, locale.getlocale(locale.LC_CTYPE)) - @unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; Error not raised') @unittest.skipUnless(os.name == 'nt', 'requires Windows') def test_setlocale_long_encoding(self): with self.assertRaises(locale.Error): diff --git a/crates/stdlib/src/locale.rs b/crates/stdlib/src/locale.rs index 630d2a419..6cca8b912 100644 --- a/crates/stdlib/src/locale.rs +++ b/crates/stdlib/src/locale.rs @@ -198,6 +198,34 @@ mod _locale { locale: OptionalArg>, } + /// Maximum code page encoding name length on Windows + #[cfg(windows)] + const MAX_CP_LEN: usize = 15; + + /// Check if the encoding part of a locale string is too long (Windows only) + #[cfg(windows)] + fn check_locale_name(locale: &str) -> bool { + if let Some(dot_pos) = locale.find('.') { + let encoding_part = &locale[dot_pos + 1..]; + // Find the end of encoding (could be followed by '@' modifier) + let encoding_len = encoding_part.find('@').unwrap_or(encoding_part.len()); + encoding_len <= MAX_CP_LEN + } else { + true + } + } + + /// Check locale names for LC_ALL (handles semicolon-separated locales) + #[cfg(windows)] + fn check_locale_name_all(locale: &str) -> bool { + for part in locale.split(';') { + if !check_locale_name(part) { + return false; + } + } + true + } + #[pyfunction] fn setlocale(args: LocaleArgs, vm: &VirtualMachine) -> PyResult { let error = error(vm); @@ -208,6 +236,21 @@ mod _locale { let result = match args.locale.flatten() { None => libc::setlocale(args.category, ptr::null()), Some(locale) => { + // On Windows, validate encoding name length + #[cfg(windows)] + { + let valid = if args.category == LC_ALL { + check_locale_name_all(locale.as_str()) + } else { + check_locale_name(locale.as_str()) + }; + if !valid { + return Err(vm.new_exception_msg( + error, + String::from("unsupported locale setting"), + )); + } + } let c_locale: CString = CString::new(locale.as_str()).map_err(|e| e.to_pyexception(vm))?; libc::setlocale(args.category, c_locale.as_ptr())