Skip to content
Merged
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
2 changes: 1 addition & 1 deletion Doc/deprecations/pending-removal-in-3.15.rst
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ Pending removal in Python 3.15
Use ``class TD(TypedDict): pass`` or ``TD = TypedDict("TD", {})``
to create a TypedDict with zero field.

* The :func:`typing.no_type_check_decorator` decorator function
* The :func:`!typing.no_type_check_decorator` decorator function
has been deprecated since Python 3.13.
After eight years in the :mod:`typing` module,
it has yet to be supported by any major type checker.
Expand Down
18 changes: 2 additions & 16 deletions Doc/library/typing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3258,17 +3258,6 @@ Functions and decorators

``@no_type_check`` mutates the decorated object in place.

.. decorator:: no_type_check_decorator

Decorator to give another decorator the :func:`no_type_check` effect.

This wraps the decorator with something that wraps the decorated
function in :func:`no_type_check`.

.. deprecated-removed:: 3.13 3.15
No type checker ever added support for ``@no_type_check_decorator``. It
is therefore deprecated, and will be removed in Python 3.15.

.. decorator:: override

Decorator to indicate that a method in a subclass is intended to override a
Expand Down Expand Up @@ -3354,7 +3343,8 @@ Introspection helpers
``__annotations__`` dictionaries. Annotations on classes appearing
earlier in the :term:`method resolution order` always take precedence over
annotations on classes appearing later in the method resolution order.
* The function recursively replaces all occurrences of ``Annotated[T, ...]``
* The function recursively replaces all occurrences of
``Annotated[T, ...]``, ``Required[T]``, ``NotRequired[T]``, and ``ReadOnly[T]``
with ``T``, unless *include_extras* is set to ``True`` (see
:class:`Annotated` for more information).

Expand Down Expand Up @@ -4113,10 +4103,6 @@ convenience. This is subject to change, and not all deprecations are listed.
- 3.12
- Undecided
- :pep:`695`
* - :func:`@typing.no_type_check_decorator <no_type_check_decorator>`
- 3.13
- 3.15
- :gh:`106309`
* - :data:`typing.AnyStr`
- 3.13
- 3.18
Expand Down
2 changes: 1 addition & 1 deletion Doc/whatsnew/3.13.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1993,7 +1993,7 @@ New Deprecations
use ``class TD(TypedDict): pass`` or ``TD = TypedDict("TD", {})``.
(Contributed by Alex Waygood in :gh:`105566` and :gh:`105570`.)

* Deprecate the :func:`typing.no_type_check_decorator` decorator function,
* Deprecate the :func:`!typing.no_type_check_decorator` decorator function,
to be removed in Python 3.15.
After eight years in the :mod:`typing` module,
it has yet to be supported by any major type checker.
Expand Down
3 changes: 3 additions & 0 deletions Doc/whatsnew/3.15.rst
Original file line number Diff line number Diff line change
Expand Up @@ -764,6 +764,9 @@ typing
:func:`issubclass`, but warnings were not previously emitted if it was merely
imported or accessed from the :mod:`!typing` module.

* Deprecated :func:`!typing.no_type_check_decorator` has been removed.
(Contributed by Nikita Sobolev in :gh:`133601`.)


unicodedata
-----------
Expand Down
22 changes: 13 additions & 9 deletions Lib/annotationlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,15 +241,8 @@ def __forward_code__(self):
if self.__code__ is not None:
return self.__code__
arg = self.__forward_arg__
# If we do `def f(*args: *Ts)`, then we'll have `arg = '*Ts'`.
# Unfortunately, this isn't a valid expression on its own, so we
# do the unpacking manually.
if arg.startswith("*"):
arg_to_compile = f"({arg},)[0]" # E.g. (*Ts,)[0] or (*tuple[int, int],)[0]
else:
arg_to_compile = arg
try:
self.__code__ = compile(arg_to_compile, "<string>", "eval")
self.__code__ = compile(_rewrite_star_unpack(arg), "<string>", "eval")
except SyntaxError:
raise SyntaxError(f"Forward reference must be an expression -- got {arg!r}")
return self.__code__
Expand Down Expand Up @@ -1025,7 +1018,8 @@ def get_annotations(
locals = {param.__name__: param for param in type_params} | locals

return_value = {
key: value if not isinstance(value, str) else eval(value, globals, locals)
key: value if not isinstance(value, str)
else eval(_rewrite_star_unpack(value), globals, locals)
for key, value in ann.items()
}
return return_value
Expand Down Expand Up @@ -1062,6 +1056,16 @@ def annotations_to_string(annotations):
}


def _rewrite_star_unpack(arg):
"""If the given argument annotation expression is a star unpack e.g. `'*Ts'`
rewrite it to a valid expression.
"""
if arg.startswith("*"):
return f"({arg},)[0]" # E.g. (*Ts,)[0] or (*tuple[int, int],)[0]
else:
return arg


def _get_and_call_annotate(obj, format):
"""Get the __annotate__ function and call it.

Expand Down
6 changes: 6 additions & 0 deletions Lib/test/test_annotationlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,12 @@ def test_stringized_annotations_in_empty_module(self):
self.assertEqual(get_annotations(isa2, eval_str=True), {})
self.assertEqual(get_annotations(isa2, eval_str=False), {})

def test_stringized_annotations_with_star_unpack(self):
def f(*args: *tuple[int, ...]): ...
self.assertEqual(get_annotations(f, eval_str=True),
{'args': (*tuple[int, ...],)[0]})


def test_stringized_annotations_on_wrapper(self):
isa = inspect_stringized_annotations
wrapped = times_three(isa.function)
Expand Down
31 changes: 1 addition & 30 deletions Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
from typing import is_typeddict, is_protocol
from typing import reveal_type
from typing import dataclass_transform
from typing import no_type_check, no_type_check_decorator
from typing import no_type_check
from typing import Type
from typing import NamedTuple, NotRequired, Required, ReadOnly, TypedDict, NoExtraItems
from typing import IO, TextIO, BinaryIO
Expand Down Expand Up @@ -6376,35 +6376,6 @@ class F:
for clazz in [C, D, E, F]:
self.assertEqual(get_type_hints(clazz), expected_result)

def test_meta_no_type_check(self):
depr_msg = (
"'typing.no_type_check_decorator' is deprecated "
"and slated for removal in Python 3.15"
)
with self.assertWarnsRegex(DeprecationWarning, depr_msg):
@no_type_check_decorator
def magic_decorator(func):
return func

self.assertEqual(magic_decorator.__name__, 'magic_decorator')

@magic_decorator
def foo(a: 'whatevers') -> {}:
pass

@magic_decorator
class C:
def foo(a: 'whatevers') -> {}:
pass

self.assertEqual(foo.__name__, 'foo')
th = get_type_hints(foo)
self.assertEqual(th, {})
cth = get_type_hints(C.foo)
self.assertEqual(cth, {})
ith = get_type_hints(C().foo)
self.assertEqual(ith, {})


class InternalsTests(BaseTestCase):
def test_collect_parameters(self):
Expand Down
18 changes: 0 additions & 18 deletions Lib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,6 @@
'Never',
'NewType',
'no_type_check',
'no_type_check_decorator',
'NoDefault',
'NoExtraItems',
'NoReturn',
Expand Down Expand Up @@ -2623,23 +2622,6 @@ def no_type_check(arg):
return arg


def no_type_check_decorator(decorator):
"""Decorator to give another decorator the @no_type_check effect.

This wraps the decorator with something that wraps the decorated
function in @no_type_check.
"""
import warnings
warnings._deprecated("typing.no_type_check_decorator", remove=(3, 15))
@functools.wraps(decorator)
def wrapped_decorator(*args, **kwds):
func = decorator(*args, **kwds)
func = no_type_check(func)
return func

return wrapped_decorator


def _overload_dummy(*args, **kwds):
"""Helper for @overload to raise when called."""
raise NotImplementedError(
Expand Down
5 changes: 0 additions & 5 deletions Lib/zipimport.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,12 @@
to Zip archives.
"""

#from importlib import _bootstrap_external
#from importlib import _bootstrap # for _verbose_message
import _frozen_importlib_external as _bootstrap_external
from _frozen_importlib_external import _unpack_uint16, _unpack_uint32, _unpack_uint64
import _frozen_importlib as _bootstrap # for _verbose_message
import _imp # for check_hash_based_pycs
import _io # for open
import marshal # for loads
import sys # for modules
import time # for mktime

__all__ = ['ZipImportError', 'zipimporter']
Expand All @@ -34,8 +31,6 @@ class ZipImportError(ImportError):
# _read_directory() cache
_zip_directory_cache = {}

_module_type = type(sys)

END_CENTRAL_DIR_SIZE = 22
END_CENTRAL_DIR_SIZE_64 = 56
END_CENTRAL_DIR_LOCATOR_SIZE_64 = 20
Expand Down
2 changes: 1 addition & 1 deletion Misc/NEWS.d/3.13.0a1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3426,7 +3426,7 @@ This bug was introduced in Python 3.12.0 beta 1.
.. nonce: hSlB17
.. section: Library

Deprecate :func:`typing.no_type_check_decorator`. No major type checker ever
Deprecate :func:`!typing.no_type_check_decorator`. No major type checker ever
added support for this decorator. Patch by Alex Waygood.

..
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Remove deprecated :func:`!typing.no_type_check_decorator`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix ``SyntaxError`` when ``inspect.get_annotations(f, eval_str=True)`` is
called on a function annotated with a :pep:`646` ``star_expression``
Loading