diff options
Diffstat (limited to 'Lib')
| -rw-r--r-- | Lib/functools.py | 6 | ||||
| -rw-r--r-- | Lib/inspect.py | 21 | ||||
| -rw-r--r-- | Lib/test/test_asyncio/test_tasks.py | 4 | ||||
| -rw-r--r-- | Lib/test/test_inspect.py | 27 |
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 |
