Skip to content

Commit b508dd0

Browse files
committed
gh-118803: Make ByteString deprecations louder; remove ByteString from typing.__all__ and collections.abc.__all__
1 parent 571210b commit b508dd0

File tree

7 files changed

+124
-27
lines changed

7 files changed

+124
-27
lines changed

Doc/whatsnew/3.15.rst

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,25 @@ New modules
289289
Improved modules
290290
================
291291

292+
collections.abc
293+
---------------
294+
295+
* :class:`collections.abc.ByteString` has been removed from
296+
``collections.abc.__all__``. :class:`!collections.abc.ByteString` has been
297+
deprecated since Python 3.12, and is scheduled for removal in Python 3.17.
298+
299+
* The following statements now cause ``DeprecationWarning``\ s to be emitted at
300+
runtime:
301+
302+
* ``from collections.abc import ByteString``
303+
* ``import collections.abc; collections.abc.ByteString``.
304+
305+
``DeprecationWarning``\ s were already emitted if
306+
:class:`collections.abc.ByteString` was subclassed or used as the second
307+
argument to :func:`isinstance` or :func:`issubclass`, but warnings were not
308+
previously emitted if it was merely imported or accessed from the
309+
:mod:`!collections.abc` module.
310+
292311
dbm
293312
---
294313

@@ -671,6 +690,21 @@ typing
671690
as it was incorrectly infered in runtime before.
672691
(Contributed by Nikita Sobolev in :gh:`137191`.)
673692

693+
* :class:`typing.ByteString` has been removed from ``typing.__all__``.
694+
:class:`!typing.ByteString` has been deprecated since Python 3.9, and is
695+
scheduled for removal in Python 3.17.
696+
697+
* The following statements now cause ``DeprecationWarning``\ s to be emitted at
698+
runtime:
699+
700+
* ``from typing import ByteString``
701+
* ``import typing; typing.ByteString``.
702+
703+
``DeprecationWarning``\ s were already emitted if :class:`typing.ByteString`
704+
was subclassed or used as the second argument to :func:`isinstance` or
705+
:func:`issubclass`, but warnings were not previously emitted if it was merely
706+
imported or accessed from the :mod:`!typing` module.
707+
674708

675709
unicodedata
676710
-----------

Lib/_collections_abc.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def _f(): pass
4949
"Mapping", "MutableMapping",
5050
"MappingView", "KeysView", "ItemsView", "ValuesView",
5151
"Sequence", "MutableSequence",
52-
"ByteString", "Buffer",
52+
"Buffer",
5353
]
5454

5555
# This module has been renamed from collections.abc to _collections_abc to
@@ -1161,3 +1161,12 @@ def __iadd__(self, values):
11611161

11621162
MutableSequence.register(list)
11631163
MutableSequence.register(bytearray)
1164+
1165+
_deprecated_ByteString = globals().pop("ByteString")
1166+
1167+
def __getattr__(attr):
1168+
if attr == "ByteString":
1169+
import warnings
1170+
warnings._deprecated("collections.abc.ByteString", remove=(3, 17))
1171+
return _deprecated_ByteString
1172+
raise AttributeError(f"module 'collections.abc' has no attribute {attr!r}")

Lib/test/libregrtest/refleak.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,12 @@ def runtest_refleak(test_name, test_func,
9393
for obj in abc.__subclasses__() + [abc]:
9494
abcs[obj] = _get_dump(obj)[0]
9595

96+
# `ByteString` is not included in `collections.abc.__all__`
97+
with warnings.catch_warnings(action='ignore', category=DeprecationWarning):
98+
ByteString = collections.abc.ByteString
99+
for obj in ByteString.__subclasses__() + [ByteString]:
100+
abcs[obj] = _get_dump(obj)[0]
101+
96102
# bpo-31217: Integer pool to get a single integer object for the same
97103
# value. The pool is used to prevent false alarm when checking for memory
98104
# block leaks. Fill the pool with values in -1000..1000 which are the most
@@ -254,6 +260,8 @@ def dash_R_cleanup(fs, ps, pic, zdc, abcs, linecache_data):
254260

255261
# Clear ABC registries, restoring previously saved ABC registries.
256262
abs_classes = [getattr(collections.abc, a) for a in collections.abc.__all__]
263+
with warnings.catch_warnings(action='ignore', category=DeprecationWarning):
264+
abs_classes.append(collections.abc.ByteString)
257265
abs_classes = filter(isabstract, abs_classes)
258266
for abc in abs_classes:
259267
for obj in abc.__subclasses__() + [abc]:

Lib/test/test_collections.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import string
1313
import sys
1414
from test import support
15+
from test.support.import_helper import import_fresh_module
1516
import types
1617
import unittest
1718

@@ -26,7 +27,7 @@
2627
from collections.abc import Set, MutableSet
2728
from collections.abc import Mapping, MutableMapping, KeysView, ItemsView, ValuesView
2829
from collections.abc import Sequence, MutableSequence
29-
from collections.abc import ByteString, Buffer
30+
from collections.abc import Buffer
3031

3132

3233
class TestUserObjects(unittest.TestCase):
@@ -1935,6 +1936,8 @@ def assert_index_same(seq1, seq2, index_args):
19351936
nativeseq, seqseq, (letter, start, stop))
19361937

19371938
def test_ByteString(self):
1939+
with self.assertWarns(DeprecationWarning):
1940+
from collections.abc import ByteString
19381941
for sample in [bytes, bytearray]:
19391942
with self.assertWarns(DeprecationWarning):
19401943
self.assertIsInstance(sample(), ByteString)
@@ -1956,6 +1959,14 @@ class X(ByteString): pass
19561959
# No metaclass conflict
19571960
class Z(ByteString, Awaitable): pass
19581961

1962+
def test_ByteString_attribute_access(self):
1963+
collections_abc = import_fresh_module(
1964+
"collections.abc",
1965+
fresh=("collections", "_collections_abc")
1966+
)
1967+
with self.assertWarns(DeprecationWarning):
1968+
collections_abc.ByteString
1969+
19591970
def test_Buffer(self):
19601971
for sample in [bytes, bytearray, memoryview]:
19611972
self.assertIsInstance(sample(b"x"), Buffer)

Lib/test/test_typing.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import pickle
1414
import re
1515
import sys
16+
import warnings
1617
from unittest import TestCase, main, skip
1718
from unittest.mock import patch
1819
from copy import copy, deepcopy
@@ -7500,14 +7501,19 @@ def test_mutablesequence(self):
75007501
self.assertNotIsInstance((), typing.MutableSequence)
75017502

75027503
def test_bytestring(self):
7504+
previous_typing_module = sys.modules.pop("typing", None)
7505+
self.addCleanup(sys.modules.__setitem__, "typing", previous_typing_module)
7506+
7507+
with self.assertWarns(DeprecationWarning):
7508+
from typing import ByteString
75037509
with self.assertWarns(DeprecationWarning):
7504-
self.assertIsInstance(b'', typing.ByteString)
7510+
self.assertIsInstance(b'', ByteString)
75057511
with self.assertWarns(DeprecationWarning):
7506-
self.assertIsInstance(bytearray(b''), typing.ByteString)
7512+
self.assertIsInstance(bytearray(b''), ByteString)
75077513
with self.assertWarns(DeprecationWarning):
7508-
class Foo(typing.ByteString): ...
7514+
class Foo(ByteString): ...
75097515
with self.assertWarns(DeprecationWarning):
7510-
class Bar(typing.ByteString, typing.Awaitable): ...
7516+
class Bar(ByteString, typing.Awaitable): ...
75117517

75127518
def test_list(self):
75137519
self.assertIsSubclass(list, typing.List)
@@ -10455,6 +10461,10 @@ def test_no_isinstance(self):
1045510461
class SpecialAttrsTests(BaseTestCase):
1045610462

1045710463
def test_special_attrs(self):
10464+
with warnings.catch_warnings(
10465+
action='ignore', category=DeprecationWarning
10466+
):
10467+
typing_ByteString = typing.ByteString
1045810468
cls_to_check = {
1045910469
# ABC classes
1046010470
typing.AbstractSet: 'AbstractSet',
@@ -10463,7 +10473,7 @@ def test_special_attrs(self):
1046310473
typing.AsyncIterable: 'AsyncIterable',
1046410474
typing.AsyncIterator: 'AsyncIterator',
1046510475
typing.Awaitable: 'Awaitable',
10466-
typing.ByteString: 'ByteString',
10476+
typing_ByteString: 'ByteString',
1046710477
typing.Callable: 'Callable',
1046810478
typing.ChainMap: 'ChainMap',
1046910479
typing.Collection: 'Collection',
@@ -10816,7 +10826,8 @@ def test_all_exported_names(self):
1081610826
# there's a few types and metaclasses that aren't exported
1081710827
not k.endswith(('Meta', '_contra', '_co')) and
1081810828
not k.upper() == k and
10819-
# but export all things that have __module__ == 'typing'
10829+
k not in {"ByteString"} and
10830+
# but export all other things that have __module__ == 'typing'
1082010831
getattr(v, '__module__', None) == typing.__name__
1082110832
)
1082210833
}

Lib/typing.py

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@
6565

6666
# ABCs (from collections.abc).
6767
'AbstractSet', # collections.abc.Set.
68-
'ByteString',
6968
'Container',
7069
'ContextManager',
7170
'Hashable',
@@ -1603,21 +1602,6 @@ def __ror__(self, left):
16031602
return Union[left, self]
16041603

16051604

1606-
class _DeprecatedGenericAlias(_SpecialGenericAlias, _root=True):
1607-
def __init__(
1608-
self, origin, nparams, *, removal_version, inst=True, name=None
1609-
):
1610-
super().__init__(origin, nparams, inst=inst, name=name)
1611-
self._removal_version = removal_version
1612-
1613-
def __instancecheck__(self, inst):
1614-
import warnings
1615-
warnings._deprecated(
1616-
f"{self.__module__}.{self._name}", remove=self._removal_version
1617-
)
1618-
return super().__instancecheck__(inst)
1619-
1620-
16211605
class _CallableGenericAlias(_NotIterable, _GenericAlias, _root=True):
16221606
def __repr__(self):
16231607
assert self._name == 'Callable'
@@ -2805,9 +2789,6 @@ class Other(Leaf): # Error reported by type checker
28052789
MutableMapping = _alias(collections.abc.MutableMapping, 2)
28062790
Sequence = _alias(collections.abc.Sequence, 1)
28072791
MutableSequence = _alias(collections.abc.MutableSequence, 1)
2808-
ByteString = _DeprecatedGenericAlias(
2809-
collections.abc.ByteString, 0, removal_version=(3, 17) # Not generic.
2810-
)
28112792
# Tuple accepts variable number of parameters.
28122793
Tuple = _TupleType(tuple, -1, inst=False, name='Tuple')
28132794
Tuple.__doc__ = \
@@ -3799,6 +3780,34 @@ def __getattr__(attr):
37993780
)
38003781
warnings.warn(depr_message, category=DeprecationWarning, stacklevel=2)
38013782
obj = _collect_type_parameters
3783+
elif attr == "ByteString":
3784+
import warnings
3785+
3786+
warnings._deprecated("typing.ByteString", remove=(3, 17))
3787+
3788+
class _DeprecatedGenericAlias(_SpecialGenericAlias, _root=True):
3789+
def __init__(
3790+
self, origin, nparams, *, removal_version, inst=True, name=None
3791+
):
3792+
super().__init__(origin, nparams, inst=inst, name=name)
3793+
self._removal_version = removal_version
3794+
3795+
def __instancecheck__(self, inst):
3796+
import warnings
3797+
warnings._deprecated(
3798+
f"{self.__module__}.{self._name}", remove=self._removal_version
3799+
)
3800+
return super().__instancecheck__(inst)
3801+
3802+
with warnings.catch_warnings(
3803+
action="ignore", category=DeprecationWarning
3804+
):
3805+
# Not generic
3806+
ByteString = globals()["ByteString"] = _DeprecatedGenericAlias(
3807+
collections.abc.ByteString, 0, removal_version=(3, 17)
3808+
)
3809+
3810+
return ByteString
38023811
else:
38033812
raise AttributeError(f"module {__name__!r} has no attribute {attr!r}")
38043813
globals()[attr] = obj
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
:class:`collections.abc.ByteString` has been removed from
2+
``collections.abc.__all__``, and :class:`typing.ByteString` has been removed
3+
from ``typing.__all__``. The former has been deprecated since Python 3.12,
4+
and the latter has been deprecated since Python 3.9. Both classes are
5+
scheduled for removal in Python 3.17.
6+
7+
Additionally, the following statements now cause ``DeprecationWarning``\ s to
8+
be emitted at runtime: ``from collections.abc import ByteString``, ``from
9+
typing import ByteString``, ``import collections.abc;
10+
collections.abc.ByteString`` and ``import typing; typing.ByteString``. Both
11+
classes already caused ``DeprecationWarning``\ s to be emitted if they were
12+
subclassed or used as the second argument to ``isinstance()`` or
13+
``issubclass()``, but they did not previously lead to
14+
``DeprecationWarning``\ s if they were merely imported or accessed from their
15+
respective modules.

0 commit comments

Comments
 (0)