From 5942b70aade45ba6644cc0e6bba9d479ed6646a9 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Sat, 26 Mar 2022 13:13:53 -0700 Subject: [PATCH 1/3] bpo-47061: deprecate the `aifc` module Also introduce `warning._deprecated()` and `test.support.warnings_helper.import_deprecated()`. --- Doc/whatsnew/3.11.rst | 8 ++++++ Lib/aifc.py | 4 +++ Lib/sndhdr.py | 5 +++- Lib/test/support/warnings_helper.py | 8 ++++++ Lib/test/test___all__.py | 1 + Lib/test/test_aifc.py | 7 +++-- Lib/test/test_pyclbr.py | 3 +-- Lib/test/test_warnings/__init__.py | 40 +++++++++++++++++++++++++++++ Lib/warnings.py | 21 +++++++++++++++ 9 files changed, 92 insertions(+), 5 deletions(-) diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 2c09d3583ea151..ed88f37f236f93 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -573,6 +573,14 @@ Deprecated (:pep:`594`). (Contributed by Hugo van Kemenade in :issue:`47022`.) +* :pep:`594` led to the deprecations of the following modules which are + slated for removal in Python 3.13: + + * :mod:`aifc` + + (Contributed by Brett Cannon in :issue:`47061`.) + + Removed ======= diff --git a/Lib/aifc.py b/Lib/aifc.py index d50f258e1acf8d..b5eab9215d6efa 100644 --- a/Lib/aifc.py +++ b/Lib/aifc.py @@ -140,6 +140,10 @@ __all__ = ["Error", "open"] + +warnings._deprecated(__name__, remove=(3, 13)) + + class Error(Exception): pass diff --git a/Lib/sndhdr.py b/Lib/sndhdr.py index 96595c69744682..a63b6fd20220c0 100644 --- a/Lib/sndhdr.py +++ b/Lib/sndhdr.py @@ -33,6 +33,7 @@ __all__ = ['what', 'whathdr'] from collections import namedtuple +import warnings SndHeaders = namedtuple('SndHeaders', 'filetype framerate nchannels nframes sampwidth') @@ -73,7 +74,9 @@ def whathdr(filename): tests = [] def test_aifc(h, f): - import aifc + with warnings.catch_warnings(): + warnings.simplefilter('ignore', category=DeprecationWarning) + import aifc if not h.startswith(b'FORM'): return None if h[8:12] == b'AIFC': diff --git a/Lib/test/support/warnings_helper.py b/Lib/test/support/warnings_helper.py index a024fbe5beaa02..28e96f88b24441 100644 --- a/Lib/test/support/warnings_helper.py +++ b/Lib/test/support/warnings_helper.py @@ -1,10 +1,18 @@ import contextlib import functools +import importlib import re import sys import warnings +def import_deprecated(name): + """Import *name* while suppressing DeprecationWarning.""" + with warnings.catch_warnings(): + warnings.simplefilter('ignore', category=DeprecationWarning) + return importlib.import_module(name) + + def check_syntax_warning(testcase, statement, errtext='', *, lineno=1, offset=None): # Test also that a warning is emitted only once. diff --git a/Lib/test/test___all__.py b/Lib/test/test___all__.py index a1a3d899e4e03c..1ec83cb0b14401 100644 --- a/Lib/test/test___all__.py +++ b/Lib/test/test___all__.py @@ -41,6 +41,7 @@ def tearDown(self): def check_all(self, modname): names = {} with warnings_helper.check_warnings( + (f".*{modname}", DeprecationWarning), (".* (module|package)", DeprecationWarning), (".* (module|package)", PendingDeprecationWarning), ("", ResourceWarning), diff --git a/Lib/test/test_aifc.py b/Lib/test/test_aifc.py index fb6da4136f4c58..ad8a7ee053cca9 100644 --- a/Lib/test/test_aifc.py +++ b/Lib/test/test_aifc.py @@ -1,6 +1,6 @@ from test.support import findfile from test.support.os_helper import TESTFN, unlink -from test.support.warnings_helper import check_no_resource_warning +from test.support.warnings_helper import check_no_resource_warning, import_deprecated import unittest from unittest import mock from test import audiotests @@ -8,7 +8,10 @@ import io import sys import struct -import aifc + + +aifc = import_deprecated("aifc") + class AifcTest(audiotests.AudioWriteTests, audiotests.AudioTestsWithSourceFile): diff --git a/Lib/test/test_pyclbr.py b/Lib/test/test_pyclbr.py index 4bb9cfcad9a76a..ad7b31aef1ddd1 100644 --- a/Lib/test/test_pyclbr.py +++ b/Lib/test/test_pyclbr.py @@ -216,11 +216,10 @@ def compare(parent1, children1, parent2, children2): def test_others(self): cm = self.checkModule - # These were once about the 10 longest modules + # These were once some of the longest modules. cm('random', ignore=('Random',)) # from _random import Random as CoreGenerator cm('cgi', ignore=('log',)) # set with = in module cm('pickle', ignore=('partial', 'PickleBuffer')) - cm('aifc', ignore=('_aifc_params',)) # set with = in module cm('sre_parse', ignore=('dump', 'groups', 'pos')) # from sre_constants import *; property cm( 'pdb', diff --git a/Lib/test/test_warnings/__init__.py b/Lib/test/test_warnings/__init__.py index 4b1b4e193cb165..d419a23452481f 100644 --- a/Lib/test/test_warnings/__init__.py +++ b/Lib/test/test_warnings/__init__.py @@ -1219,7 +1219,47 @@ class PyEnvironmentVariableTests(EnvironmentVariableTests, unittest.TestCase): module = py_warnings +class _DeprecatedTest(BaseTest, unittest.TestCase): + + """Test _deprecated().""" + + module = original_warnings + + def test_warning(self): + version = (3, 11, 0, "final", 0) + test = [(4, 12), (4, 11), (4, 0), (3, 12)] + for remove in test: + msg = rf".*test_warnings.*{remove[0]}\.{remove[1]}" + filter = msg, DeprecationWarning + with self.subTest(remove=remove): + with warnings_helper.check_warnings(filter, quiet=False): + self.module._deprecated("test_warnings", remove=remove, + _version=version) + + version = (3, 11, 0, "alpha", 0) + msg = r".*test_warnings.*3\.11" + with warnings_helper.check_warnings((msg, DeprecationWarning), quiet=False): + self.module._deprecated("test_warnings", remove=(3, 11), + _version=version) + + def test_RuntimeError(self): + version = (3, 11, 0, "final", 0) + test = [(2, 0), (2, 12), (3, 10)] + for remove in test: + with self.subTest(remove=remove): + with self.assertRaises(RuntimeError): + self.module._deprecated("test_warnings", remove=remove, + _version=version) + for level in ["beta", "candidate", "final"]: + version = (3, 11, 0, level, 0) + with self.subTest(releaselevel=level): + with self.assertRaises(RuntimeError): + self.module._deprecated("test_warnings", remove=(3, 11), + _version=version) + + class BootstrapTest(unittest.TestCase): + def test_issue_8766(self): # "import encodings" emits a warning whereas the warnings is not loaded # or not completely loaded (warnings imports indirectly encodings by diff --git a/Lib/warnings.py b/Lib/warnings.py index 691ccddfa450ad..887ca6ecd1a72b 100644 --- a/Lib/warnings.py +++ b/Lib/warnings.py @@ -483,6 +483,27 @@ def __exit__(self, *exc_info): self._module._showwarnmsg_impl = self._showwarnmsg_impl +_DEPRECATED_MSG = "{name!r} is deprecated and slated for removal in Python {remove}" + +def _deprecated(name, message=_DEPRECATED_MSG, *, remove, _version=sys.version_info): + """Warn that *name* is deprecated or should be removed. + + RuntimeError is raised if *remove* specifies a major/minor tuple older than + the current Python version or the same version but past the alpha. + + The *message* argument is formatted with *name* and *remove* as a Python + version (e.g. "3.11"). + + """ + remove_formatted = f"{remove[0]}.{remove[1]}" + if (_version[:2] > remove) or (_version[:2] == remove and _version[3] != "alpha"): + msg = f"{name!r} was slated for removal after Python {remove_formatted} alpha" + raise RuntimeError(msg) + else: + msg = message.format(name=name, remove=remove_formatted) + warn(msg, DeprecationWarning, stacklevel=3) + + # Private utility function called by _PyErr_WarnUnawaitedCoroutine def _warn_unawaited_coroutine(coro): msg_lines = [ From 0575c776c9a7836efff2f3d239c193d6b9581b4c Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Sat, 26 Mar 2022 13:15:05 -0700 Subject: [PATCH 2/3] Add NEWS entry --- .../NEWS.d/next/Library/2022-03-26-13-14-43.bpo-47061.QLxbC6.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2022-03-26-13-14-43.bpo-47061.QLxbC6.rst diff --git a/Misc/NEWS.d/next/Library/2022-03-26-13-14-43.bpo-47061.QLxbC6.rst b/Misc/NEWS.d/next/Library/2022-03-26-13-14-43.bpo-47061.QLxbC6.rst new file mode 100644 index 00000000000000..17180861a88cd6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-03-26-13-14-43.bpo-47061.QLxbC6.rst @@ -0,0 +1 @@ +Deprecate the aifc module. From 20a160c85cf9254a38481a7b3f6f0056f1419bb5 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Sun, 27 Mar 2022 14:49:38 -0700 Subject: [PATCH 3/3] Fix whitespace --- Lib/test/test_warnings/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_warnings/__init__.py b/Lib/test/test_warnings/__init__.py index d419a23452481f..f7f931130714c0 100644 --- a/Lib/test/test_warnings/__init__.py +++ b/Lib/test/test_warnings/__init__.py @@ -1239,8 +1239,8 @@ def test_warning(self): version = (3, 11, 0, "alpha", 0) msg = r".*test_warnings.*3\.11" with warnings_helper.check_warnings((msg, DeprecationWarning), quiet=False): - self.module._deprecated("test_warnings", remove=(3, 11), - _version=version) + self.module._deprecated("test_warnings", remove=(3, 11), + _version=version) def test_RuntimeError(self): version = (3, 11, 0, "final", 0)