From 71a04797203b1f84763fffba2f6bb6bcd5024195 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Thu, 3 Sep 2026 09:23:25 +0100 Subject: [PATCH] gh-82406: Add 3.10.6 change notes for inspect.is*function (GH-94987) Document when these functions started checking code flags for "duck-typed" function-like objects. (cherry picked from commit 1059e8072e24154bbcb9d4c881609821c117f6ab) Co-authored-by: Thomas Grainger --- Doc/library/inspect.rst | 12 ++++++++++++ Lib/inspect.py | 6 ++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index af1a7220ec5e9e4..96d78ca122a870c 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -388,6 +388,10 @@ attributes (see :ref:`import-mod-attrs` for module attributes): Functions wrapped in :func:`functools.partial` now return ``True`` if the wrapped function is a Python generator function. + .. versionchanged:: 3.10.6 + :term:`Duck-typed ` function-like objects now return + ``True`` if their code object has the :data:`CO_GENERATOR` flag. + .. versionchanged:: 3.13 Functions wrapped in :func:`functools.partialmethod` now return ``True`` if the wrapped function is a Python generator function. @@ -410,6 +414,10 @@ attributes (see :ref:`import-mod-attrs` for module attributes): Functions wrapped in :func:`functools.partial` now return ``True`` if the wrapped function is a :term:`coroutine function`. + .. versionchanged:: 3.10.6 + :term:`Duck-typed ` function-like objects now return + ``True`` if their code object has the :data:`CO_COROUTINE` flag. + .. versionchanged:: 3.12 Sync functions marked with :func:`markcoroutinefunction` now return ``True``. @@ -484,6 +492,10 @@ attributes (see :ref:`import-mod-attrs` for module attributes): Functions wrapped in :func:`functools.partial` now return ``True`` if the wrapped function is an :term:`asynchronous generator` function. + .. versionchanged:: 3.10.6 + :term:`Duck-typed ` function-like objects now return + ``True`` if their code object has the :data:`CO_ASYNC_GENERATOR` flag. + .. versionchanged:: 3.13 Functions wrapped in :func:`functools.partialmethod` now return ``True`` if the wrapped function is a :term:`asynchronous generator` function. diff --git a/Lib/inspect.py b/Lib/inspect.py index 9711cb874022ca0..28df127b15c5274 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -414,6 +414,8 @@ def _has_code_flag(f, flag): f = functools._unwrap_partial(f) if not (isfunction(f) or _signature_is_functionlike(f)): return False + # If it's a pure Python function, or an object that is duck type + # of a Python function (Cython and Mock functions, for instance), then: return bool(f.__code__.co_flags & flag) def isgeneratorfunction(obj): @@ -2408,7 +2410,7 @@ def _signature_from_function(cls, func, skip_bound_arg=True, is_duck_function = True else: # If it's not a pure Python function, and not a duck type - # of pure function: + # of pure function (Cython and Mock functions, for instance), then: raise TypeError('{!r} is not a Python function'.format(func)) s = getattr(func, "__text_signature__", None) @@ -2601,7 +2603,7 @@ def _signature_from_callable(obj, *, if isfunction(obj) or _signature_is_functionlike(obj): # If it's a pure Python function, or an object that is duck type - # of a Python function (Cython functions, for instance), then: + # of a Python function (Cython and Mock functions, for instance), then: return _signature_from_function(sigcls, obj, skip_bound_arg=skip_bound_arg, globals=globals, locals=locals, eval_str=eval_str)