Skip to content

Commit

Permalink
Copy the coroutine status in deprecated (#438)
Browse files Browse the repository at this point in the history
Co-authored-by: Alex Waygood <[email protected]>
  • Loading branch information
srittau and AlexWaygood authored Aug 29, 2024
1 parent 70cec91 commit d9509f9
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
- Add `typing_extensions.get_annotations`, a backport of
`inspect.get_annotations` that adds features specified
by PEP 649. Patches by Jelle Zijlstra and Alex Waygood.
- Copy the coroutine status of functions and methods wrapped
with `@typing_extensions.deprecated`. Patch by Sebastian Rittau.

# Release 4.12.2 (June 7, 2024)

Expand Down
38 changes: 38 additions & 0 deletions src/test_typing_extensions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import abc
import asyncio
import collections
import collections.abc
import contextlib
Expand Down Expand Up @@ -115,9 +116,15 @@
# and adds PEP 695 to CPython's grammar
TYPING_3_12_0 = sys.version_info[:3] >= (3, 12, 0)

# @deprecated works differently in Python 3.12
TYPING_3_12_ONLY = (3, 12) <= sys.version_info < (3, 13)

# 3.13 drops support for the keyword argument syntax of TypedDict
TYPING_3_13_0 = sys.version_info[:3] >= (3, 13, 0)

# 3.13.0.rc1 fixes a problem with @deprecated
TYPING_3_13_0_RC = sys.version_info[:4] >= (3, 13, 0, "candidate")

# https://github.com/python/cpython/pull/27017 was backported into some 3.9 and 3.10
# versions, but not all
HAS_FORWARD_MODULE = "module" in inspect.signature(typing._type_check).parameters
Expand Down Expand Up @@ -850,6 +857,37 @@ def d(): pass
isinstance(cell.cell_contents, deprecated) for cell in d.__closure__
))

@deprecated("depr")
def func():
pass

@deprecated("depr")
async def coro():
pass

class Cls:
@deprecated("depr")
def func(self):
pass

@deprecated("depr")
async def coro(self):
pass

class DeprecatedCoroTests(BaseTestCase):
def test_asyncio_iscoroutinefunction(self):
self.assertFalse(asyncio.coroutines.iscoroutinefunction(func))
self.assertFalse(asyncio.coroutines.iscoroutinefunction(Cls.func))
self.assertTrue(asyncio.coroutines.iscoroutinefunction(coro))
self.assertTrue(asyncio.coroutines.iscoroutinefunction(Cls.coro))

@skipUnless(TYPING_3_12_ONLY or TYPING_3_13_0_RC, "inspect.iscoroutinefunction works differently on Python < 3.12")
def test_inspect_iscoroutinefunction(self):
self.assertFalse(inspect.iscoroutinefunction(func))
self.assertFalse(inspect.iscoroutinefunction(Cls.func))
self.assertTrue(inspect.iscoroutinefunction(coro))
self.assertTrue(inspect.iscoroutinefunction(Cls.coro))


class AnyTests(BaseTestCase):
def test_can_subclass(self):
Expand Down
8 changes: 8 additions & 0 deletions src/typing_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2898,13 +2898,21 @@ def __init_subclass__(*args, **kwargs):
__init_subclass__.__deprecated__ = msg
return arg
elif callable(arg):
import asyncio.coroutines
import functools
import inspect

@functools.wraps(arg)
def wrapper(*args, **kwargs):
warnings.warn(msg, category=category, stacklevel=stacklevel + 1)
return arg(*args, **kwargs)

if asyncio.coroutines.iscoroutinefunction(arg):
if sys.version_info >= (3, 12):
wrapper = inspect.markcoroutinefunction(wrapper)
else:
wrapper._is_coroutine = asyncio.coroutines._is_coroutine

arg.__deprecated__ = wrapper.__deprecated__ = msg
return wrapper
else:
Expand Down

0 comments on commit d9509f9

Please sign in to comment.