gh-118803: Make ByteString deprecations louder; remove ByteString from typing.__all__ and collections.abc.__all__ (#139127)
This commit is contained in:
@@ -289,6 +289,25 @@ New modules
|
||||
Improved modules
|
||||
================
|
||||
|
||||
collections.abc
|
||||
---------------
|
||||
|
||||
* :class:`collections.abc.ByteString` has been removed from
|
||||
``collections.abc.__all__``. :class:`!collections.abc.ByteString` has been
|
||||
deprecated since Python 3.12, and is scheduled for removal in Python 3.17.
|
||||
|
||||
* The following statements now cause ``DeprecationWarning``\ s to be emitted at
|
||||
runtime:
|
||||
|
||||
* ``from collections.abc import ByteString``
|
||||
* ``import collections.abc; collections.abc.ByteString``.
|
||||
|
||||
``DeprecationWarning``\ s were already emitted if
|
||||
:class:`collections.abc.ByteString` was subclassed or used as the second
|
||||
argument to :func:`isinstance` or :func:`issubclass`, but warnings were not
|
||||
previously emitted if it was merely imported or accessed from the
|
||||
:mod:`!collections.abc` module.
|
||||
|
||||
dbm
|
||||
---
|
||||
|
||||
@@ -671,6 +690,21 @@ typing
|
||||
as it was incorrectly infered in runtime before.
|
||||
(Contributed by Nikita Sobolev in :gh:`137191`.)
|
||||
|
||||
* :class:`typing.ByteString` has been removed from ``typing.__all__``.
|
||||
:class:`!typing.ByteString` has been deprecated since Python 3.9, and is
|
||||
scheduled for removal in Python 3.17.
|
||||
|
||||
* The following statements now cause ``DeprecationWarning``\ s to be emitted at
|
||||
runtime:
|
||||
|
||||
* ``from typing import ByteString``
|
||||
* ``import typing; typing.ByteString``.
|
||||
|
||||
``DeprecationWarning``\ s were already emitted if :class:`typing.ByteString`
|
||||
was subclassed or used as the second argument to :func:`isinstance` or
|
||||
:func:`issubclass`, but warnings were not previously emitted if it was merely
|
||||
imported or accessed from the :mod:`!typing` module.
|
||||
|
||||
|
||||
unicodedata
|
||||
-----------
|
||||
|
||||
@@ -49,7 +49,7 @@ __all__ = ["Awaitable", "Coroutine",
|
||||
"Mapping", "MutableMapping",
|
||||
"MappingView", "KeysView", "ItemsView", "ValuesView",
|
||||
"Sequence", "MutableSequence",
|
||||
"ByteString", "Buffer",
|
||||
"Buffer",
|
||||
]
|
||||
|
||||
# This module has been renamed from collections.abc to _collections_abc to
|
||||
@@ -1165,3 +1165,13 @@ class MutableSequence(Sequence):
|
||||
|
||||
MutableSequence.register(list)
|
||||
MutableSequence.register(bytearray)
|
||||
|
||||
_deprecated_ByteString = globals().pop("ByteString")
|
||||
|
||||
def __getattr__(attr):
|
||||
if attr == "ByteString":
|
||||
import warnings
|
||||
warnings._deprecated("collections.abc.ByteString", remove=(3, 17))
|
||||
globals()["ByteString"] = _deprecated_ByteString
|
||||
return _deprecated_ByteString
|
||||
raise AttributeError(f"module 'collections.abc' has no attribute {attr!r}")
|
||||
|
||||
@@ -93,6 +93,13 @@ def runtest_refleak(test_name, test_func,
|
||||
for obj in abc.__subclasses__() + [abc]:
|
||||
abcs[obj] = _get_dump(obj)[0]
|
||||
|
||||
# `ByteString` is not included in `collections.abc.__all__`
|
||||
with warnings.catch_warnings(action='ignore', category=DeprecationWarning):
|
||||
ByteString = collections.abc.ByteString
|
||||
# Mypy doesn't even think `ByteString` is a class, hence the `type: ignore`
|
||||
for obj in ByteString.__subclasses__() + [ByteString]: # type: ignore[attr-defined]
|
||||
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
|
||||
# block leaks. Fill the pool with values in -1000..1000 which are the most
|
||||
@@ -254,6 +261,8 @@ def dash_R_cleanup(fs, ps, pic, zdc, abcs, linecache_data):
|
||||
|
||||
# Clear ABC registries, restoring previously saved ABC registries.
|
||||
abs_classes = [getattr(collections.abc, a) for a in collections.abc.__all__]
|
||||
with warnings.catch_warnings(action='ignore', category=DeprecationWarning):
|
||||
abs_classes.append(collections.abc.ByteString)
|
||||
abs_classes = filter(isabstract, abs_classes)
|
||||
for abc in abs_classes:
|
||||
for obj in abc.__subclasses__() + [abc]:
|
||||
|
||||
@@ -12,6 +12,7 @@ from itertools import product, chain, combinations
|
||||
import string
|
||||
import sys
|
||||
from test import support
|
||||
from test.support.import_helper import import_fresh_module
|
||||
import types
|
||||
import unittest
|
||||
|
||||
@@ -26,7 +27,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 ByteString, Buffer
|
||||
from collections.abc import Buffer
|
||||
|
||||
|
||||
class TestUserObjects(unittest.TestCase):
|
||||
@@ -1935,6 +1936,14 @@ class TestCollectionABCs(ABCTestCase):
|
||||
nativeseq, seqseq, (letter, start, stop))
|
||||
|
||||
def test_ByteString(self):
|
||||
previous_sys_modules = sys.modules.copy()
|
||||
self.addCleanup(sys.modules.update, previous_sys_modules)
|
||||
|
||||
for module in "collections", "_collections_abc", "collections.abc":
|
||||
sys.modules.pop(module, None)
|
||||
|
||||
with self.assertWarns(DeprecationWarning):
|
||||
from collections.abc import ByteString
|
||||
for sample in [bytes, bytearray]:
|
||||
with self.assertWarns(DeprecationWarning):
|
||||
self.assertIsInstance(sample(), ByteString)
|
||||
@@ -1956,6 +1965,14 @@ class TestCollectionABCs(ABCTestCase):
|
||||
# No metaclass conflict
|
||||
class Z(ByteString, Awaitable): pass
|
||||
|
||||
def test_ByteString_attribute_access(self):
|
||||
collections_abc = import_fresh_module(
|
||||
"collections.abc",
|
||||
fresh=("collections", "_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)
|
||||
|
||||
@@ -13,6 +13,7 @@ import os
|
||||
import pickle
|
||||
import re
|
||||
import sys
|
||||
import warnings
|
||||
from unittest import TestCase, main, skip
|
||||
from unittest.mock import patch
|
||||
from copy import copy, deepcopy
|
||||
@@ -7500,14 +7501,23 @@ class CollectionsAbcTests(BaseTestCase):
|
||||
self.assertNotIsInstance((), typing.MutableSequence)
|
||||
|
||||
def test_bytestring(self):
|
||||
previous_typing_module = sys.modules.pop("typing", None)
|
||||
self.addCleanup(sys.modules.__setitem__, "typing", previous_typing_module)
|
||||
|
||||
with self.assertWarns(DeprecationWarning):
|
||||
self.assertIsInstance(b'', typing.ByteString)
|
||||
from typing import ByteString
|
||||
with self.assertWarns(DeprecationWarning):
|
||||
self.assertIsInstance(bytearray(b''), typing.ByteString)
|
||||
self.assertIsInstance(b'', ByteString)
|
||||
with self.assertWarns(DeprecationWarning):
|
||||
class Foo(typing.ByteString): ...
|
||||
self.assertIsInstance(bytearray(b''), ByteString)
|
||||
with self.assertWarns(DeprecationWarning):
|
||||
class Bar(typing.ByteString, typing.Awaitable): ...
|
||||
self.assertIsSubclass(bytes, ByteString)
|
||||
with self.assertWarns(DeprecationWarning):
|
||||
self.assertIsSubclass(bytearray, ByteString)
|
||||
with self.assertWarns(DeprecationWarning):
|
||||
class Foo(ByteString): ...
|
||||
with self.assertWarns(DeprecationWarning):
|
||||
class Bar(ByteString, typing.Awaitable): ...
|
||||
|
||||
def test_list(self):
|
||||
self.assertIsSubclass(list, typing.List)
|
||||
@@ -10455,6 +10465,10 @@ SpecialAttrsT = typing.TypeVar('SpecialAttrsT', int, float, complex)
|
||||
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',
|
||||
@@ -10463,7 +10477,7 @@ class SpecialAttrsTests(BaseTestCase):
|
||||
typing.AsyncIterable: 'AsyncIterable',
|
||||
typing.AsyncIterator: 'AsyncIterator',
|
||||
typing.Awaitable: 'Awaitable',
|
||||
typing.ByteString: 'ByteString',
|
||||
typing_ByteString: 'ByteString',
|
||||
typing.Callable: 'Callable',
|
||||
typing.ChainMap: 'ChainMap',
|
||||
typing.Collection: 'Collection',
|
||||
@@ -10816,7 +10830,8 @@ class AllTests(BaseTestCase):
|
||||
# there's a few types and metaclasses that aren't exported
|
||||
not k.endswith(('Meta', '_contra', '_co')) and
|
||||
not k.upper() == k and
|
||||
# but export all things that have __module__ == 'typing'
|
||||
k not in {"ByteString"} and
|
||||
# but export all other things that have __module__ == 'typing'
|
||||
getattr(v, '__module__', None) == typing.__name__
|
||||
)
|
||||
}
|
||||
|
||||
@@ -65,7 +65,6 @@ __all__ = [
|
||||
|
||||
# ABCs (from collections.abc).
|
||||
'AbstractSet', # collections.abc.Set.
|
||||
'ByteString',
|
||||
'Container',
|
||||
'ContextManager',
|
||||
'Hashable',
|
||||
@@ -1603,21 +1602,6 @@ 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'
|
||||
@@ -2805,9 +2789,6 @@ 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__ = \
|
||||
@@ -3799,6 +3780,48 @@ def __getattr__(attr):
|
||||
)
|
||||
warnings.warn(depr_message, category=DeprecationWarning, stacklevel=2)
|
||||
obj = _collect_type_parameters
|
||||
elif attr == "ByteString":
|
||||
import warnings
|
||||
|
||||
warnings._deprecated(
|
||||
"typing.ByteString",
|
||||
message=(
|
||||
"{name!r} and 'collections.abc.ByteString' are deprecated "
|
||||
"and slated for removal in Python {remove}"
|
||||
),
|
||||
remove=(3, 17)
|
||||
)
|
||||
|
||||
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)
|
||||
|
||||
def __subclasscheck__(self, cls):
|
||||
import warnings
|
||||
warnings._deprecated(
|
||||
f"{self.__module__}.{self._name}", remove=self._removal_version
|
||||
)
|
||||
return super().__subclasscheck__(cls)
|
||||
|
||||
with warnings.catch_warnings(
|
||||
action="ignore", category=DeprecationWarning
|
||||
):
|
||||
# Not generic
|
||||
ByteString = globals()["ByteString"] = _DeprecatedGenericAlias(
|
||||
collections.abc.ByteString, 0, removal_version=(3, 17)
|
||||
)
|
||||
|
||||
return ByteString
|
||||
else:
|
||||
raise AttributeError(f"module {__name__!r} has no attribute {attr!r}")
|
||||
globals()[attr] = obj
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
:class:`collections.abc.ByteString` has been removed from
|
||||
``collections.abc.__all__``, and :class:`typing.ByteString` has been removed
|
||||
from ``typing.__all__``. The former has been deprecated since Python 3.12,
|
||||
and the latter has been deprecated since Python 3.9. Both classes are
|
||||
scheduled for removal in Python 3.17.
|
||||
|
||||
Additionally, the following statements now cause ``DeprecationWarning``\ s to
|
||||
be emitted at runtime: ``from collections.abc import ByteString``, ``from
|
||||
typing import ByteString``, ``import collections.abc;
|
||||
collections.abc.ByteString`` and ``import typing; typing.ByteString``. Both
|
||||
classes already caused ``DeprecationWarning``\ s to be emitted if they were
|
||||
subclassed or used as the second argument to ``isinstance()`` or
|
||||
``issubclass()``, but they did not previously lead to
|
||||
``DeprecationWarning``\ s if they were merely imported or accessed from their
|
||||
respective modules.
|
||||
Reference in New Issue
Block a user