@@ -160,8 +160,8 @@ Using ``async with`` from C
160160---------------------------
161161Unlike the :c:func: `PyAwaitable_AddAwait ` and the :c:func: `PyAwaitable_AddExpr `
162162functions there exists :c:func: `PyAwaitable_AsyncWith ` that will call the
163- ` __aenter__ ` and ` __aexit__ ` members of a class if it implements the Async Context
164- Manager.
163+ :meth: ` ~object. __aenter__ ` and :meth: ` ~object. __aexit__ ` members of a class
164+ if it implements the Async Context Manager.
165165
166166Using this on a type that is designed with `async with ` in mind that automatically
167167cleans up resources when the scope leaves the context manager can be much easier
@@ -177,12 +177,31 @@ than manually making those calls to clean them up.
177177.. note ::
178178
179179 This example uses the `asqlite ` library created by Rapptz to allow using the
180- `sqlite3 ` module from within Asynchronous code safely. It also uses a helper header
181- file called `awaitfunc.h ` from the https://github.com/AraHaan/awaitfunc github
182- repository.
180+ `sqlite3 ` module from within Asynchronous code safely.
183181
184182.. code-block :: c
185183
184+ static PyObject *
185+ _PyObject_GetCallableMethod(PyObject *obj, PyObject *attr_name) {
186+ if (attr_name == NULL) {
187+ // the python string is null.
188+ return NULL;
189+ }
190+
191+ PyObject *method = PyObject_GetAttr(obj, attr_name);
192+ if (!PyCallable_Check(method)) {
193+ Py_DECREF(attr_name);
194+ Py_XDECREF(method);
195+ return NULL;
196+ }
197+
198+ Py_DECREF(attr_name);
199+ return method;
200+ }
201+
202+ #define PyObject_GetCallableMethod(obj, name) _PyObject_GetCallableMethod(_PyObject_CAST(obj), name)
203+ #define PyObject_GetCallableMethodString(obj, name) PyObject_GetCallableMethod(obj, PyUnicode_FromString(name))
204+
186205 static int
187206 add_or_delete_items_cursor_cb(PyObject *awaitable, PyObject *cursor) {
188207 if (cursor != NULL && !Py_IsNone(cursor)) {
@@ -192,11 +211,11 @@ than manually making those calls to clean them up.
192211 return -1;
193212 }
194213
195- if (PyAwaitable_AwaitFunction (awaitable, PyObject_GetCallableMethodString(cursor, "executemany"), "OO", NULL, NULL, PySequence_GetItem(args, 0), PySequence_GetItem(args, 1)) < 0) {
214+ if (PyAwaitable_AddExpr (awaitable, PyObject_CallFunction( PyObject_GetCallableMethodString(cursor, "executemany"), "OO", PySequence_GetItem(args, 0), PySequence_GetItem(args, 1)), NULL, NULL ) < 0) {
196215 return -1;
197216 }
198217
199- if (PyAwaitable_AwaitFunctionNoArgs (awaitable, PyObject_GetCallableMethodString(connection, "commit"), NULL, NULL) < 0) {
218+ if (PyAwaitable_AddExpr (awaitable, PyObject_CallNoArgs( PyObject_GetCallableMethodString(connection, "commit") ), NULL, NULL) < 0) {
200219 return -1;
201220 }
202221
@@ -220,7 +239,7 @@ than manually making those calls to clean them up.
220239 return -1;
221240 }
222241
223- if (PyAwaitable_AsyncWithFunctionNoArgs (awaitable, PyObject_GetCallableMethodString(connection, "cursor"), add_or_delete_items_cursor_cb, NULL) < 0) {
242+ if (PyAwaitable_AsyncWith (awaitable, PyObject_CallNoArgs( PyObject_GetCallableMethodString(connection, "cursor") ), add_or_delete_items_cursor_cb, NULL) < 0) {
224243 return -1;
225244 }
226245
@@ -249,7 +268,7 @@ than manually making those calls to clean them up.
249268 }
250269
251270 DiscordBot_State *state = get_DiscordBot_state(mod);
252- if (PyAwaitable_AsyncWithFunction (awaitable, PyObject_GetCallableMethodString(state->asqliteModule, "connect"), "N", add_or_delete_items_connect_cb, NULL, dbString ) < 0) {
271+ if (PyAwaitable_AsyncWith (awaitable, PyObject_CallFunction( PyObject_GetCallableMethodString(state->asqliteModule, "connect"), "N", dbString), add_or_delete_items_connect_cb, NULL ) < 0) {
253272 Py_XDECREF(awaitable);
254273 return NULL;
255274 }
0 commit comments