bpo-43510: Implement PEP 597 opt-in EncodingWarning. (GH-19481)
See [PEP 597](https://www.python.org/dev/peps/pep-0597/).
* Add `-X warn_default_encoding` and `PYTHONWARNDEFAULTENCODING`.
* Add EncodingWarning
* Add io.text_encoding()
* open(), TextIOWrapper() emits EncodingWarning when encoding is omitted and warn_default_encoding is enabled.
* _pyio.TextIOWrapper() uses UTF-8 as fallback default encoding used when failed to import locale module. (used during building Python)
* bz2, configparser, gzip, lzma, pathlib, tempfile modules use io.text_encoding().
* What's new entry
diff --git a/Lib/test/exception_hierarchy.txt b/Lib/test/exception_hierarchy.txt
index 763a6c8..6c5e821 100644
--- a/Lib/test/exception_hierarchy.txt
+++ b/Lib/test/exception_hierarchy.txt
@@ -61,4 +61,5 @@
+-- ImportWarning
+-- UnicodeWarning
+-- BytesWarning
+ +-- EncodingWarning
+-- ResourceWarning
diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py
index 6833b25..646cd06 100644
--- a/Lib/test/test_embed.py
+++ b/Lib/test/test_embed.py
@@ -389,6 +389,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
'site_import': 1,
'bytes_warning': 0,
+ 'warn_default_encoding': 0,
'inspect': 0,
'interactive': 0,
'optimization_level': 0,
diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
index 3768b62..c731302 100644
--- a/Lib/test/test_io.py
+++ b/Lib/test/test_io.py
@@ -4249,6 +4249,29 @@ def test_check_encoding_errors(self):
proc = assert_python_failure('-X', 'dev', '-c', code)
self.assertEqual(proc.rc, 10, proc)
+ def test_check_encoding_warning(self):
+ # PEP 597: Raise warning when encoding is not specified
+ # and sys.flags.warn_default_encoding is set.
+ mod = self.io.__name__
+ filename = __file__
+ code = textwrap.dedent(f'''\
+ import sys
+ from {mod} import open, TextIOWrapper
+ import pathlib
+
+ with open({filename!r}) as f: # line 5
+ pass
+
+ pathlib.Path({filename!r}).read_text() # line 8
+ ''')
+ proc = assert_python_ok('-X', 'warn_default_encoding', '-c', code)
+ warnings = proc.err.splitlines()
+ self.assertEqual(len(warnings), 2)
+ self.assertTrue(
+ warnings[0].startswith(b"<string>:5: EncodingWarning: "))
+ self.assertTrue(
+ warnings[1].startswith(b"<string>:8: EncodingWarning: "))
+
class CMiscIOTest(MiscIOTest):
io = io
diff --git a/Lib/test/test_pickle.py b/Lib/test/test_pickle.py
index 1f5cb10..23c7bd2 100644
--- a/Lib/test/test_pickle.py
+++ b/Lib/test/test_pickle.py
@@ -483,7 +483,8 @@ def test_exceptions(self):
if exc in (BlockingIOError,
ResourceWarning,
StopAsyncIteration,
- RecursionError):
+ RecursionError,
+ EncodingWarning):
continue
if exc is not OSError and issubclass(exc, OSError):
self.assertEqual(reverse_mapping('builtins', name),
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
index fca05e6..5b004c2 100644
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -591,7 +591,8 @@ def test_sys_flags(self):
"inspect", "interactive", "optimize",
"dont_write_bytecode", "no_user_site", "no_site",
"ignore_environment", "verbose", "bytes_warning", "quiet",
- "hash_randomization", "isolated", "dev_mode", "utf8_mode")
+ "hash_randomization", "isolated", "dev_mode", "utf8_mode",
+ "warn_default_encoding")
for attr in attrs:
self.assertTrue(hasattr(sys.flags, attr), attr)
attr_type = bool if attr == "dev_mode" else int