]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.14] Revert "gh-118803: Remove `ByteString` from `typing` and `collections.abc...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Wed, 17 Sep 2025 08:08:15 +0000 (10:08 +0200)
committerGitHub <noreply@github.com>
Wed, 17 Sep 2025 08:08:15 +0000 (09:08 +0100)
Revert "gh-118803: Remove `ByteString` from `typing` and `collections.abc` (GH-118804)" (GH-138990)
(cherry picked from commit 530ddd3e06a425b8bb9e8afb657dc7711a5aa2f9)

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
13 files changed:
Doc/deprecations/pending-removal-in-3.14.rst
Doc/deprecations/pending-removal-in-3.17.rst
Doc/library/collections.abc.rst
Doc/library/stdtypes.rst
Doc/library/typing.rst
Doc/whatsnew/3.12.rst
Doc/whatsnew/3.14.rst
Doc/whatsnew/3.5.rst
Lib/_collections_abc.py
Lib/test/test_collections.py
Lib/test/test_typing.py
Lib/typing.py
Misc/NEWS.d/next/Library/2025-09-16-15-56-29.gh-issue-118803.aOPtmL.rst [new file with mode: 0644]

index 9aac10840a663ff0771e8202e0828a20e5d00cf1..171758156ab1176e6add64ab696700eefa6186e5 100644 (file)
@@ -38,12 +38,6 @@ Pending removal in Python 3.14
     is no current event loop set and it decides to create one.
     (Contributed by Serhiy Storchaka and Guido van Rossum in :gh:`100160`.)
 
-* :mod:`collections.abc`: Deprecated :class:`!collections.abc.ByteString`.
-  Prefer :class:`!Sequence` or :class:`~collections.abc.Buffer`.
-  For use in typing, prefer a union, like ``bytes | bytearray``,
-  or :class:`collections.abc.Buffer`.
-  (Contributed by Shantanu Jain in :gh:`91896`.)
-
 * :mod:`email`: Deprecated the *isdst* parameter in :func:`email.utils.localtime`.
   (Contributed by Alan Williams in :gh:`72346`.)
 
@@ -96,9 +90,6 @@ Pending removal in Python 3.14
     if :ref:`named placeholders <sqlite3-placeholders>` are used and
     *parameters* is a sequence instead of a :class:`dict`.
 
-* :mod:`typing`: :class:`!typing.ByteString`, deprecated since Python 3.9,
-  now causes a :exc:`DeprecationWarning` to be emitted when it is used.
-
 * :mod:`urllib`:
   :class:`!urllib.parse.Quoter` is deprecated: it was not intended to be a
   public API.
index 370b98307e52280e3392ccae22385dbd3da9da6f..4fd4bde24d42b3f749bec48044b1c6c352a5a264 100644 (file)
@@ -8,3 +8,15 @@ Pending removal in Python 3.17
     but it has been retained for backward compatibility, with removal scheduled for Python
     3.17. Users should use documented introspection helpers like :func:`typing.get_origin`
     and :func:`typing.get_args` instead of relying on private implementation details.
+  - :class:`typing.ByteString`, deprecated since Python 3.9, is scheduled for removal in
+    Python 3.17. Prefer :class:`~collections.abc.Sequence` or
+    :class:`~collections.abc.Buffer`. For use in type annotations, prefer a union, like
+    ``bytes | bytearray``, or :class:`collections.abc.Buffer`.
+    (Contributed by Shantanu Jain in :gh:`91896`.)
+
+* :mod:`collections.abc`:
+
+  - :class:`collections.abc.ByteString` is scheduled for removal in Python 3.17. Prefer
+    :class:`~collections.abc.Sequence` or :class:`~collections.abc.Buffer`. For use in
+    type annotations, prefer a union, like ``bytes | bytearray``, or
+    :class:`collections.abc.Buffer`. (Contributed by Shantanu Jain in :gh:`91896`.)
index db9277ff09bdbfc1bbf201dbf984607a881828aa..9deaaee06a6becf5e360b1eb08ab7f8cb261ea94 100644 (file)
@@ -140,6 +140,9 @@ ABC                            Inherits from          Abstract Methods        Mi
                                                       ``__len__``,
                                                       ``insert``
 
+:class:`ByteString`            :class:`Sequence`      ``__getitem__``,        Inherited :class:`Sequence` methods
+                                                      ``__len__``
+
 :class:`Set`                   :class:`Collection`    ``__contains__``,       ``__le__``, ``__lt__``, ``__eq__``, ``__ne__``,
                                                       ``__iter__``,           ``__gt__``, ``__ge__``, ``__and__``, ``__or__``,
                                                       ``__len__``             ``__sub__``, ``__rsub__``, ``__xor__``, ``__rxor__``
@@ -260,6 +263,7 @@ Collections Abstract Base Classes -- Detailed Descriptions
 
 .. class:: Sequence
            MutableSequence
+           ByteString
 
    ABCs for read-only and mutable :term:`sequences <sequence>`.
 
@@ -285,6 +289,12 @@ Collections Abstract Base Classes -- Detailed Descriptions
          The :meth:`~sequence.index` method gained support for
          the *stop* and *start* arguments.
 
+   .. deprecated-removed:: 3.12 3.17
+      The :class:`ByteString` ABC has been deprecated.
+      For use in type annotations, prefer a union, like ``bytes | bytearray``, or
+      :class:`collections.abc.Buffer`.
+      For use as an ABC, prefer :class:`Sequence` or :class:`collections.abc.Buffer`.
+
 .. class:: Set
            MutableSet
 
index b30b7fef9089f1f9e258b1db26c566f3639d3ab6..aea73724ef56d69729c9cbdbca6328676aabddc0 100644 (file)
@@ -5544,6 +5544,7 @@ list is non-exhaustive.
 * :class:`collections.abc.MutableMapping`
 * :class:`collections.abc.Sequence`
 * :class:`collections.abc.MutableSequence`
+* :class:`collections.abc.ByteString`
 * :class:`collections.abc.MappingView`
 * :class:`collections.abc.KeysView`
 * :class:`collections.abc.ItemsView`
index 022c76b084c08c90c8e000b326b8cb8cc3b8779a..ef8752fea3bb6b2ea518c41c246a6af4524cf52b 100644 (file)
@@ -3788,6 +3788,14 @@ Aliases to container ABCs in :mod:`collections.abc`
       :class:`collections.abc.Set` now supports subscripting (``[]``).
       See :pep:`585` and :ref:`types-genericalias`.
 
+.. class:: ByteString(Sequence[int])
+
+   This type represents the types :class:`bytes`, :class:`bytearray`,
+   and :class:`memoryview` of byte sequences.
+
+   .. deprecated-removed:: 3.9 3.17
+      Prefer :class:`collections.abc.Buffer`, or a union like ``bytes | bytearray | memoryview``.
+
 .. class:: Collection(Sized, Iterable[T_co], Container[T_co])
 
    Deprecated alias to :class:`collections.abc.Collection`.
@@ -4081,6 +4089,10 @@ convenience. This is subject to change, and not all deprecations are listed.
      - 3.9
      - Undecided (see :ref:`deprecated-aliases` for more information)
      - :pep:`585`
+   * - :class:`typing.ByteString`
+     - 3.9
+     - 3.17
+     - :gh:`91896`
    * - :data:`typing.Text`
      - 3.11
      - Undecided
index 7cfdc287b7fad72db1240b2936650e9348fbf7b9..8e0cb652a73b03253da93a966f848d1bacbcceb8 100644 (file)
@@ -1191,9 +1191,9 @@ Deprecated
   replaced by :data:`calendar.JANUARY` and :data:`calendar.FEBRUARY`.
   (Contributed by Prince Roshan in :gh:`103636`.)
 
-* :mod:`collections.abc`: Deprecated :class:`!collections.abc.ByteString`.
+* :mod:`collections.abc`: Deprecated :class:`collections.abc.ByteString`.
   Prefer :class:`Sequence` or :class:`collections.abc.Buffer`.
-  For use in typing, prefer a union, like ``bytes | bytearray``, or :class:`collections.abc.Buffer`.
+  For use in type annotations, prefer a union, like ``bytes | bytearray``, or :class:`collections.abc.Buffer`.
   (Contributed by Shantanu Jain in :gh:`91896`.)
 
 * :mod:`datetime`: :class:`datetime.datetime`'s :meth:`~datetime.datetime.utcnow` and
@@ -1301,7 +1301,7 @@ Deprecated
     :class:`collections.abc.Hashable` and :class:`collections.abc.Sized` respectively, are
     deprecated. (:gh:`94309`.)
 
-  * :class:`!typing.ByteString`, deprecated since Python 3.9, now causes a
+  * :class:`typing.ByteString`, deprecated since Python 3.9, now causes a
     :exc:`DeprecationWarning` to be emitted when it is used.
     (Contributed by Alex Waygood in :gh:`91896`.)
 
index 5462c5dc425e2e1fe86bdd573b7beb00b345fe8a..e8695f1db332814df0939b527eb9e242f30d4d9a 100644 (file)
@@ -2560,15 +2560,6 @@ asyncio
          blocking_code()
          runner.run(operation_two())
 
-
-collections.abc
----------------
-
-* Remove :class:`!ByteString`, which has been deprecated since Python 3.12.
-  (Contributed by Nikita Sobolev in :gh:`118803`.)
-
-
-
 email
 -----
 
@@ -2647,13 +2638,6 @@ sqlite3
   (Contributed by Erlend E. Aasland in :gh:`118928` and :gh:`101693`.)
 
 
-typing
-------
-
-* Remove :class:`!ByteString`, which has been deprecated since Python 3.12.
-  (Contributed by Nikita Sobolev in :gh:`118803`.)
-
-
 urllib
 ------
 
index 59e8ecebb10444ef2911337f7317d3fc635a720a..6009dd8a71eea52c5cb4a21545333c0eccf132b4 100644 (file)
@@ -936,7 +936,7 @@ methods to match the corresponding methods of :class:`str`.
 collections.abc
 ---------------
 
-The :meth:`Sequence.index() <collections.abc.MutableSequence.index>` method now
+The :meth:`!Sequence.index` method now
 accepts *start* and *stop* arguments to match the corresponding methods
 of :class:`tuple`, :class:`list`, etc.
 (Contributed by Devin Jeanpierre in :issue:`23086`.)
index 51263d696a1777305b2ecaa9765117dafdc8d2db..2842707712789060329c81e8f57b9acb967d8428 100644 (file)
@@ -49,7 +49,7 @@ __all__ = ["Awaitable", "Coroutine",
            "Mapping", "MutableMapping",
            "MappingView", "KeysView", "ItemsView", "ValuesView",
            "Sequence", "MutableSequence",
-           "Buffer",
+           "ByteString", "Buffer",
            ]
 
 # This module has been renamed from collections.abc to _collections_abc to
@@ -1061,6 +1061,37 @@ Sequence.register(bytes)
 Sequence.register(range)
 Sequence.register(memoryview)
 
+class _DeprecateByteStringMeta(ABCMeta):
+    def __new__(cls, name, bases, namespace, **kwargs):
+        if name != "ByteString":
+            import warnings
+
+            warnings._deprecated(
+                "collections.abc.ByteString",
+                remove=(3, 17),
+            )
+        return super().__new__(cls, name, bases, namespace, **kwargs)
+
+    def __instancecheck__(cls, instance):
+        import warnings
+
+        warnings._deprecated(
+            "collections.abc.ByteString",
+            remove=(3, 17),
+        )
+        return super().__instancecheck__(instance)
+
+class ByteString(Sequence, metaclass=_DeprecateByteStringMeta):
+    """This unifies bytes and bytearray.
+
+    XXX Should add all their methods.
+    """
+
+    __slots__ = ()
+
+ByteString.register(bytes)
+ByteString.register(bytearray)
+
 
 class MutableSequence(Sequence):
     """All the operations on a read-write sequence.
index d9d61e5c2053e33645f6629dc00c9498d34d874e..6c91d7aba2d53e792c37a23661c3bee5a279e52d 100644 (file)
@@ -26,7 +26,7 @@ from collections.abc import Sized, Container, Callable, Collection
 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):
@@ -1936,6 +1936,28 @@ class TestCollectionABCs(ABCTestCase):
                         assert_index_same(
                             nativeseq, seqseq, (letter, start, stop))
 
+    def test_ByteString(self):
+        for sample in [bytes, bytearray]:
+            with self.assertWarns(DeprecationWarning):
+                self.assertIsInstance(sample(), ByteString)
+            self.assertTrue(issubclass(sample, ByteString))
+        for sample in [str, list, tuple]:
+            with self.assertWarns(DeprecationWarning):
+                self.assertNotIsInstance(sample(), ByteString)
+            self.assertFalse(issubclass(sample, ByteString))
+        with self.assertWarns(DeprecationWarning):
+            self.assertNotIsInstance(memoryview(b""), ByteString)
+        self.assertFalse(issubclass(memoryview, ByteString))
+        with self.assertWarns(DeprecationWarning):
+            self.validate_abstract_methods(ByteString, '__getitem__', '__len__')
+
+        with self.assertWarns(DeprecationWarning):
+            class X(ByteString): pass
+
+        with self.assertWarns(DeprecationWarning):
+            # No metaclass conflict
+            class Z(ByteString, Awaitable): pass
+
     def test_Buffer(self):
         for sample in [bytes, bytearray, memoryview]:
             self.assertIsInstance(sample(b"x"), Buffer)
index 2aae92c5ea10216baab08cca767495e318d3e0ba..889deddc56cd3f59117dbe24e093dbed440b46ac 100644 (file)
@@ -7446,6 +7446,16 @@ class CollectionsAbcTests(BaseTestCase):
         self.assertIsInstance([], typing.MutableSequence)
         self.assertNotIsInstance((), typing.MutableSequence)
 
+    def test_bytestring(self):
+        with self.assertWarns(DeprecationWarning):
+            self.assertIsInstance(b'', typing.ByteString)
+        with self.assertWarns(DeprecationWarning):
+            self.assertIsInstance(bytearray(b''), typing.ByteString)
+        with self.assertWarns(DeprecationWarning):
+            class Foo(typing.ByteString): ...
+        with self.assertWarns(DeprecationWarning):
+            class Bar(typing.ByteString, typing.Awaitable): ...
+
     def test_list(self):
         self.assertIsSubclass(list, typing.List)
 
@@ -10450,6 +10460,7 @@ class SpecialAttrsTests(BaseTestCase):
             typing.AsyncIterable: 'AsyncIterable',
             typing.AsyncIterator: 'AsyncIterator',
             typing.Awaitable: 'Awaitable',
+            typing.ByteString: 'ByteString',
             typing.Callable: 'Callable',
             typing.ChainMap: 'ChainMap',
             typing.Collection: 'Collection',
index d4a79ed5e352952203bea86446e75957befe21f2..da5e0b5653404500e19114eb9e87d5a241d35986 100644 (file)
@@ -65,6 +65,7 @@ __all__ = [
 
     # ABCs (from collections.abc).
     'AbstractSet',  # collections.abc.Set.
+    'ByteString',
     'Container',
     'ContextManager',
     'Hashable',
@@ -1570,6 +1571,21 @@ class _SpecialGenericAlias(_NotIterable, _BaseGenericAlias, _root=True):
         return Union[left, self]
 
 
+class _DeprecatedGenericAlias(_SpecialGenericAlias, _root=True):
+    def __init__(
+        self, origin, nparams, *, removal_version, inst=True, name=None
+    ):
+        super().__init__(origin, nparams, inst=inst, name=name)
+        self._removal_version = removal_version
+
+    def __instancecheck__(self, inst):
+        import warnings
+        warnings._deprecated(
+            f"{self.__module__}.{self._name}", remove=self._removal_version
+        )
+        return super().__instancecheck__(inst)
+
+
 class _CallableGenericAlias(_NotIterable, _GenericAlias, _root=True):
     def __repr__(self):
         assert self._name == 'Callable'
@@ -2755,6 +2771,9 @@ Mapping = _alias(collections.abc.Mapping, 2)
 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, 17)  # Not generic.
+)
 # Tuple accepts variable number of parameters.
 Tuple = _TupleType(tuple, -1, inst=False, name='Tuple')
 Tuple.__doc__ = \
diff --git a/Misc/NEWS.d/next/Library/2025-09-16-15-56-29.gh-issue-118803.aOPtmL.rst b/Misc/NEWS.d/next/Library/2025-09-16-15-56-29.gh-issue-118803.aOPtmL.rst
new file mode 100644 (file)
index 0000000..0fa8f5c
--- /dev/null
@@ -0,0 +1,3 @@
+Add back :class:`collections.abc.ByteString` and :class:`typing.ByteString`.
+Both had been removed in prior alpha, beta and release candidates for Python
+3.14, but their removal has now been postponed to Python 3.17.