[Python-checkins] bpo-47061: deprecate the `aifc` module (GH-32134)

brettcannon webhook-mailer at python.org
Tue Apr 5 15:06:00 EDT 2022


https://github.com/python/cpython/commit/c1d93b6411f975d67e43942f1a2745a22983c18c
commit: c1d93b6411f975d67e43942f1a2745a22983c18c
branch: main
author: Brett Cannon <brett at python.org>
committer: brettcannon <brett at python.org>
date: 2022-04-05T12:05:48-07:00
summary:

bpo-47061: deprecate the `aifc` module (GH-32134)

Co-authored-by: Christian Heimes <christian at python.org>

files:
A Misc/NEWS.d/next/Library/2022-03-26-13-14-43.bpo-47061.QLxbC6.rst
M Doc/whatsnew/3.11.rst
M Lib/aifc.py
M Lib/sndhdr.py
M Lib/test/support/warnings_helper.py
M Lib/test/test___all__.py
M Lib/test/test_aifc.py
M Lib/test/test_pyclbr.py
M Lib/test/test_warnings/__init__.py
M Lib/warnings.py

diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst
index 537fa49fd2f28..a2c57eb909ed1 100644
--- a/Doc/whatsnew/3.11.rst
+++ b/Doc/whatsnew/3.11.rst
@@ -608,6 +608,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 d50f258e1acf8..b5eab9215d6ef 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 96595c6974468..a63b6fd20220c 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 a024fbe5beaa0..28e96f88b2444 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 a1a3d899e4e03..1ec83cb0b1440 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 fb6da4136f4c5..ad8a7ee053cca 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 157c522b63bd0..329acf0c64295 100644
--- a/Lib/test/test_pyclbr.py
+++ b/Lib/test/test_pyclbr.py
@@ -216,12 +216,12 @@ 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('aifc', ignore=('_aifc_params',))  # set with = in module
         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('re._parser', ignore=('dump', 'groups', 'pos')) # from ._constants import *; property
+        cm('sre_parse', ignore=('dump', 'groups', 'pos')) # from sre_constants import *; property
         cm(
             'pdb',
             # pyclbr does not handle elegantly `typing` or properties
diff --git a/Lib/test/test_warnings/__init__.py b/Lib/test/test_warnings/__init__.py
index 4b1b4e193cb16..f7f931130714c 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 691ccddfa450a..887ca6ecd1a72 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 = [
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 0000000000000..17180861a88cd
--- /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.



More information about the Python-checkins mailing list