python / python/cpython

`inspect.iscoroutinefunction()` does not detect marked partial objects

オープン
#142,418 コメント 4 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

stdlib type-bug
主要言語
Python
スター
77.2k
フォーク
35.9k
PR マージ指標
PR 指標を取得中

説明

Bug report

Bug description:

inspect.markcoroutinefunction() is applied directly to the passed function, except for methods (which is correct behavior). However, inspect.iscoroutinefunction() checks the passed function only after unwrapping (a function that is not wrapped in either functools.partial or functools.partialmethod (currently, _has_coroutine_mark() does not handle these objects; why?)), and thus cannot detect the marker that is not at the end of the unwrapping chain, which results in false negative in cases where a functools.partial/functools.partialmethod object is marked.

>>> from functools import partial
>>> from inspect import iscoroutinefunction, markcoroutinefunction
>>> async def wedonotlikesnakecase():
...     return "the_funniest_joke_in_the_world"
>>> def manufacturer_of_jokes(somefunc):
...     global manufacturer_of_jokes
...     del manufacturer_of_jokes
...     return somefunc()
>>> joke = partial(manufacturer_of_jokes, wedonotlikesnakecase)
>>> joke = markcoroutinefunction(joke)
>>> iscoroutinefunction(joke)
False

I discovered this problem while theoretically considering backporting inspect.iscoroutinefunction() to older versions of Python. The problem has not yet been caused by any use case, so it is okay if the issue is closed due to lack of demand. But just in case, I am attaching part of how iscoroutinefunction() is implemented in my code.

def iscoroutinefunction(obj):
    marker_name, marker_value = _get_coroutinefunction_marker()

    while True:  # unwrap & check
        if ismethod(obj):
            obj = obj.__func__
            continue

        if marker_value is not MISSING:
            if getattr(obj, marker_name, MISSING) is marker_value:
                return True

        if isinstance(obj, partial):
            obj = obj.func
            continue

        impl = getattr(obj, _partialmethod_attribute_name, MISSING)

        if isinstance(impl, partialmethod):
            obj = impl.func
            continue

        # unlike its namesake in the `inspect` module, it does not unwrap
        return _has_code_flag(obj, CO_COROUTINE)
CPython versions tested on:

3.12, 3.13, 3.14

Operating systems tested on:

Linux

Linked PRs
  • gh-142503
  • gh-142505

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

inspect.iscoroutinefunction()、inspect.markcoroutinefunction()、_has_coroutine_mark()から始め、issueのreproducerを使って、マークされたfunctools.partialに対するfalse negativeを確認してください。開始前に、リンクされているPR gh-142503とgh-142505を確認してください。完了とは、報告されたpartial-objectのケースが正しく検出され、既存のメソッドおよびアンラップの動作にリグレッションが発生しないことを意味します。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
python
領域
backend
issue の種類
バグ
難易度
3/5
見積もり時間
1〜2日
活発さ
停滞
明瞭さ
明確に書かれている
初心者へのやさしさ
35/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。