Title: Inconsistency in Cython object handling · Issue #143908 · python/cpython · GitHub
Open Graph Title: Inconsistency in Cython object handling · Issue #143908 · python/cpython
X Title: Inconsistency in Cython object handling · Issue #143908 · python/cpython
Description: Bug report Bug description: There seems to be no consensus in the codebase on how to handle Cython objects. Both inspect.iscoroutinefunction() and inspect.iscoroutine() are defined in the documentation for async def functions and their o...
Open Graph Description: Bug report Bug description: There seems to be no consensus in the codebase on how to handle Cython objects. Both inspect.iscoroutinefunction() and inspect.iscoroutine() are defined in the documenta...
X Description: Bug report Bug description: There seems to be no consensus in the codebase on how to handle Cython objects. Both inspect.iscoroutinefunction() and inspect.iscoroutine() are defined in the documenta...
Opengraph URL: https://github.com/python/cpython/issues/143908
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Inconsistency in Cython object handling","articleBody":"# Bug report\n\n### Bug description:\n\nThere seems to be no consensus in the codebase on how to handle Cython objects. Both [`inspect.iscoroutinefunction()`](https://docs.python.org/3/library/inspect.html#inspect.iscoroutinefunction) and [`inspect.iscoroutine()`](https://docs.python.org/3/library/inspect.html#inspect.iscoroutine) are defined in the documentation for [`async def`](https://docs.python.org/3/reference/compound_stmts.html#async-def) functions and their objects, respectively. Therefore, the following code should be valid for them:\n\n```python\n#!/usr/bin/env python3\n\nimport inspect\n\n\nasync def coroutine_function() -\u003e None:\n pass\n\n\ndef main() -\u003e None:\n print(inspect.iscoroutinefunction(coroutine_function)) # `True`\n print(inspect.iscoroutine(coro := coroutine_function())) # `True`\n coro.close() # to avoid `RuntimeWarning`\n\n\nif __name__ == \"__main__\":\n main()\n```\n\nThe same semantics are also expected by [typeshed](https://github.com/python/typeshed), which defines annotations as follows (and thus declares support for introspection):\n\n```python\n...\n@overload\ndef iscoroutinefunction(obj: object) -\u003e TypeGuard[Callable[..., CoroutineType[Any, Any, Any]]]: ...\n...\ndef iscoroutine(object: object) -\u003e TypeIs[CoroutineType[Any, Any, Any]]: ...\n...\n```\n\nHowever, after `cythonize -i -3`, the code changes its behavior:\n\n```python\nTrue # `inspect.iscoroutinefunction()`\nFalse # `inspect.iscoroutine()`\n```\n\nThis is because Cython uses its own objects for compiled functions and generators/coroutines/asynchronous generators. `inspect.is\u003cobject\u003e()` returns `True` only for uncompiled objects, as it relies on the [types](https://docs.python.org/3/library/types.html) module, but `inspect.is\u003cobject\u003efunction()` relies on checking function flags and handles function-like objects in a special way (for compatibility with Cython). As a result, we get the contradictory \"coroutine function does not return a coroutine\".\n\nThe problem is even deeper than one might imagine:\n\n1. Cython objects do not actually correspond completely to their counterparts from CPython. See cython/cython#7448.\n2. Mypy avoids using the [types](https://docs.python.org/3/library/types.html) module to infer the return type due to possible incompatibility with Cython. See python/mypy#18635 and python/mypy#20522.\n3. If the user wants to handle objects regardless of whether the module has been compiled or not, they have to come up with their own way of checking objects. See python/cpython#131983.\n\nWhat if we want to define a universal decorator that works for both regular and asynchronous functions? We could use [`inspect.iscoroutinefunction()`](https://docs.python.org/3/library/inspect.html#inspect.iscoroutinefunction), but it has very limited detection (in particular, it cannot detect object with `async def __call__()`), and library developers will only be able to rely on [`inspect.markcoroutinefunction()`](https://docs.python.org/3/library/inspect.html#inspect.markcoroutinefunction) after the Python 3.11's EOF. A frequently suggested alternative is to check the return value's type using [`inspect.isawaitable()`](https://docs.python.org/3/library/inspect.html#inspect.isawaitable), but this is actually shooting oneself in the foot, as it will lead to false positives for future-like objects (such as [asyncio future objects](https://docs.python.org/3/library/asyncio-future.html), which are also awaitable). The most logical solution would be to use [`inspect.iscoroutine()`](https://docs.python.org/3/library/inspect.html#inspect.iscoroutine), but it does not support Cython (and in fact, it is even less useful; see https://github.com/GrahamDumpleton/wrapt/issues/236#issuecomment-3655259023).\n\nIt seems to me that the question of whether the standard library (and related tools) should be Cython-aware has not been fully explored, which leads to such contradictions. I marked the issue as a bug, since it violates the expected behavior for any consistent interpretation.\n\n### CPython versions tested on:\n\n3.9, 3.10, 3.11, 3.12, 3.13, 3.14\n\n### Operating systems tested on:\n\nLinux","author":{"url":"https://github.com/x42005e1f","@type":"Person","name":"x42005e1f"},"datePublished":"2026-01-16T14:16:16.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":7},"url":"https://github.com/143908/cpython/issues/143908"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:ab523514-a928-b8ca-b463-e584c7694864 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | 8D32:FB091:244D47:339C95:6A631E50 |
| html-safe-nonce | e4723ae9d1b745f05389bece36df281b7f8f3ffac8af4569e1a38aafafa1e92c |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiI4RDMyOkZCMDkxOjI0NEQ0NzozMzlDOTU6NkE2MzFFNTAiLCJ2aXNpdG9yX2lkIjoiODM5ODc3Mjc0MTk3MDUzMzk2OCIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9 |
| visitor-hmac | 200de2b0f5f81d68464339d55c107dfff5faece950c3c9bc0cc948e24e2afe99 |
| hovercard-subject-tag | issue:3822228330 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/python/cpython/143908/issue_layout |
| twitter:image | https://opengraph.githubassets.com/3c501d559792d611116f30462892fbf4003145e986988eab156115ec5d5b9d13/python/cpython/issues/143908 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/3c501d559792d611116f30462892fbf4003145e986988eab156115ec5d5b9d13/python/cpython/issues/143908 |
| og:image:alt | Bug report Bug description: There seems to be no consensus in the codebase on how to handle Cython objects. Both inspect.iscoroutinefunction() and inspect.iscoroutine() are defined in the documenta... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | x42005e1f |
| hostname | github.com |
| expected-hostname | github.com |
| None | 1a6c056e02f174fffc096c521ec0ff6fb83e40a2ec8cb8875466ec1524872dd6 |
| turbo-cache-control | no-preview |
| go-import | github.com/python/cpython git https://github.com/python/cpython.git |
| octolytics-dimension-user_id | 1525981 |
| octolytics-dimension-user_login | python |
| octolytics-dimension-repository_id | 81598961 |
| octolytics-dimension-repository_nwo | python/cpython |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 81598961 |
| octolytics-dimension-repository_network_root_nwo | python/cpython |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 6a93e25585f487ddff9e3996c06d5b869d6e1828 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width