diff --git a/crates/vm/src/codecs.rs b/crates/vm/src/codecs.rs index 587701d6528..f3b6b13342f 100644 --- a/crates/vm/src/codecs.rs +++ b/crates/vm/src/codecs.rs @@ -261,6 +261,7 @@ impl CodecsRegistry { } pub fn lookup(&self, encoding: &str, vm: &VirtualMachine) -> PyResult { + let original_encoding = encoding; let encoding = normalize_encoding_name(encoding); let search_path = { let inner = self.inner.read(); @@ -286,7 +287,7 @@ impl CodecsRegistry { } } - Err(vm.new_lookup_error(format!("unknown encoding: {encoding}"))) + Err(vm.new_lookup_error(format!("unknown encoding: {original_encoding}"))) } fn _lookup_text_encoding( diff --git a/extra_tests/snippets/stdlib_codecs_wide.py b/extra_tests/snippets/stdlib_codecs_wide.py index d5a7d68fe8c..4b950ba70ba 100644 --- a/extra_tests/snippets/stdlib_codecs_wide.py +++ b/extra_tests/snippets/stdlib_codecs_wide.py @@ -28,3 +28,39 @@ _codecs.utf_32_ex_decode(b"\xff\xfe\x00\x00h\x00\x00\x00", "strict", 0, True)[0] == "h" ) + + +# Lookup errors preserve the requested spelling, while search hooks receive +# the Python 3.14 normalized registry key. +import codecs + +seen_encoding_names = [] + + +def record_unknown_encoding(name): + seen_encoding_names.append(name) + return None + + +codecs.register(record_unknown_encoding) +try: + for requested, normalized in ( + ("NO Such Codec!", "no_such_codec"), + ("x_ weird--Ω .Ab", "x_weird_.ab"), + ): + for lookup in ( + codecs.lookup, + lambda name: codecs.encode("value", name), + lambda name: codecs.decode(b"value", name), + lambda name: "value".encode(name), + lambda name: b"value".decode(name), + ): + try: + lookup(requested) + except LookupError as error: + assert str(error) == "unknown encoding: " + requested + else: + assert False, "unknown encoding was accepted" + assert seen_encoding_names[-1] == normalized +finally: + codecs.unregister(record_unknown_encoding)