FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

bpo-34890: Make iscoroutinefunction, isgeneratorfunction and isasyncgenfunction work with functools.partial by pablogsal · Pull Request #9903 · python/cpython · GitHub

Repository navigation

12 changes: 12 additions & 0 deletions Doc/library/inspect.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,10 @@ attributes:

Return true if the object is a Python generator function.

.. versionchanged:: 3.8
Functions wrapped in :func:`functools.partial` now return true if the
wrapped function is a Python generator function.


.. function:: isgenerator(object)

Expand All @@ -314,6 +318,10 @@ attributes:

.. versionadded:: 3.5

.. versionchanged:: 3.8
Functions wrapped in :func:`functools.partial` now return true if the
wrapped function is a :term:`coroutine function`.


.. function:: iscoroutine(object)

Expand Down Expand Up @@ -355,6 +363,10 @@ attributes:

.. versionadded:: 3.6

.. versionchanged:: 3.8
Functions wrapped in :func:`functools.partial` now return true if the
wrapped function is a :term:`asynchronous generator` function.


.. function:: isasyncgen(object)

Expand Down
6 changes: 6 additions & 0 deletions Lib/functools.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,12 @@ def __get__(self, obj, cls):
def __isabstractmethod__(self):
return getattr(self.func, "__isabstractmethod__", False)

# Helper functions

def _unwrap_partial(func):
while isinstance(func, partial):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

@pablogsal BTW this doesn't handle the case of partialmethod. Should we add that?

func = func.func
return func

################################################################################
### LRU Cache function decorator
Expand Down
21 changes: 12 additions & 9 deletions Lib/inspect.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -168,30 +168,33 @@ def isfunction(object):
__kwdefaults__ dict of keyword only parameters with defaults"""
return isinstance(object, types.FunctionType)

def isgeneratorfunction(object):
def isgeneratorfunction(obj):
"""Return true if the object is a user-defined generator function.

Generator function objects provide the same attributes as functions.
See help(isfunction) for a list of attributes."""
return bool((isfunction(object) or ismethod(object)) and
object.__code__.co_flags & CO_GENERATOR)
obj = functools._unwrap_partial(obj)
return bool((isfunction(obj) or ismethod(obj)) and
obj.__code__.co_flags & CO_GENERATOR)

def iscoroutinefunction(object):
def iscoroutinefunction(obj):
"""Return true if the object is a coroutine function.

Coroutine functions are defined with "async def" syntax.
"""
return bool((isfunction(object) or ismethod(object)) and
object.__code__.co_flags & CO_COROUTINE)
obj = functools._unwrap_partial(obj)
return bool(((isfunction(obj) or ismethod(obj)) and
obj.__code__.co_flags & CO_COROUTINE))

def isasyncgenfunction(object):
def isasyncgenfunction(obj):
"""Return true if the object is an asynchronous generator function.

Asynchronous generator functions are defined with "async def"
syntax and have "yield" expressions in their body.
"""
return bool((isfunction(object) or ismethod(object)) and
object.__code__.co_flags & CO_ASYNC_GENERATOR)
obj = functools._unwrap_partial(obj)
return bool((isfunction(obj) or ismethod(obj)) and
obj.__code__.co_flags & CO_ASYNC_GENERATOR)

def isasyncgen(object):
"""Return true if the object is an asynchronous generator."""
Expand Down
4 changes: 2 additions & 2 deletions Lib/test/test_asyncio/test_tasks.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -440,8 +440,8 @@ async def func(x, y):

coro_repr = repr(task._coro)
expected = (
r'<CoroWrapper \w+.test_task_repr_partial_corowrapper'
r'\.<locals>\.func\(1\)\(\) running, '
r'<coroutine object \w+\.test_task_repr_partial_corowrapper'
r'\.<locals>\.func at'
)
self.assertRegex(coro_repr, expected)

Expand Down
27 changes: 26 additions & 1 deletion Lib/test/test_inspect.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -166,26 +166,51 @@ def test_excluding_predicates(self):
self.assertFalse(inspect.ismemberdescriptor(datetime.timedelta.days))

def test_iscoroutine(self):
async_gen_coro = async_generator_function_example(1)
gen_coro = gen_coroutine_function_example(1)
coro = coroutine_function_example(1)

self.assertFalse(
inspect.iscoroutinefunction(gen_coroutine_function_example))
self.assertFalse(
inspect.iscoroutinefunction(
functools.partial(functools.partial(
gen_coroutine_function_example))))
self.assertFalse(inspect.iscoroutine(gen_coro))

self.assertTrue(
inspect.isgeneratorfunction(gen_coroutine_function_example))
self.assertTrue(
inspect.isgeneratorfunction(
functools.partial(functools.partial(
gen_coroutine_function_example))))
self.assertTrue(inspect.isgenerator(gen_coro))

self.assertTrue(
inspect.iscoroutinefunction(coroutine_function_example))
self.assertTrue(
inspect.iscoroutinefunction(
functools.partial(functools.partial(
coroutine_function_example))))
self.assertTrue(inspect.iscoroutine(coro))

self.assertFalse(
inspect.isgeneratorfunction(coroutine_function_example))
self.assertFalse(
inspect.isgeneratorfunction(
functools.partial(functools.partial(
coroutine_function_example))))
self.assertFalse(inspect.isgenerator(coro))

coro.close(); gen_coro.close() # silence warnings
self.assertTrue(
inspect.isasyncgenfunction(async_generator_function_example))
self.assertTrue(
inspect.isasyncgenfunction(
functools.partial(functools.partial(
async_generator_function_example))))
self.assertTrue(inspect.isasyncgen(async_gen_coro))

coro.close(); gen_coro.close(); # silence warnings

def test_isawaitable(self):
def gen(): yield
Expand Down
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Make :func:`inspect.iscoroutinefunction`,
:func:`inspect.isgeneratorfunction` and :func:`inspect.isasyncgenfunction`
work with :func:`functools.partial`. Patch by Pablo Galindo.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Maybe also document the change with a ".. versionchanged:: 3.8" markup in https://docs.python.org/dev/library/inspect.html#inspect.isgeneratorfunction ?


Back | FazBrowse Home | New Git URL