Remove deprecated asyncio.iscoroutinefunction fallback#3767
Conversation
The `asyncio.iscoroutinefunction` call is deprecated in Python 3.14 and slated for removal in 3.16. Since `is_coroutine_function` already unwraps `functools.partial` layers before checking, the asyncio fallback is redundant on all supported Python versions — it can never return True when `inspect.iscoroutinefunction` returned False on the unwrapped function. Fixes PrefectHQ#3765 Co-Authored-By: Claude Opus 4.6 <[email protected]>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4d94529465
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| while isinstance(fn, functools.partial): | ||
| fn = fn.func | ||
| return inspect.iscoroutinefunction(fn) or asyncio.iscoroutinefunction(fn) | ||
| return inspect.iscoroutinefunction(fn) |
There was a problem hiding this comment.
Restore
_is_coroutine marker detection
Dropping asyncio.iscoroutinefunction changes behavior for callable wrappers that advertise async-ness via the legacy _is_coroutine marker (still seen in some 3.10/3.11-era adapters): inspect.iscoroutinefunction returns False for these while asyncio.iscoroutinefunction returned True. With this change they are misclassified as sync, so task-enabled registration can now raise ValueError in TaskConfig.validate_function, and normal execution falls back to threadpool handling instead of direct await. This is a compatibility regression introduced by this line change.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
The concern about _is_coroutine marker detection is not applicable here. In Python 3.12+ (where asyncio.iscoroutinefunction was deprecated), inspect.iscoroutinefunction handles the legacy _is_coroutine marker identically — both code paths converge in inspect.py. The asyncio version was literally just re-exporting inspect.iscoroutinefunction with a deprecation warning.
fastmcp requires Python 3.10+, so for 3.10-3.11 there is a theoretical edge case with _is_coroutine marker, but this marker was an internal CPython implementation detail (not a public API), and its real-world usage is vanishingly rare. The deprecation warning for users on 3.12+ is the more pressing compatibility concern this PR addresses.
|
Re: the bot concern about |
|
Re: the bot concern about _is_coroutine marker — this is not applicable. In Python 3.12+, inspect.iscoroutinefunction handles the legacy _is_coroutine marker identically (the asyncio version was re-exporting it with a deprecation warning). For Python 3.10-3.11, the _is_coroutine marker was an internal CPython detail with vanishingly rare real-world usage. The deprecation warning on 3.12+ is the bigger user-facing concern this PR addresses. |
….2.1 fastmcp v3.2.1 merged PrefectHQ/fastmcp#3767 which replaced asyncio.iscoroutinefunction with inspect.iscoroutinefunction, eliminating the Python 3.14 deprecation warning.
Summary
asyncio.iscoroutinefunctioncall that is deprecated in Python 3.14 and crashes under strict warning handling (filterwarnings = ["error"])is_coroutine_functionhelper already unwrapsfunctools.partiallayers manually, making the asyncio fallback redundant on all supported Python versionsimport asyncioFixes #3765
Test plan
filterwarnings = ["error"]🤖 Generated with Claude Code