| 109 | } |
| 110 | |
| 111 | PyEventLoop::Future PyEventLoop::ensureFuture(PyObject *awaitable) { |
| 112 | PyObject *asyncio = PyImport_ImportModule("asyncio"); |
| 113 | |
| 114 | PyObject *ensure_future_fn = PyObject_GetAttrString(asyncio, "ensure_future"); // ensure_future_fn = asyncio.ensure_future |
| 115 | // instead of a simpler `PyObject_CallMethod`, only the `PyObject_Call` API function can be used here because `loop` is a keyword-only argument |
| 116 | // see https://docs.python.org/3.9/library/asyncio-future.html#asyncio.ensure_future |
| 117 | // https://docs.python.org/3/c-api/call.html#object-calling-api |
| 118 | PyObject *args = PyTuple_New(1); |
| 119 | PyTuple_SetItem(args, 0, awaitable); |
| 120 | PyObject *kwargs = PyDict_New(); |
| 121 | PyDict_SetItemString(kwargs, "loop", _loop); |
| 122 | PyObject *futureObj = PyObject_Call(ensure_future_fn, args, kwargs); // futureObj = ensure_future_fn(awaitable, loop=_loop) |
| 123 | |
| 124 | // clean up |
| 125 | Py_DECREF(asyncio); |
| 126 | Py_DECREF(ensure_future_fn); |
| 127 | Py_DECREF(args); |
| 128 | Py_DECREF(kwargs); |
| 129 | |
| 130 | Py_INCREF(futureObj); // needs to be kept alive as `PyEventLoop::Future` will decrease the reference count in its destructor |
| 131 | return PyEventLoop::Future(futureObj); |
| 132 | } |
| 133 | |
| 134 | /* static */ |
| 135 | PyEventLoop PyEventLoop::_loopNotFound() { |