task: Also check for subclasses of coroutine

Apparently Nuitka uses custom coroutine classes that inherit from Python's own coroutine class, causing PyCoro_CheckExact to be inadequate

In the future we may want to check the ABC or check the existence of send/throw methods
This commit is contained in:
rdb 2025-11-12 11:40:50 +01:00
parent fd5258fe09
commit 23782ec511
2 changed files with 9 additions and 6 deletions

View File

@ -396,7 +396,7 @@ gather(PyObject *args) {
continue;
}
#if PY_VERSION_HEX >= 0x03050000
} else if (PyCoro_CheckExact(item)) {
} else if (PyObject_TypeCheck(item, &PyCoro_Type)) {
// We allow passing in a coroutine instead of a future. This causes it
// to be scheduled as a task on the current task manager.
PT(AsyncTask) task = new PythonTask(item);

View File

@ -53,15 +53,18 @@ PythonTask(PyObject *func_or_coro, const std::string &name) :
_function = func_or_coro;
Py_INCREF(_function);
#if PY_VERSION_HEX >= 0x03050000
} else if (PyCoro_CheckExact(func_or_coro)) {
// We also allow passing in a coroutine, because why not.
} else if (PyCoro_CheckExact(func_or_coro) ||
PyGen_CheckExact(func_or_coro) ||
PyType_IsSubtype(Py_TYPE(func_or_coro), &PyCoro_Type)) {
// We also allow passing in a coroutine.
_generator = func_or_coro;
Py_INCREF(_generator);
#endif
#else
} else if (PyGen_CheckExact(func_or_coro)) {
// Something emulating a coroutine.
_generator = func_or_coro;
Py_INCREF(_generator);
#endif
} else {
nassert_raise("Invalid function passed to PythonTask");
}
@ -528,7 +531,7 @@ do_python_task() {
Py_DECREF(str);
Py_DECREF(str2);
}
if (PyCoro_CheckExact(result)) {
if (PyObject_TypeCheck(result, &PyCoro_Type)) {
// If a coroutine, am_await is possible but senseless, since we can
// just call send(None) on the coroutine itself.
_generator = result;
@ -624,7 +627,7 @@ do_python_task() {
}
#if PY_VERSION_HEX >= 0x03050000
} else if (result == Py_None && PyCoro_CheckExact(_generator)) {
} else if (result == Py_None && PyObject_TypeCheck(_generator, &PyCoro_Type)) {
// Bare yield from a coroutine means to try again next frame.
Py_DECREF(result);
return DS_cont;