From 8718b98ac76401c0aee1bee7b631f3b109fe95fa Mon Sep 17 00:00:00 2001
From: AlexWaygood <alex.waygood@gmail.com>
Date: Fri, 12 May 2023 15:51:19 +0100
Subject: [PATCH 1/2] Revert some very noisy DeprecationWarnings for
 `ByteString`

---
 Doc/library/collections.abc.rst |  5 +----
 Doc/whatsnew/3.12.rst           |  2 +-
 Lib/collections/abc.py          |  9 ---------
 Lib/test/libregrtest/refleak.py | 15 ++++++---------
 Lib/test/test_collections.py    | 10 +---------
 Lib/test/test_typing.py         | 28 ++++++----------------------
 Lib/typing.py                   | 27 +++------------------------
 7 files changed, 18 insertions(+), 78 deletions(-)

diff --git a/Doc/library/collections.abc.rst b/Doc/library/collections.abc.rst
index 158f4851634652..43a3286ba832cf 100644
--- a/Doc/library/collections.abc.rst
+++ b/Doc/library/collections.abc.rst
@@ -14,10 +14,7 @@
 
 .. testsetup:: *
 
-   import warnings
-   # Ignore warning when ByteString is imported
-   with warnings.catch_warnings(action='ignore', category=DeprecationWarning):
-       from collections.abc import *
+   from collections.abc import *
    import itertools
    __name__ = '<doctest>'
 
diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst
index 546c7147bb3b27..486d0d7051de74 100644
--- a/Doc/whatsnew/3.12.rst
+++ b/Doc/whatsnew/3.12.rst
@@ -832,7 +832,7 @@ Pending Removal in Python 3.14
   (Contributed by Shantanu Jain in :gh:`91896`.)
 
 * :class:`typing.ByteString`, deprecated since Python 3.9, now causes an
-  :exc:`DeprecationWarning` to be emitted when it is used or accessed.
+  :exc:`DeprecationWarning` to be emitted when it is used.
 
 * Creating immutable types (:data:`Py_TPFLAGS_IMMUTABLETYPE`) with mutable
   bases using the C API.
diff --git a/Lib/collections/abc.py b/Lib/collections/abc.py
index 60b1eb60fa6ae1..86ca8b8a8414b3 100644
--- a/Lib/collections/abc.py
+++ b/Lib/collections/abc.py
@@ -1,12 +1,3 @@
 from _collections_abc import *
 from _collections_abc import __all__
 from _collections_abc import _CallableGenericAlias
-
-_deprecated_ByteString = globals().pop("ByteString")
-
-def __getattr__(attr):
-    if attr == "ByteString":
-        import warnings
-        warnings._deprecated("collections.abc.ByteString", remove=(3, 14))
-        return _deprecated_ByteString
-    raise AttributeError(f"module 'collections.abc' has no attribute {attr!r}")
diff --git a/Lib/test/libregrtest/refleak.py b/Lib/test/libregrtest/refleak.py
index 776a9e9b587d32..cd11d385591f80 100644
--- a/Lib/test/libregrtest/refleak.py
+++ b/Lib/test/libregrtest/refleak.py
@@ -48,13 +48,11 @@ def dash_R(ns, test_name, test_func):
     else:
         zdc = zipimport._zip_directory_cache.copy()
     abcs = {}
-    # catch and ignore collections.abc.ByteString deprecation
-    with warnings.catch_warnings(action='ignore', category=DeprecationWarning):
-        for abc in [getattr(collections.abc, a) for a in collections.abc.__all__]:
-            if not isabstract(abc):
-                continue
-            for obj in abc.__subclasses__() + [abc]:
-                abcs[obj] = _get_dump(obj)[0]
+    for abc in [getattr(collections.abc, a) for a in collections.abc.__all__]:
+        if not isabstract(abc):
+            continue
+        for obj in abc.__subclasses__() + [abc]:
+            abcs[obj] = _get_dump(obj)[0]
 
     # bpo-31217: Integer pool to get a single integer object for the same
     # value. The pool is used to prevent false alarm when checking for memory
@@ -176,8 +174,7 @@ def dash_R_cleanup(fs, ps, pic, zdc, abcs):
 
     # Clear ABC registries, restoring previously saved ABC registries.
     # ignore deprecation warning for collections.abc.ByteString
-    with warnings.catch_warnings(action='ignore', category=DeprecationWarning):
-        abs_classes = [getattr(collections.abc, a) for a in collections.abc.__all__]
+    abs_classes = [getattr(collections.abc, a) for a in collections.abc.__all__]
     abs_classes = filter(isabstract, abs_classes)
     for abc in abs_classes:
         for obj in abc.__subclasses__() + [abc]:
diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py
index f0736b8081feac..bb8b352518ef3e 100644
--- a/Lib/test/test_collections.py
+++ b/Lib/test/test_collections.py
@@ -11,7 +11,6 @@
 import string
 import sys
 from test import support
-from test.support.import_helper import import_fresh_module
 import types
 import unittest
 
@@ -26,7 +25,7 @@
 from collections.abc import Set, MutableSet
 from collections.abc import Mapping, MutableMapping, KeysView, ItemsView, ValuesView
 from collections.abc import Sequence, MutableSequence
-from collections.abc import Buffer
+from collections.abc import ByteString, Buffer
 
 
 class TestUserObjects(unittest.TestCase):
@@ -1940,8 +1939,6 @@ def assert_index_same(seq1, seq2, index_args):
                             nativeseq, seqseq, (letter, start, stop))
 
     def test_ByteString(self):
-        with self.assertWarns(DeprecationWarning):
-            from collections.abc import ByteString
         for sample in [bytes, bytearray]:
             with self.assertWarns(DeprecationWarning):
                 self.assertIsInstance(sample(), ByteString)
@@ -1963,11 +1960,6 @@ class X(ByteString): pass
             # No metaclass conflict
             class Z(ByteString, Awaitable): pass
 
-    def test_ByteString_attribute_access(self):
-        collections_abc = import_fresh_module("collections.abc")
-        with self.assertWarns(DeprecationWarning):
-            collections_abc.ByteString
-
     def test_Buffer(self):
         for sample in [bytes, bytearray, memoryview]:
             self.assertIsInstance(sample(b"x"), Buffer)
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index 3422dc1ed3f5f8..e1c6a8a7f376eb 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -8,7 +8,6 @@
 import re
 import sys
 import warnings
-from test.support.import_helper import import_fresh_module
 from unittest import TestCase, main, skipUnless, skip
 from unittest.mock import patch
 from copy import copy, deepcopy
@@ -3909,14 +3908,7 @@ class MyChain(typing.ChainMap[str, T]): ...
         self.assertEqual(MyChain[int]().__orig_class__, MyChain[int])
 
     def test_all_repr_eq_any(self):
-        typing = import_fresh_module("typing")
-        with warnings.catch_warnings(record=True) as wlog:
-            warnings.filterwarnings('always', '', DeprecationWarning)
-            objs = [getattr(typing, el) for el in typing.__all__]
-        self.assertEqual(
-            [str(w.message) for w in wlog],
-            ["'typing.ByteString' is deprecated and slated for removal in Python 3.14"]
-        )
+        objs = (getattr(typing, el) for el in typing.__all__)
         for obj in objs:
             self.assertNotEqual(repr(obj), '')
             self.assertEqual(obj, obj)
@@ -6005,15 +5997,13 @@ def test_mutablesequence(self):
 
     def test_bytestring(self):
         with self.assertWarns(DeprecationWarning):
-            from typing import ByteString
+            self.assertIsInstance(b'', typing.ByteString)
         with self.assertWarns(DeprecationWarning):
-            self.assertIsInstance(b'', ByteString)
+            self.assertIsInstance(bytearray(b''), typing.ByteString)
         with self.assertWarns(DeprecationWarning):
-            self.assertIsInstance(bytearray(b''), ByteString)
+            class Foo(typing.ByteString): ...
         with self.assertWarns(DeprecationWarning):
-            class Foo(ByteString): ...
-        with self.assertWarns(DeprecationWarning):
-            class Bar(ByteString, typing.Awaitable): ...
+            class Bar(typing.ByteString, typing.Awaitable): ...
 
     def test_list(self):
         self.assertIsSubclass(list, typing.List)
@@ -8309,10 +8299,6 @@ def test_no_isinstance(self):
 class SpecialAttrsTests(BaseTestCase):
 
     def test_special_attrs(self):
-        with warnings.catch_warnings(
-            action='ignore', category=DeprecationWarning
-        ):
-            typing_ByteString = typing.ByteString
         cls_to_check = {
             # ABC classes
             typing.AbstractSet: 'AbstractSet',
@@ -8321,7 +8307,7 @@ def test_special_attrs(self):
             typing.AsyncIterable: 'AsyncIterable',
             typing.AsyncIterator: 'AsyncIterator',
             typing.Awaitable: 'Awaitable',
-            typing_ByteString: 'ByteString',
+            typing.ByteString: 'ByteString',
             typing.Callable: 'Callable',
             typing.ChainMap: 'ChainMap',
             typing.Collection: 'Collection',
@@ -8646,8 +8632,6 @@ def test_all_exported_names(self):
                 getattr(v, '__module__', None) == typing.__name__
             )
         }
-        # Deprecated; added dynamically via module __getattr__
-        computed_all.add("ByteString")
         self.assertSetEqual(computed_all, actual_all)
 
 
diff --git a/Lib/typing.py b/Lib/typing.py
index 513d4d96dd6e1d..61aed0980ac2eb 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -2772,6 +2772,9 @@ class Other(Leaf):  # Error reported by type checker
 MutableMapping = _alias(collections.abc.MutableMapping, 2)
 Sequence = _alias(collections.abc.Sequence, 1)
 MutableSequence = _alias(collections.abc.MutableSequence, 1)
+ByteString = _DeprecatedGenericAlias(
+    collections.abc.ByteString, 0, removal_version=(3, 14)  # Not generic.
+)
 # Tuple accepts variable number of parameters.
 Tuple = _TupleType(tuple, -1, inst=False, name='Tuple')
 Tuple.__doc__ = \
@@ -3571,27 +3574,3 @@ def method(self) -> None:
         # read-only property, TypeError if it's a builtin class.
         pass
     return method
-
-
-def __getattr__(attr):
-    if attr == "ByteString":
-        import warnings
-        warnings._deprecated("typing.ByteString", remove=(3, 14))
-        with warnings.catch_warnings(
-            action="ignore", category=DeprecationWarning
-        ):
-            # Not generic
-            ByteString = globals()["ByteString"] = _DeprecatedGenericAlias(
-                collections.abc.ByteString, 0, removal_version=(3, 14)
-            )
-        return ByteString
-    raise AttributeError(f"module 'typing' has no attribute {attr!r}")
-
-
-def _remove_cached_ByteString_from_globals():
-    try:
-        del globals()["ByteString"]
-    except KeyError:
-        pass
-
-_cleanups.append(_remove_cached_ByteString_from_globals)

From 1afc689bdbbee3a845583a81247629df964fc30a Mon Sep 17 00:00:00 2001
From: Alex Waygood <Alex.Waygood@Gmail.com>
Date: Fri, 12 May 2023 17:46:20 +0100
Subject: [PATCH 2/2] Update Doc/whatsnew/3.12.rst

---
 Doc/whatsnew/3.12.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst
index 486d0d7051de74..dc1178811e75cc 100644
--- a/Doc/whatsnew/3.12.rst
+++ b/Doc/whatsnew/3.12.rst
@@ -831,7 +831,7 @@ Pending Removal in Python 3.14
   For use in typing, prefer a union, like ``bytes | bytearray``, or :class:`collections.abc.Buffer`.
   (Contributed by Shantanu Jain in :gh:`91896`.)
 
-* :class:`typing.ByteString`, deprecated since Python 3.9, now causes an
+* :class:`typing.ByteString`, deprecated since Python 3.9, now causes a
   :exc:`DeprecationWarning` to be emitted when it is used.
 
 * Creating immutable types (:data:`Py_TPFLAGS_IMMUTABLETYPE`) with mutable