diff --git a/Doc/deprecations/pending-removal-in-3.14.rst b/Doc/deprecations/pending-removal-in-3.14.rst index 9aac10840a663f..171758156ab117 100644 --- a/Doc/deprecations/pending-removal-in-3.14.rst +++ b/Doc/deprecations/pending-removal-in-3.14.rst @@ -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 ` 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. diff --git a/Doc/deprecations/pending-removal-in-3.17.rst b/Doc/deprecations/pending-removal-in-3.17.rst index 370b98307e5228..4fd4bde24d42b3 100644 --- a/Doc/deprecations/pending-removal-in-3.17.rst +++ b/Doc/deprecations/pending-removal-in-3.17.rst @@ -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`.) diff --git a/Doc/library/collections.abc.rst b/Doc/library/collections.abc.rst index db9277ff09bdbf..9deaaee06a6bec 100644 --- a/Doc/library/collections.abc.rst +++ b/Doc/library/collections.abc.rst @@ -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 `. @@ -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 diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index b30b7fef9089f1..aea73724ef56d6 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -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` diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 022c76b084c08c..ef8752fea3bb6b 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -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 diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 7cfdc287b7fad7..8e0cb652a73b03 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -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`.) diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 5462c5dc425e2e..e8695f1db33281 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -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 ------ diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst index 59e8ecebb10444..6009dd8a71eea5 100644 --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -936,7 +936,7 @@ methods to match the corresponding methods of :class:`str`. collections.abc --------------- -The :meth:`Sequence.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`.) diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py index 51263d696a1777..28427077127890 100644 --- a/Lib/_collections_abc.py +++ b/Lib/_collections_abc.py @@ -49,7 +49,7 @@ def _f(): pass "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 @@ def count(self, value): 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. diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py index d9d61e5c2053e3..6c91d7aba2d53e 100644 --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -26,7 +26,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): @@ -1936,6 +1936,28 @@ def assert_index_same(seq1, seq2, index_args): 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) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 2aae92c5ea1021..889deddc56cd3f 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -7446,6 +7446,16 @@ def test_mutablesequence(self): 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 @@ def test_special_attrs(self): typing.AsyncIterable: 'AsyncIterable', typing.AsyncIterator: 'AsyncIterator', typing.Awaitable: 'Awaitable', + typing.ByteString: 'ByteString', typing.Callable: 'Callable', typing.ChainMap: 'ChainMap', typing.Collection: 'Collection', diff --git a/Lib/typing.py b/Lib/typing.py index d4a79ed5e35295..da5e0b56534045 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -65,6 +65,7 @@ # ABCs (from collections.abc). 'AbstractSet', # collections.abc.Set. + 'ByteString', 'Container', 'ContextManager', 'Hashable', @@ -1570,6 +1571,21 @@ def __ror__(self, left): 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 @@ 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, 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 index 00000000000000..0fa8f5c35c9ed3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-09-16-15-56-29.gh-issue-118803.aOPtmL.rst @@ -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.