diff options
author | Alex Waygood <Alex.Waygood@Gmail.com> | 2023-05-12 06:01:31 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-12 06:01:31 (GMT) |
commit | f0f5bb32043e1223d8c413e763cd93061d4f9fac (patch) | |
tree | 217a4dbfc9e85a7e2722b6791062f6a96bdadaab /Lib | |
parent | a0a98ddb31591357bead4694b21717cb4034924f (diff) | |
download | cpython-f0f5bb32043e1223d8c413e763cd93061d4f9fac.zip cpython-f0f5bb32043e1223d8c413e763cd93061d4f9fac.tar.gz cpython-f0f5bb32043e1223d8c413e763cd93061d4f9fac.tar.bz2 |
gh-91896: Improve visibility of `ByteString` deprecation warnings (#104294)
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/collections/abc.py | 9 | ||||
-rw-r--r-- | Lib/test/libregrtest/refleak.py | 16 | ||||
-rw-r--r-- | Lib/test/test_collections.py | 10 | ||||
-rw-r--r-- | Lib/test/test_typing.py | 30 | ||||
-rw-r--r-- | Lib/typing.py | 32 |
5 files changed, 85 insertions, 12 deletions
diff --git a/Lib/collections/abc.py b/Lib/collections/abc.py index 86ca8b8..60b1eb6 100644 --- a/Lib/collections/abc.py +++ b/Lib/collections/abc.py @@ -1,3 +1,12 @@ 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 2de8c6c..776a9e9 100644 --- a/Lib/test/libregrtest/refleak.py +++ b/Lib/test/libregrtest/refleak.py @@ -48,11 +48,13 @@ def dash_R(ns, test_name, test_func): else: zdc = zipimport._zip_directory_cache.copy() abcs = {} - 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] + # 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] # 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 @@ -173,7 +175,9 @@ def dash_R_cleanup(fs, ps, pic, zdc, abcs): zipimport._zip_directory_cache.update(zdc) # Clear ABC registries, restoring previously saved ABC registries. - abs_classes = [getattr(collections.abc, a) for a in collections.abc.__all__] + # 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 = 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 bb8b352..f0736b8 100644 --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -11,6 +11,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 @@ -25,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 ByteString, Buffer +from collections.abc import Buffer class TestUserObjects(unittest.TestCase): @@ -1939,6 +1940,8 @@ class TestCollectionABCs(ABCTestCase): 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) @@ -1960,6 +1963,11 @@ class TestCollectionABCs(ABCTestCase): # 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 f162e58..3422dc1 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -8,6 +8,7 @@ import pickle 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 @@ -3908,7 +3909,14 @@ class GenericTests(BaseTestCase): self.assertEqual(MyChain[int]().__orig_class__, MyChain[int]) def test_all_repr_eq_any(self): - objs = (getattr(typing, el) for el in typing.__all__) + 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"] + ) for obj in objs: self.assertNotEqual(repr(obj), '') self.assertEqual(obj, obj) @@ -5996,8 +6004,16 @@ class CollectionsAbcTests(BaseTestCase): self.assertNotIsInstance((), typing.MutableSequence) def test_bytestring(self): - self.assertIsInstance(b'', typing.ByteString) - self.assertIsInstance(bytearray(b''), typing.ByteString) + with self.assertWarns(DeprecationWarning): + from typing import ByteString + with self.assertWarns(DeprecationWarning): + self.assertIsInstance(b'', ByteString) + with self.assertWarns(DeprecationWarning): + self.assertIsInstance(bytearray(b''), 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) @@ -8293,6 +8309,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', @@ -8301,7 +8321,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', @@ -8626,6 +8646,8 @@ class AllTests(BaseTestCase): 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 62c7dd3..bf7bd24 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1599,6 +1599,22 @@ class _SpecialGenericAlias(_NotIterable, _BaseGenericAlias, _root=True): 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' @@ -2756,7 +2772,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 = _alias(collections.abc.ByteString, 0) # Not generic # Tuple accepts variable number of parameters. Tuple = _TupleType(tuple, -1, inst=False, name='Tuple') Tuple.__doc__ = \ @@ -3556,3 +3571,18 @@ def override(method: F, /) -> F: # 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}") |