Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Doc/deprecations/pending-removal-in-3.21.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,10 @@ Pending removal in Python 3.21

* ``tempfile._TemporaryFileWrapper`` will be removed in Python 3.21. Use the
public :class:`tempfile.TemporaryFileWrapper` instead.

* :mod:`typing`:

* :data:`typing.AnyStr` has been discouraged
and deprecated since Python 3.13
and is scheduled to be removed in Python 3.21.
Use :pep:`695` syntax instead.
8 changes: 4 additions & 4 deletions Doc/library/typing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -894,15 +894,15 @@ using ``[]``.
def greet_proper(cond: bool) -> str | bytes:
return "hi there!" if cond else b"greetings!"

.. deprecated-removed:: 3.13 3.18
.. deprecated-removed:: 3.13 3.21
Deprecated in favor of the new :ref:`type parameter syntax <type-params>`.
Use ``class A[T: (str, bytes)]: ...`` instead of importing ``AnyStr``. See
:pep:`695` for more details.

In Python 3.16, ``AnyStr`` will be removed from ``typing.__all__``, and
deprecation warnings will be emitted at runtime when it is accessed or
Since Python 3.16, ``AnyStr`` is removed from ``typing.__all__``, and
deprecation warnings are emitted at runtime when it is accessed or
imported from ``typing``. ``AnyStr`` will be removed from ``typing``
in Python 3.18.
in Python 3.21.

.. data:: LiteralString

Expand Down
4 changes: 4 additions & 0 deletions Doc/whatsnew/3.16.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1218,6 +1218,10 @@ New deprecations
open them one by one instead.
(Contributed by Serhiy Storchaka in :gh:`152638`.)

* :mod:`typing`:

* :data:`typing.AnyStr` now raises :exc:`DeprecationWarning` when used.

.. Add deprecations above alphabetically, not here at the end.

.. include:: ../deprecations/pending-removal-in-3.17.rst
Expand Down
30 changes: 22 additions & 8 deletions Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

from typing import Any, NoReturn, Never, assert_never
from typing import overload, get_overloads, clear_overloads
from typing import TypeVar, TypeVarTuple, Unpack, AnyStr
from typing import TypeVar, TypeVarTuple, Unpack
from typing import T, KT, VT # Not in __all__.
from typing import Union, Optional, Literal
from typing import Tuple, List, Dict, MutableMapping
Expand Down Expand Up @@ -489,7 +489,6 @@ def test_repr(self):
self.assertEqual(repr(T), '~T')
self.assertEqual(repr(KT), '~KT')
self.assertEqual(repr(VT), '~VT')
self.assertEqual(repr(AnyStr), '~AnyStr')
T_co = TypeVar('T_co', covariant=True)
self.assertEqual(repr(T_co), '+T_co')
T_contra = TypeVar('T_contra', contravariant=True)
Expand Down Expand Up @@ -6388,13 +6387,15 @@ def on_bottom(self, a: int) -> int:
class CastTests(BaseTestCase):

def test_basics(self):
T = TypeVar("T")

self.assertEqual(cast(int, 42), 42)
self.assertEqual(cast(float, 42), 42)
self.assertIs(type(cast(float, 42)), int)
self.assertEqual(cast(Any, 42), 42)
self.assertEqual(cast(list, 42), 42)
self.assertEqual(cast(Union[str, float], 42), 42)
self.assertEqual(cast(AnyStr, 42), 42)
self.assertEqual(cast(T, 42), 42)
self.assertEqual(cast(None, 42), 42)

def test_errors(self):
Expand All @@ -6407,9 +6408,10 @@ class AssertTypeTests(BaseTestCase):

def test_basics(self):
arg = 42
T = TypeVar("T")
self.assertIs(assert_type(arg, int), arg)
self.assertIs(assert_type(arg, str | float), arg)
self.assertIs(assert_type(arg, AnyStr), arg)
self.assertIs(assert_type(arg, T), arg)
self.assertIs(assert_type(arg, None), arg)

def test_errors(self):
Expand Down Expand Up @@ -9637,12 +9639,15 @@ def test_no_isinstance(self):
class IOTests(BaseTestCase):

def test_io(self):

def stuff(a: IO) -> AnyStr:
def stuff(a: IO):
return a.readline()

a = stuff.__annotations__['a']
self.assertEqual(a.__parameters__, (AnyStr,))
self.assertEqual(len(a.__parameters__), 1)
any_str = a.__parameters__[0]
self.assertEqual(repr(any_str), 'AnyStr')
self.assertEqual(any_str.__bound__, None)
self.assertEqual(any_str.__constraints__, (bytes, str))

def test_textio(self):

Expand Down Expand Up @@ -11285,13 +11290,22 @@ def test_all_exported_names(self):
# there's a few types and metaclasses that aren't exported
not k.endswith(('Meta', '_contra', '_co')) and
not k.upper() == k and
k not in {"ByteString"} and
k not in {"ByteString", "AnyStr"} and
# but export all other things that have __module__ == 'typing'
getattr(v, '__module__', None) == typing.__name__
)
}
self.assertSetEqual(computed_all, actual_all)

def test_any_str_deprecated(self):
# gh-105578
fresh = import_helper.import_fresh_module('typing')

with self.assertWarnsRegex(DeprecationWarning, r'typing\.AnyStr'):
fresh.AnyStr

self.assertEqual(repr(fresh.AnyStr), '~AnyStr')


class TypeIterationTests(BaseTestCase):
_UNITERABLE_TYPES = (
Expand Down
25 changes: 17 additions & 8 deletions Lib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,6 @@
'TextIO',

# One-off things.
'AnyStr',
'assert_type',
'assert_never',
'cast',
Expand Down Expand Up @@ -2840,11 +2839,6 @@ class Disjoint3(Disjoint1, Disjoint2): pass # Type checker error
CT_co = TypeVar('CT_co', covariant=True, bound=type)


# A useful type variable with constraints. This represents string types.
# (This one *is* for export!)
AnyStr = TypeVar('AnyStr', bytes, str)


# Various ABCs mimicking those in collections.abc.
_alias = _SpecialGenericAlias

Expand Down Expand Up @@ -3548,8 +3542,9 @@ def __ror__(self, other):
# Constant that's True when type checking, but False here.
TYPE_CHECKING = False


class IO(Generic[AnyStr]):
# Since `AnyStr` public API is deprecated since 3.16 and will be removed
# in 3.21, we need to keep `IO` protocol the same as it used to be:
class IO[AnyStr: (bytes, str)]:
"""Generic base class for TextIO and BinaryIO.

This is an abstract, generic version of the return of open().
Expand Down Expand Up @@ -3949,6 +3944,20 @@ def __subclasscheck__(self, cls):
)

return ByteString
elif attr == "AnyStr":
import warnings

warnings._deprecated(
"typing.AnyStr",
message=(
"{name!r} is deprecated and slated for removal "
"in Python {remove}. Use PEP 695 type parameters "
"with constraints instead"
),
remove=(3, 21),
)
AnyStr = globals()["AnyStr"] = TypeVar('AnyStr', bytes, str)
return AnyStr
else:
raise AttributeError(f"module {__name__!r} has no attribute {attr!r}")
globals()[attr] = obj
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Deprecate :data:`typing.AnyStr` type variable and raise a warning when it
is imported.
Loading