Skip to content

Commit 1c4e6b9

Browse files
committed
gh-142418: Fix inspect.iscoroutinefunction for marked functools.partial and partialmethod objects
1 parent a51db30 commit 1c4e6b9

File tree

3 files changed

+49
-4
lines changed

3 files changed

+49
-4
lines changed

Lib/inspect.py

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -306,10 +306,33 @@ def isgeneratorfunction(obj):
306306
_is_coroutine_mark = object()
307307

308308
def _has_coroutine_mark(f):
309-
while ismethod(f):
310-
f = f.__func__
311-
f = functools._unwrap_partial(f)
312-
return getattr(f, "_is_coroutine_marker", None) is _is_coroutine_mark
309+
visited = set()
310+
while True:
311+
if id(f) in visited:
312+
return False
313+
visited.add(id(f))
314+
315+
if getattr(f, "_is_coroutine_marker", None) is _is_coroutine_mark:
316+
return True
317+
318+
pm = getattr(f, "__partialmethod__", None)
319+
if isinstance(pm, functools.partialmethod):
320+
f = pm
321+
continue
322+
323+
if isinstance(f, functools.partialmethod):
324+
f = getattr(f, 'func')
325+
continue
326+
327+
if ismethod(f):
328+
f = f.__func__
329+
continue
330+
331+
if isinstance(f, functools.partial):
332+
f = f.func
333+
continue
334+
335+
return False
313336

314337
def markcoroutinefunction(func):
315338
"""

Lib/test/test_inspect/test_inspect.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,27 @@ def do_something_static():
380380

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

383+
def test_marked_partials_are_coroutinefunctions(self):
384+
def regular_function():
385+
pass
386+
387+
marked_partial = inspect.markcoroutinefunction(
388+
functools.partial(regular_function))
389+
self.assertTrue(inspect.iscoroutinefunction(marked_partial))
390+
self.assertFalse(
391+
inspect.iscoroutinefunction(functools.partial(regular_function)))
392+
393+
class PMClass:
394+
def method(self, /):
395+
pass
396+
397+
marked = inspect.markcoroutinefunction(
398+
functools.partialmethod(method))
399+
unmarked = functools.partialmethod(method)
400+
401+
self.assertTrue(inspect.iscoroutinefunction(PMClass.marked))
402+
self.assertFalse(inspect.iscoroutinefunction(PMClass.unmarked))
403+
383404
def test_isawaitable(self):
384405
def gen(): yield
385406
self.assertFalse(inspect.isawaitable(gen()))
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix inspect.iscoroutinefunction() not detecting marked functools.partial or functools.partialmethod objects.

0 commit comments

Comments
 (0)