summaryrefslogtreecommitdiff
path: root/Lib
diff options
context:
space:
mode:
Diffstat (limited to 'Lib')
-rw-r--r--Lib/functools.py6
-rw-r--r--Lib/inspect.py21
-rw-r--r--Lib/test/test_asyncio/test_tasks.py4
-rw-r--r--Lib/test/test_inspect.py27
4 files changed, 46 insertions, 12 deletions
diff --git a/Lib/functools.py b/Lib/functools.py
index 39a4af81d0..ab7d71e126 100644
--- a/Lib/functools.py
+++ b/Lib/functools.py
@@ -423,6 +423,12 @@ class partialmethod(object):
def __isabstractmethod__(self):
return getattr(self.func, "__isabstractmethod__", False)
+# Helper functions
+
+def _unwrap_partial(func):
+ while isinstance(func, partial):
+ func = func.func
+ return func
################################################################################
### LRU Cache function decorator
diff --git a/Lib/inspect.py b/Lib/inspect.py
index 3edf97d389..b8a142232b 100644
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -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."""
diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py
index 0fe767630f..c65d1f2440 100644
--- a/Lib/test/test_asyncio/test_tasks.py
+++ b/Lib/test/test_asyncio/test_tasks.py
@@ -440,8 +440,8 @@ class BaseTaskTests:
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)
diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py
index 134b0cd0b7..b9072e0137 100644
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -166,26 +166,51 @@ class TestPredicates(IsTestBase):
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