Functions wrapped in :func:`functools.partial` now return ``True`` if the
wrapped function is a Python generator function.
+ .. versionchanged:: 3.13
+ Functions wrapped in :func:`functools.partialmethod` now return ``True``
+ if the wrapped function is a Python generator function.
.. function:: isgenerator(object)
Sync functions marked with :func:`markcoroutinefunction` now return
``True``.
+ .. versionchanged:: 3.13
+ Functions wrapped in :func:`functools.partialmethod` now return ``True``
+ if the wrapped function is a :term:`coroutine function`.
+
.. function:: markcoroutinefunction(func)
Functions wrapped in :func:`functools.partial` now return ``True`` if the
wrapped function is a :term:`asynchronous generator` function.
+ .. versionchanged:: 3.13
+ Functions wrapped in :func:`functools.partialmethod` now return ``True``
+ if the wrapped function is a :term:`coroutine function`.
.. function:: isasyncgen(object)
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
_method.__isabstractmethod__ = self.__isabstractmethod__
- _method._partialmethod = self
+ _method.__partialmethod__ = self
return _method
def __get__(self, obj, cls=None):
func = func.func
return func
+def _unwrap_partialmethod(func):
+ prev = None
+ while func is not prev:
+ prev = func
+ while isinstance(getattr(func, "__partialmethod__", None), partialmethod):
+ func = func.__partialmethod__
+ while isinstance(func, partialmethod):
+ func = getattr(func, 'func')
+ func = _unwrap_partial(func)
+ return func
+
################################################################################
### LRU Cache function decorator
################################################################################
gen_coro = gen_coroutine_function_example(1)
coro = coroutine_function_example(1)
+ class PMClass:
+ async_generator_partialmethod_example = functools.partialmethod(
+ async_generator_function_example)
+ coroutine_partialmethod_example = functools.partialmethod(
+ coroutine_function_example)
+ gen_coroutine_partialmethod_example = functools.partialmethod(
+ gen_coroutine_function_example)
+
+ # partialmethods on the class, bound to an instance
+ pm_instance = PMClass()
+ async_gen_coro_pmi = pm_instance.async_generator_partialmethod_example
+ gen_coro_pmi = pm_instance.gen_coroutine_partialmethod_example
+ coro_pmi = pm_instance.coroutine_partialmethod_example
+
+ # partialmethods on the class, unbound but accessed via the class
+ async_gen_coro_pmc = PMClass.async_generator_partialmethod_example
+ gen_coro_pmc = PMClass.gen_coroutine_partialmethod_example
+ coro_pmc = PMClass.coroutine_partialmethod_example
+
self.assertFalse(
inspect.iscoroutinefunction(gen_coroutine_function_example))
self.assertFalse(
inspect.iscoroutinefunction(
functools.partial(functools.partial(
gen_coroutine_function_example))))
+ self.assertFalse(inspect.iscoroutinefunction(gen_coro_pmi))
+ self.assertFalse(inspect.iscoroutinefunction(gen_coro_pmc))
self.assertFalse(inspect.iscoroutine(gen_coro))
self.assertTrue(
inspect.isgeneratorfunction(
functools.partial(functools.partial(
gen_coroutine_function_example))))
+ self.assertTrue(inspect.isgeneratorfunction(gen_coro_pmi))
+ self.assertTrue(inspect.isgeneratorfunction(gen_coro_pmc))
self.assertTrue(inspect.isgenerator(gen_coro))
async def _fn3():
inspect.iscoroutinefunction(
functools.partial(functools.partial(
coroutine_function_example))))
+ self.assertTrue(inspect.iscoroutinefunction(coro_pmi))
+ self.assertTrue(inspect.iscoroutinefunction(coro_pmc))
self.assertTrue(inspect.iscoroutine(coro))
self.assertFalse(
inspect.isgeneratorfunction(
functools.partial(functools.partial(
coroutine_function_example))))
+ self.assertFalse(inspect.isgeneratorfunction(coro_pmi))
+ self.assertFalse(inspect.isgeneratorfunction(coro_pmc))
self.assertFalse(inspect.isgenerator(coro))
self.assertFalse(
inspect.isasyncgenfunction(
functools.partial(functools.partial(
async_generator_function_example))))
+ self.assertTrue(inspect.isasyncgenfunction(async_gen_coro_pmi))
+ self.assertTrue(inspect.isasyncgenfunction(async_gen_coro_pmc))
self.assertTrue(inspect.isasyncgen(async_gen_coro))
coro.close(); gen_coro.close(); # silence warnings
def test_signature_on_fake_partialmethod(self):
def foo(a): pass
- foo._partialmethod = 'spam'
+ foo.__partialmethod__ = 'spam'
self.assertEqual(str(inspect.signature(foo)), '(a)')
def test_signature_on_decorated(self):