You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add pyawaitable_set* and pyawaitable_get* functions (#28)
Needed for [view.py](https://github.com/ZeroIntensity/view.py) to switch
to the PyPI copy instead of a vendor. `set` functions are generally used
for mutating state between calls, while `get` functions are there
because it's kind of weird to have `set` without `get`.
Copy file name to clipboardExpand all lines: docs/storage.md
+102Lines changed: 102 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -304,8 +304,110 @@ test(PyObject *self, PyObject *coro) // We're back to METH_O!
304
304
}
305
305
```
306
306
307
+
## Getting and Setting
308
+
309
+
In some cases, you might want to overwrite existing saved values (e.g. in a recursive callback). For example, we could have some state information, and want to change that between calls.
310
+
311
+
Let's start in a callback that uses itself recursively:
312
+
313
+
```c
314
+
static int
315
+
callback(PyObject *aw, PyObject *result)
316
+
{
317
+
if (!PyCoro_CheckExact(result)) {
318
+
return 0;
319
+
}
320
+
321
+
if (pyawaitable_await(aw, result, callback, NULL) < 0)
322
+
return -1;
323
+
324
+
return 0;
325
+
}
326
+
327
+
static PyObject *
328
+
test(PyObject *self, PyObject *coro) // We're back to METH_O!
329
+
{
330
+
PyObject *aw = pyawaitable_new();
331
+
332
+
if (pyawaitable_await(aw, coro, callback, NULL) < 0)
333
+
{
334
+
Py_DECREF(aw);
335
+
return NULL;
336
+
}
337
+
338
+
return aw;
339
+
}
340
+
```
341
+
342
+
Theoretically, `callback` could be called an infinite number of times for the same PyAwaitable object, so we don't know what the state of the call is!
343
+
344
+
OK, let's start by saving an integer value:
345
+
346
+
```c
347
+
static PyObject *
348
+
test(PyObject *self, PyObject *coro) // We're back to METH_O!
349
+
{
350
+
PyObject *aw = pyawaitable_new();
351
+
352
+
if (pyawaitable_await(aw, coro, callback, NULL) < 0)
353
+
{
354
+
Py_DECREF(aw);
355
+
return NULL;
356
+
}
357
+
358
+
if (pyawaitable_save_int(aw, 1, 1) < 0)
359
+
{
360
+
Py_DECREF(aw);
361
+
return NULL;
362
+
}
363
+
364
+
return aw;
365
+
}
366
+
```
367
+
368
+
But, so far, we've only learned about _appending_ to the values array, not mutating in place. So, how do we do that? Each of the value arrays have their own get and set functions.
369
+
370
+
In this case, we want `pyawaitable_set_int`:
371
+
372
+
```c
373
+
static int
374
+
callback(PyObject *aw, PyObject *result)
375
+
{
376
+
long value = pyawaitable_get_int(aw, 0);
377
+
if (value == -1 && PyErr_Occurred())
378
+
{
379
+
return -1;
380
+
}
381
+
382
+
if (pyawaitable_set_int(aw, 0, value + 1) < 0)
383
+
{
384
+
return -1;
385
+
}
386
+
387
+
if (!PyCoro_CheckExact(result))
388
+
{
389
+
return 0;
390
+
}
391
+
392
+
if (pyawaitable_await(aw, result, callback, NULL) < 0)
393
+
return -1;
394
+
395
+
return 0;
396
+
}
397
+
```
398
+
399
+
Great! We increment our state for each call!
400
+
401
+
!!! warning "Prefer `unpack` over `get`!"
402
+
403
+
In the above, `pyawaitable_get_int` was used for teaching purposes. `pyawaitable_get_*` functions exist for very niche cases, they shouldn't be preferred over `pyawaitable_unpack_*`!
404
+
307
405
## Next Steps
308
406
309
407
Congratuilations, you now know how to use PyAwaitable! If you're interested in reading about the internals, be sure to take a look at the [scrapped PEP draft](https://gist.github.com/ZeroIntensity/8d32e94b243529c7e1c27349e972d926), where this was originally designed to be part of CPython.
310
408
311
409
Moreover, this project was conceived due to being needed in [view.py](https://github.com/ZeroIntensity/view.py). If you would like to see some very complex examples of PyAwaitable usage, take a look at their [C ASGI implementation](https://github.com/ZeroIntensity/view.py/blob/master/src/_view/app.c#L273), which is powered by PyAwaitable.
0 commit comments