Skip to content
6 changes: 6 additions & 0 deletions Doc/deprecations/pending-removal-in-3.17.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ Pending removal in Python 3.17
(Contributed by Shantanu Jain in :gh:`91896`.)


* :mod:`encodings`:

- Passing non-ascii *encoding* names to :func:`encodings.normalize_encoding`
is deprecated and scheduled for removal in Python 3.17.
(Contributed by Stan Ulbrych in :gh:`136702`)

* :mod:`typing`:

- Before Python 3.14, old-style unions were implemented using the private class
Expand Down
8 changes: 7 additions & 1 deletion Lib/encodings/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.

"""#"
"""

import codecs
import sys
Expand Down Expand Up @@ -56,6 +56,12 @@ def normalize_encoding(encoding):
if isinstance(encoding, bytes):
encoding = str(encoding, "ascii")

if not encoding.isascii():
import warnings
warnings.warn(
"Support for non-ascii encoding names will be removed in 3.17",
DeprecationWarning, stacklevel=2)

return _normalize_encoding(encoding)

def search_function(encoding):
Expand Down
10 changes: 7 additions & 3 deletions Lib/test/test_codecs.py
Original file line number Diff line number Diff line change
Expand Up @@ -3886,22 +3886,26 @@ def search_function(encoding):
self.assertEqual(codecs.lookup('TEST.AAA 8'), ('test.aaa-8', 2, 3, 4))
self.assertEqual(codecs.lookup('TEST.AAA---8'), ('test.aaa---8', 2, 3, 4))
self.assertEqual(codecs.lookup('TEST.AAA 8'), ('test.aaa---8', 2, 3, 4))
self.assertEqual(codecs.lookup('TEST.AAA\xe9\u20ac-8'), ('test.aaa\xe9\u20ac-8', 2, 3, 4))
self.assertEqual(codecs.lookup('TEST.AAA.8'), ('test.aaa.8', 2, 3, 4))
self.assertEqual(codecs.lookup('TEST.AAA...8'), ('test.aaa...8', 2, 3, 4))
with self.assertWarns(DeprecationWarning):
self.assertEqual(codecs.lookup('TEST.AAA\xe9\u20ac-8'), ('test.aaa\xe9\u20ac-8', 2, 3, 4))

def test_encodings_normalize_encoding(self):
# encodings.normalize_encoding() ignores non-ASCII characters.
normalize = encodings.normalize_encoding
self.assertEqual(normalize('utf_8'), 'utf_8')
self.assertEqual(normalize('utf\xE9\u20AC\U0010ffff-8'), 'utf_8')
self.assertEqual(normalize('utf 8'), 'utf_8')
# encodings.normalize_encoding() doesn't convert
# characters to lower case.
self.assertEqual(normalize('UTF 8'), 'UTF_8')
self.assertEqual(normalize('utf.8'), 'utf.8')
self.assertEqual(normalize('utf...8'), 'utf...8')

# Non-ASCII *encoding* is deprecated.
with self.assertWarnsRegex(DeprecationWarning,
"Support for non-ascii encoding names will be removed in 3.17"):
self.assertEqual(normalize('utf\xE9\u20AC\U0010ffff-8'), 'utf_8')


if __name__ == "__main__":
unittest.main()
5 changes: 4 additions & 1 deletion Lib/test/test_email/test_email.py
Original file line number Diff line number Diff line change
Expand Up @@ -5717,7 +5717,10 @@ def test_rfc2231_bad_character_in_encoding(self):

"""
msg = email.message_from_string(m)
self.assertEqual(msg.get_filename(), 'myfile.txt')
import warnings
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
self.assertEqual(msg.get_filename(), 'myfile.txt')
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bitdancer It was indeed tested.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I missed that. I guess maybe warnings weren't enabled the way I ran the tests, though I thought I was doing so...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you want to do, keep it like so or revert to my backwards-compatible approach?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe I've confirmed that the tests will still pass after lookup starts raising a ValueError, which is what I was hoping would happen. I wonder if we should actually assert the deprecation warning here, though, so that we are reminded to remove the check when the deprecation turns into reality. I'm fine with whatever is standard practice for such cases, though.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Converted to asserts.


def test_rfc2231_single_tick_in_filename_extended(self):
eq = self.assertEqual
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:mod:`encodings`: Deprecate passing a non-ascii *encoding* name to
:func:`encodings.normalize_encoding` and schedule removal of support for
Python 3.17.
Loading