| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | #include "Python.h"
 | 
					
						
							| 
									
										
										
										
											2021-10-14 21:53:04 +02:00
										 |  |  | #include "pycore_call.h"          // _PyObject_VectorcallTstate()
 | 
					
						
							| 
									
										
										
										
											2018-11-01 00:52:28 +01:00
										 |  |  | #include "pycore_context.h"
 | 
					
						
							| 
									
										
										
										
											2024-07-22 12:08:27 -04:00
										 |  |  | #include "pycore_freelist.h"      // _Py_FREELIST_FREE(), _Py_FREELIST_POP()
 | 
					
						
							| 
									
										
										
										
											2020-04-14 17:52:15 +02:00
										 |  |  | #include "pycore_gc.h"            // _PyObject_GC_MAY_BE_TRACKED()
 | 
					
						
							| 
									
										
										
										
											2018-11-01 00:52:28 +01:00
										 |  |  | #include "pycore_hamt.h"
 | 
					
						
							| 
									
										
										
										
											2021-12-09 12:59:26 -07:00
										 |  |  | #include "pycore_initconfig.h"    // _PyStatus_OK()
 | 
					
						
							| 
									
										
										
										
											2018-11-21 22:27:47 +01:00
										 |  |  | #include "pycore_object.h"
 | 
					
						
							| 
									
										
										
										
											2019-11-08 10:05:17 +01:00
										 |  |  | #include "pycore_pyerrors.h"
 | 
					
						
							| 
									
										
										
										
											2020-04-14 17:52:15 +02:00
										 |  |  | #include "pycore_pystate.h"       // _PyThreadState_GET()
 | 
					
						
							| 
									
										
										
										
											2023-07-25 15:28:30 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "clinic/context.c.h"
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | module _contextvars | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | /*[clinic end generated code: output=da39a3ee5e6b4b0d input=a0955718c8b8cea6]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-21 15:33:56 -04:00
										 |  |  | #define ENSURE_Context(o, err_ret)                                  \
 | 
					
						
							|  |  |  |     if (!PyContext_CheckExact(o)) {                                 \ | 
					
						
							|  |  |  |         PyErr_SetString(PyExc_TypeError,                            \ | 
					
						
							|  |  |  |                         "an instance of Context was expected");     \ | 
					
						
							|  |  |  |         return err_ret;                                             \ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define ENSURE_ContextVar(o, err_ret)                               \
 | 
					
						
							|  |  |  |     if (!PyContextVar_CheckExact(o)) {                              \ | 
					
						
							|  |  |  |         PyErr_SetString(PyExc_TypeError,                            \ | 
					
						
							|  |  |  |                        "an instance of ContextVar was expected");   \ | 
					
						
							|  |  |  |         return err_ret;                                             \ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define ENSURE_ContextToken(o, err_ret)                             \
 | 
					
						
							|  |  |  |     if (!PyContextToken_CheckExact(o)) {                            \ | 
					
						
							|  |  |  |         PyErr_SetString(PyExc_TypeError,                            \ | 
					
						
							|  |  |  |                         "an instance of Token was expected");       \ | 
					
						
							|  |  |  |         return err_ret;                                             \ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | /////////////////////////// Context API
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyContext * | 
					
						
							|  |  |  | context_new_empty(void); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyContext * | 
					
						
							|  |  |  | context_new_from_vars(PyHamtObject *vars); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline PyContext * | 
					
						
							|  |  |  | context_get(void); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyContextToken * | 
					
						
							|  |  |  | token_new(PyContext *ctx, PyContextVar *var, PyObject *val); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyContextVar * | 
					
						
							|  |  |  | contextvar_new(PyObject *name, PyObject *def); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | contextvar_set(PyContextVar *var, PyObject *val); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | contextvar_del(PyContextVar *var); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyObject * | 
					
						
							|  |  |  | _PyContext_NewHamtForTests(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return (PyObject *)_PyHamt_New(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-21 15:33:56 -04:00
										 |  |  | PyObject * | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | PyContext_New(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-09-21 15:33:56 -04:00
										 |  |  |     return (PyObject *)context_new_empty(); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-21 15:33:56 -04:00
										 |  |  | PyObject * | 
					
						
							|  |  |  | PyContext_Copy(PyObject * octx) | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-09-21 15:33:56 -04:00
										 |  |  |     ENSURE_Context(octx, NULL) | 
					
						
							|  |  |  |     PyContext *ctx = (PyContext *)octx; | 
					
						
							|  |  |  |     return (PyObject *)context_new_from_vars(ctx->ctx_vars); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-21 15:33:56 -04:00
										 |  |  | PyObject * | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | PyContext_CopyCurrent(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PyContext *ctx = context_get(); | 
					
						
							|  |  |  |     if (ctx == NULL) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-21 15:33:56 -04:00
										 |  |  |     return (PyObject *)context_new_from_vars(ctx->ctx_vars); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-23 20:40:17 -07:00
										 |  |  | static const char * | 
					
						
							|  |  |  | context_event_name(PyContextEvent event) { | 
					
						
							|  |  |  |     switch (event) { | 
					
						
							| 
									
										
										
										
											2024-10-16 14:53:21 +03:00
										 |  |  |         case Py_CONTEXT_SWITCHED: | 
					
						
							|  |  |  |             return "Py_CONTEXT_SWITCHED"; | 
					
						
							| 
									
										
										
										
											2024-09-23 20:40:17 -07:00
										 |  |  |         default: | 
					
						
							|  |  |  |             return "?"; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     Py_UNREACHABLE(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-12 15:33:00 -04:00
										 |  |  | static void | 
					
						
							| 
									
										
										
										
											2024-10-12 16:57:27 -04:00
										 |  |  | notify_context_watchers(PyThreadState *ts, PyContextEvent event, PyObject *ctx) | 
					
						
							| 
									
										
										
										
											2024-09-23 20:40:17 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-10-16 14:53:21 +03:00
										 |  |  |     if (ctx == NULL) { | 
					
						
							|  |  |  |         // This will happen after exiting the last context in the stack, which
 | 
					
						
							|  |  |  |         // can occur if context_get was never called before entering a context
 | 
					
						
							|  |  |  |         // (e.g., called `contextvars.Context().run()` on a fresh thread, as
 | 
					
						
							|  |  |  |         // PyContext_Enter doesn't call context_get).
 | 
					
						
							|  |  |  |         ctx = Py_None; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-09-23 20:40:17 -07:00
										 |  |  |     assert(Py_REFCNT(ctx) > 0); | 
					
						
							| 
									
										
										
										
											2024-09-25 22:26:23 -07:00
										 |  |  |     PyInterpreterState *interp = ts->interp; | 
					
						
							| 
									
										
										
										
											2024-09-23 20:40:17 -07:00
										 |  |  |     assert(interp->_initialized); | 
					
						
							|  |  |  |     uint8_t bits = interp->active_context_watchers; | 
					
						
							|  |  |  |     int i = 0; | 
					
						
							|  |  |  |     while (bits) { | 
					
						
							|  |  |  |         assert(i < CONTEXT_MAX_WATCHERS); | 
					
						
							|  |  |  |         if (bits & 1) { | 
					
						
							|  |  |  |             PyContext_WatchCallback cb = interp->context_watchers[i]; | 
					
						
							|  |  |  |             assert(cb != NULL); | 
					
						
							|  |  |  |             if (cb(event, ctx) < 0) { | 
					
						
							|  |  |  |                 PyErr_FormatUnraisable( | 
					
						
							|  |  |  |                     "Exception ignored in %s watcher callback for %R", | 
					
						
							|  |  |  |                     context_event_name(event), ctx); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         i++; | 
					
						
							|  |  |  |         bits >>= 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | PyContext_AddWatcher(PyContext_WatchCallback callback) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PyInterpreterState *interp = _PyInterpreterState_GET(); | 
					
						
							|  |  |  |     assert(interp->_initialized); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (int i = 0; i < CONTEXT_MAX_WATCHERS; i++) { | 
					
						
							|  |  |  |         if (!interp->context_watchers[i]) { | 
					
						
							|  |  |  |             interp->context_watchers[i] = callback; | 
					
						
							|  |  |  |             interp->active_context_watchers |= (1 << i); | 
					
						
							|  |  |  |             return i; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     PyErr_SetString(PyExc_RuntimeError, "no more context watcher IDs available"); | 
					
						
							|  |  |  |     return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | PyContext_ClearWatcher(int watcher_id) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PyInterpreterState *interp = _PyInterpreterState_GET(); | 
					
						
							|  |  |  |     assert(interp->_initialized); | 
					
						
							|  |  |  |     if (watcher_id < 0 || watcher_id >= CONTEXT_MAX_WATCHERS) { | 
					
						
							|  |  |  |         PyErr_Format(PyExc_ValueError, "Invalid context watcher ID %d", watcher_id); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!interp->context_watchers[watcher_id]) { | 
					
						
							|  |  |  |         PyErr_Format(PyExc_ValueError, "No context watcher set for ID %d", watcher_id); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     interp->context_watchers[watcher_id] = NULL; | 
					
						
							|  |  |  |     interp->active_context_watchers &= ~(1 << watcher_id); | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-16 14:53:21 +03:00
										 |  |  | static inline void | 
					
						
							|  |  |  | context_switched(PyThreadState *ts) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ts->context_ver++; | 
					
						
							|  |  |  |     // ts->context is used instead of context_get() because context_get() might
 | 
					
						
							|  |  |  |     // throw if ts->context is NULL.
 | 
					
						
							|  |  |  |     notify_context_watchers(ts, Py_CONTEXT_SWITCHED, ts->context); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-08 10:05:17 +01:00
										 |  |  | static int | 
					
						
							|  |  |  | _PyContext_Enter(PyThreadState *ts, PyObject *octx) | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-09-21 15:33:56 -04:00
										 |  |  |     ENSURE_Context(octx, -1) | 
					
						
							|  |  |  |     PyContext *ctx = (PyContext *)octx; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     if (ctx->ctx_entered) { | 
					
						
							| 
									
										
										
										
											2019-11-08 10:05:17 +01:00
										 |  |  |         _PyErr_Format(ts, PyExc_RuntimeError, | 
					
						
							|  |  |  |                       "cannot enter context: %R is already entered", ctx); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ctx->ctx_prev = (PyContext *)ts->context;  /* borrow */ | 
					
						
							|  |  |  |     ctx->ctx_entered = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-10 11:23:36 +01:00
										 |  |  |     ts->context = Py_NewRef(ctx); | 
					
						
							| 
									
										
										
										
											2024-10-16 14:53:21 +03:00
										 |  |  |     context_switched(ts); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							| 
									
										
										
										
											2019-11-08 10:05:17 +01:00
										 |  |  | PyContext_Enter(PyObject *octx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PyThreadState *ts = _PyThreadState_GET(); | 
					
						
							|  |  |  |     assert(ts != NULL); | 
					
						
							|  |  |  |     return _PyContext_Enter(ts, octx); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | _PyContext_Exit(PyThreadState *ts, PyObject *octx) | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-09-21 15:33:56 -04:00
										 |  |  |     ENSURE_Context(octx, -1) | 
					
						
							|  |  |  |     PyContext *ctx = (PyContext *)octx; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     if (!ctx->ctx_entered) { | 
					
						
							|  |  |  |         PyErr_Format(PyExc_RuntimeError, | 
					
						
							|  |  |  |                      "cannot exit context: %R has not been entered", ctx); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (ts->context != (PyObject *)ctx) { | 
					
						
							|  |  |  |         /* Can only happen if someone misuses the C API */ | 
					
						
							|  |  |  |         PyErr_SetString(PyExc_RuntimeError, | 
					
						
							|  |  |  |                         "cannot exit context: thread state references " | 
					
						
							|  |  |  |                         "a different context object"); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Py_SETREF(ts->context, (PyObject *)ctx->ctx_prev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ctx->ctx_prev = NULL; | 
					
						
							|  |  |  |     ctx->ctx_entered = 0; | 
					
						
							| 
									
										
										
										
											2024-10-16 14:53:21 +03:00
										 |  |  |     context_switched(ts); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-08 10:05:17 +01:00
										 |  |  | int | 
					
						
							|  |  |  | PyContext_Exit(PyObject *octx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PyThreadState *ts = _PyThreadState_GET(); | 
					
						
							|  |  |  |     assert(ts != NULL); | 
					
						
							|  |  |  |     return _PyContext_Exit(ts, octx); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-21 15:33:56 -04:00
										 |  |  | PyObject * | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | PyContextVar_New(const char *name, PyObject *def) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PyObject *pyname = PyUnicode_FromString(name); | 
					
						
							|  |  |  |     if (pyname == NULL) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-01-25 14:18:55 -05:00
										 |  |  |     PyContextVar *var = contextvar_new(pyname, def); | 
					
						
							|  |  |  |     Py_DECREF(pyname); | 
					
						
							| 
									
										
										
										
											2018-09-21 15:33:56 -04:00
										 |  |  |     return (PyObject *)var; | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							| 
									
										
										
										
											2018-09-21 15:33:56 -04:00
										 |  |  | PyContextVar_Get(PyObject *ovar, PyObject *def, PyObject **val) | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-09-21 15:33:56 -04:00
										 |  |  |     ENSURE_ContextVar(ovar, -1) | 
					
						
							|  |  |  |     PyContextVar *var = (PyContextVar *)ovar; | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-01 01:51:40 +01:00
										 |  |  |     PyThreadState *ts = _PyThreadState_GET(); | 
					
						
							| 
									
										
										
										
											2018-01-26 17:24:52 -05:00
										 |  |  |     assert(ts != NULL); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     if (ts->context == NULL) { | 
					
						
							|  |  |  |         goto not_found; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-16 02:57:58 +08:00
										 |  |  | #ifndef Py_GIL_DISABLED
 | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     if (var->var_cached != NULL && | 
					
						
							|  |  |  |             var->var_cached_tsid == ts->id && | 
					
						
							|  |  |  |             var->var_cached_tsver == ts->context_ver) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         *val = var->var_cached; | 
					
						
							|  |  |  |         goto found; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-07-16 02:57:58 +08:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     assert(PyContext_CheckExact(ts->context)); | 
					
						
							|  |  |  |     PyHamtObject *vars = ((PyContext *)ts->context)->ctx_vars; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     PyObject *found = NULL; | 
					
						
							|  |  |  |     int res = _PyHamt_Find(vars, (PyObject*)var, &found); | 
					
						
							|  |  |  |     if (res < 0) { | 
					
						
							|  |  |  |         goto error; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (res == 1) { | 
					
						
							|  |  |  |         assert(found != NULL); | 
					
						
							| 
									
										
										
										
											2024-07-16 02:57:58 +08:00
										 |  |  | #ifndef Py_GIL_DISABLED
 | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |         var->var_cached = found;  /* borrow */ | 
					
						
							|  |  |  |         var->var_cached_tsid = ts->id; | 
					
						
							|  |  |  |         var->var_cached_tsver = ts->context_ver; | 
					
						
							| 
									
										
										
										
											2024-07-16 02:57:58 +08:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         *val = found; | 
					
						
							|  |  |  |         goto found; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | not_found: | 
					
						
							|  |  |  |     if (def == NULL) { | 
					
						
							|  |  |  |         if (var->var_default != NULL) { | 
					
						
							|  |  |  |             *val = var->var_default; | 
					
						
							|  |  |  |             goto found; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         *val = NULL; | 
					
						
							|  |  |  |         goto found; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         *val = def; | 
					
						
							|  |  |  |         goto found; | 
					
						
							|  |  |  |    } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | found: | 
					
						
							|  |  |  |     Py_XINCREF(*val); | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | error: | 
					
						
							|  |  |  |     *val = NULL; | 
					
						
							|  |  |  |     return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-21 15:33:56 -04:00
										 |  |  | PyObject * | 
					
						
							|  |  |  | PyContextVar_Set(PyObject *ovar, PyObject *val) | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-09-21 15:33:56 -04:00
										 |  |  |     ENSURE_ContextVar(ovar, NULL) | 
					
						
							|  |  |  |     PyContextVar *var = (PyContextVar *)ovar; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     if (!PyContextVar_CheckExact(var)) { | 
					
						
							|  |  |  |         PyErr_SetString( | 
					
						
							|  |  |  |             PyExc_TypeError, "an instance of ContextVar was expected"); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     PyContext *ctx = context_get(); | 
					
						
							|  |  |  |     if (ctx == NULL) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     PyObject *old_val = NULL; | 
					
						
							|  |  |  |     int found = _PyHamt_Find(ctx->ctx_vars, (PyObject *)var, &old_val); | 
					
						
							|  |  |  |     if (found < 0) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Py_XINCREF(old_val); | 
					
						
							|  |  |  |     PyContextToken *tok = token_new(ctx, var, old_val); | 
					
						
							|  |  |  |     Py_XDECREF(old_val); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (contextvar_set(var, val)) { | 
					
						
							|  |  |  |         Py_DECREF(tok); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-21 15:33:56 -04:00
										 |  |  |     return (PyObject *)tok; | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							| 
									
										
										
										
											2018-09-21 15:33:56 -04:00
										 |  |  | PyContextVar_Reset(PyObject *ovar, PyObject *otok) | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-09-21 15:33:56 -04:00
										 |  |  |     ENSURE_ContextVar(ovar, -1) | 
					
						
							|  |  |  |     ENSURE_ContextToken(otok, -1) | 
					
						
							|  |  |  |     PyContextVar *var = (PyContextVar *)ovar; | 
					
						
							|  |  |  |     PyContextToken *tok = (PyContextToken *)otok; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     if (tok->tok_used) { | 
					
						
							|  |  |  |         PyErr_Format(PyExc_RuntimeError, | 
					
						
							|  |  |  |                      "%R has already been used once", tok); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (var != tok->tok_var) { | 
					
						
							|  |  |  |         PyErr_Format(PyExc_ValueError, | 
					
						
							|  |  |  |                      "%R was created by a different ContextVar", tok); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     PyContext *ctx = context_get(); | 
					
						
							|  |  |  |     if (ctx != tok->tok_ctx) { | 
					
						
							|  |  |  |         PyErr_Format(PyExc_ValueError, | 
					
						
							|  |  |  |                      "%R was created in a different Context", tok); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     tok->tok_used = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (tok->tok_oldval == NULL) { | 
					
						
							|  |  |  |         return contextvar_del(var); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         return contextvar_set(var, tok->tok_oldval); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /////////////////////////// PyContext
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | class _contextvars.Context "PyContext *" "&PyContext_Type" | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | /*[clinic end generated code: output=da39a3ee5e6b4b0d input=bdf87f8e0cb580e8]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  | #define _PyContext_CAST(op)     ((PyContext *)(op))
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | static inline PyContext * | 
					
						
							|  |  |  | _context_alloc(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-07-22 12:08:27 -04:00
										 |  |  |     PyContext *ctx = _Py_FREELIST_POP(PyContext, contexts); | 
					
						
							|  |  |  |     if (ctx == NULL) { | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |         ctx = PyObject_GC_New(PyContext, &PyContext_Type); | 
					
						
							|  |  |  |         if (ctx == NULL) { | 
					
						
							|  |  |  |             return NULL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ctx->ctx_vars = NULL; | 
					
						
							|  |  |  |     ctx->ctx_prev = NULL; | 
					
						
							|  |  |  |     ctx->ctx_entered = 0; | 
					
						
							|  |  |  |     ctx->ctx_weakreflist = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return ctx; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyContext * | 
					
						
							|  |  |  | context_new_empty(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PyContext *ctx = _context_alloc(); | 
					
						
							|  |  |  |     if (ctx == NULL) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ctx->ctx_vars = _PyHamt_New(); | 
					
						
							|  |  |  |     if (ctx->ctx_vars == NULL) { | 
					
						
							|  |  |  |         Py_DECREF(ctx); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _PyObject_GC_TRACK(ctx); | 
					
						
							|  |  |  |     return ctx; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyContext * | 
					
						
							|  |  |  | context_new_from_vars(PyHamtObject *vars) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PyContext *ctx = _context_alloc(); | 
					
						
							|  |  |  |     if (ctx == NULL) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-10 11:23:36 +01:00
										 |  |  |     ctx->ctx_vars = (PyHamtObject*)Py_NewRef(vars); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     _PyObject_GC_TRACK(ctx); | 
					
						
							|  |  |  |     return ctx; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline PyContext * | 
					
						
							|  |  |  | context_get(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-11-01 01:51:40 +01:00
										 |  |  |     PyThreadState *ts = _PyThreadState_GET(); | 
					
						
							| 
									
										
										
										
											2018-01-27 13:24:20 -05:00
										 |  |  |     assert(ts != NULL); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     PyContext *current_ctx = (PyContext *)ts->context; | 
					
						
							|  |  |  |     if (current_ctx == NULL) { | 
					
						
							|  |  |  |         current_ctx = context_new_empty(); | 
					
						
							|  |  |  |         if (current_ctx == NULL) { | 
					
						
							|  |  |  |             return NULL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         ts->context = (PyObject *)current_ctx; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return current_ctx; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | context_check_key_type(PyObject *key) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!PyContextVar_CheckExact(key)) { | 
					
						
							|  |  |  |         // abort();
 | 
					
						
							|  |  |  |         PyErr_Format(PyExc_TypeError, | 
					
						
							|  |  |  |                      "a ContextVar key was expected, got %R", key); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | context_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (PyTuple_Size(args) || (kwds != NULL && PyDict_Size(kwds))) { | 
					
						
							|  |  |  |         PyErr_SetString( | 
					
						
							|  |  |  |             PyExc_TypeError, "Context() does not accept any arguments"); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-09-21 15:33:56 -04:00
										 |  |  |     return PyContext_New(); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  | context_tp_clear(PyObject *op) | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     PyContext *self = _PyContext_CAST(op); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     Py_CLEAR(self->ctx_prev); | 
					
						
							|  |  |  |     Py_CLEAR(self->ctx_vars); | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  | context_tp_traverse(PyObject *op, visitproc visit, void *arg) | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     PyContext *self = _PyContext_CAST(op); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     Py_VISIT(self->ctx_prev); | 
					
						
							|  |  |  |     Py_VISIT(self->ctx_vars); | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  | context_tp_dealloc(PyObject *self) | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							|  |  |  |     _PyObject_GC_UNTRACK(self); | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     PyContext *ctx = _PyContext_CAST(self); | 
					
						
							|  |  |  |     if (ctx->ctx_weakreflist != NULL) { | 
					
						
							|  |  |  |         PyObject_ClearWeakRefs(self); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     } | 
					
						
							|  |  |  |     (void)context_tp_clear(self); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-22 12:08:27 -04:00
										 |  |  |     _Py_FREELIST_FREE(contexts, self, Py_TYPE(self)->tp_free); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  | context_tp_iter(PyObject *op) | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     PyContext *self = _PyContext_CAST(op); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     return _PyHamt_NewIterKeys(self->ctx_vars); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | context_tp_richcompare(PyObject *v, PyObject *w, int op) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!PyContext_CheckExact(v) || !PyContext_CheckExact(w) || | 
					
						
							|  |  |  |             (op != Py_EQ && op != Py_NE)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         Py_RETURN_NOTIMPLEMENTED; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int res = _PyHamt_Eq( | 
					
						
							|  |  |  |         ((PyContext *)v)->ctx_vars, ((PyContext *)w)->ctx_vars); | 
					
						
							|  |  |  |     if (res < 0) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (op == Py_NE) { | 
					
						
							|  |  |  |         res = !res; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (res) { | 
					
						
							|  |  |  |         Py_RETURN_TRUE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         Py_RETURN_FALSE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static Py_ssize_t | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  | context_tp_len(PyObject *op) | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     PyContext *self = _PyContext_CAST(op); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     return _PyHamt_Len(self->ctx_vars); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  | context_tp_subscript(PyObject *op, PyObject *key) | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							|  |  |  |     if (context_check_key_type(key)) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     PyObject *val = NULL; | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     PyContext *self = _PyContext_CAST(op); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     int found = _PyHamt_Find(self->ctx_vars, key, &val); | 
					
						
							|  |  |  |     if (found < 0) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (found == 0) { | 
					
						
							|  |  |  |         PyErr_SetObject(PyExc_KeyError, key); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-11-10 11:23:36 +01:00
										 |  |  |     return Py_NewRef(val); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  | context_tp_contains(PyObject *op, PyObject *key) | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							|  |  |  |     if (context_check_key_type(key)) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     PyObject *val = NULL; | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     PyContext *self = _PyContext_CAST(op); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     return _PyHamt_Find(self->ctx_vars, key, &val); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | _contextvars.Context.get | 
					
						
							|  |  |  |     key: object | 
					
						
							|  |  |  |     default: object = None | 
					
						
							|  |  |  |     / | 
					
						
							| 
									
										
										
										
											2018-07-30 16:15:44 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | Return the value for `key` if `key` has the value in the context object. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | If `key` does not exist, return `default`. If `default` is not given, | 
					
						
							|  |  |  | return None. | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | _contextvars_Context_get_impl(PyContext *self, PyObject *key, | 
					
						
							|  |  |  |                               PyObject *default_value) | 
					
						
							| 
									
										
										
										
											2018-07-30 16:15:44 +01:00
										 |  |  | /*[clinic end generated code: output=0c54aa7664268189 input=c8eeb81505023995]*/ | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							|  |  |  |     if (context_check_key_type(key)) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     PyObject *val = NULL; | 
					
						
							|  |  |  |     int found = _PyHamt_Find(self->ctx_vars, key, &val); | 
					
						
							|  |  |  |     if (found < 0) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (found == 0) { | 
					
						
							| 
									
										
										
										
											2022-11-10 11:23:36 +01:00
										 |  |  |         return Py_NewRef(default_value); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-11-10 11:23:36 +01:00
										 |  |  |     return Py_NewRef(val); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | _contextvars.Context.items | 
					
						
							| 
									
										
										
										
											2018-07-30 16:15:44 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | Return all variables and their values in the context object. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The result is returned as a list of 2-tuples (variable, value). | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | _contextvars_Context_items_impl(PyContext *self) | 
					
						
							| 
									
										
										
										
											2018-07-30 16:15:44 +01:00
										 |  |  | /*[clinic end generated code: output=fa1655c8a08502af input=00db64ae379f9f42]*/ | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							|  |  |  |     return _PyHamt_NewIterItems(self->ctx_vars); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | _contextvars.Context.keys | 
					
						
							| 
									
										
										
										
											2018-07-30 16:15:44 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | Return a list of all variables in the context object. | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | _contextvars_Context_keys_impl(PyContext *self) | 
					
						
							| 
									
										
										
										
											2018-07-30 16:15:44 +01:00
										 |  |  | /*[clinic end generated code: output=177227c6b63ec0e2 input=114b53aebca3449c]*/ | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							|  |  |  |     return _PyHamt_NewIterKeys(self->ctx_vars); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | _contextvars.Context.values | 
					
						
							| 
									
										
										
										
											2018-07-30 16:15:44 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-25 07:18:48 +08:00
										 |  |  | Return a list of all variables' values in the context object. | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | _contextvars_Context_values_impl(PyContext *self) | 
					
						
							| 
									
										
										
										
											2019-02-25 07:18:48 +08:00
										 |  |  | /*[clinic end generated code: output=d286dabfc8db6dde input=ce8075d04a6ea526]*/ | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							|  |  |  |     return _PyHamt_NewIterValues(self->ctx_vars); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | _contextvars.Context.copy | 
					
						
							| 
									
										
										
										
											2018-07-30 16:15:44 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | Return a shallow copy of the context object. | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | _contextvars_Context_copy_impl(PyContext *self) | 
					
						
							| 
									
										
										
										
											2018-07-30 16:15:44 +01:00
										 |  |  | /*[clinic end generated code: output=30ba8896c4707a15 input=ebafdbdd9c72d592]*/ | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							|  |  |  |     return (PyObject *)context_new_from_vars(self->ctx_vars); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  | context_run(PyObject *self, PyObject *const *args, | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |             Py_ssize_t nargs, PyObject *kwnames) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-11-08 10:05:17 +01:00
										 |  |  |     PyThreadState *ts = _PyThreadState_GET(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     if (nargs < 1) { | 
					
						
							| 
									
										
										
										
											2019-11-08 10:05:17 +01:00
										 |  |  |         _PyErr_SetString(ts, PyExc_TypeError, | 
					
						
							|  |  |  |                          "run() missing 1 required positional argument"); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     if (_PyContext_Enter(ts, self)) { | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-08 10:05:17 +01:00
										 |  |  |     PyObject *call_result = _PyObject_VectorcallTstate( | 
					
						
							|  |  |  |         ts, args[0], args + 1, nargs - 1, kwnames); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     if (_PyContext_Exit(ts, self)) { | 
					
						
							| 
									
										
										
										
											2024-06-21 12:28:19 -05:00
										 |  |  |         Py_XDECREF(call_result); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return call_result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyMethodDef PyContext_methods[] = { | 
					
						
							|  |  |  |     _CONTEXTVARS_CONTEXT_GET_METHODDEF | 
					
						
							|  |  |  |     _CONTEXTVARS_CONTEXT_ITEMS_METHODDEF | 
					
						
							|  |  |  |     _CONTEXTVARS_CONTEXT_KEYS_METHODDEF | 
					
						
							|  |  |  |     _CONTEXTVARS_CONTEXT_VALUES_METHODDEF | 
					
						
							|  |  |  |     _CONTEXTVARS_CONTEXT_COPY_METHODDEF | 
					
						
							| 
									
										
										
										
											2022-03-31 10:02:34 +02:00
										 |  |  |     {"run", _PyCFunction_CAST(context_run), METH_FASTCALL | METH_KEYWORDS, NULL}, | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     {NULL, NULL} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PySequenceMethods PyContext_as_sequence = { | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     .sq_contains = context_tp_contains | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyMappingMethods PyContext_as_mapping = { | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     .mp_length = context_tp_len, | 
					
						
							|  |  |  |     .mp_subscript = context_tp_subscript | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyTypeObject PyContext_Type = { | 
					
						
							|  |  |  |     PyVarObject_HEAD_INIT(&PyType_Type, 0) | 
					
						
							| 
									
										
										
										
											2020-11-04 16:33:55 +01:00
										 |  |  |     "_contextvars.Context", | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     sizeof(PyContext), | 
					
						
							|  |  |  |     .tp_methods = PyContext_methods, | 
					
						
							|  |  |  |     .tp_as_mapping = &PyContext_as_mapping, | 
					
						
							|  |  |  |     .tp_as_sequence = &PyContext_as_sequence, | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     .tp_iter = context_tp_iter, | 
					
						
							|  |  |  |     .tp_dealloc = context_tp_dealloc, | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     .tp_getattro = PyObject_GenericGetAttr, | 
					
						
							|  |  |  |     .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, | 
					
						
							|  |  |  |     .tp_richcompare = context_tp_richcompare, | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     .tp_traverse = context_tp_traverse, | 
					
						
							|  |  |  |     .tp_clear = context_tp_clear, | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     .tp_new = context_tp_new, | 
					
						
							|  |  |  |     .tp_weaklistoffset = offsetof(PyContext, ctx_weakreflist), | 
					
						
							|  |  |  |     .tp_hash = PyObject_HashNotImplemented, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /////////////////////////// ContextVar
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | contextvar_set(PyContextVar *var, PyObject *val) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-07-16 02:57:58 +08:00
										 |  |  | #ifndef Py_GIL_DISABLED
 | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     var->var_cached = NULL; | 
					
						
							| 
									
										
										
										
											2021-10-13 14:09:13 +02:00
										 |  |  |     PyThreadState *ts = _PyThreadState_GET(); | 
					
						
							| 
									
										
										
										
											2024-07-16 02:57:58 +08:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     PyContext *ctx = context_get(); | 
					
						
							|  |  |  |     if (ctx == NULL) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     PyHamtObject *new_vars = _PyHamt_Assoc( | 
					
						
							|  |  |  |         ctx->ctx_vars, (PyObject *)var, val); | 
					
						
							|  |  |  |     if (new_vars == NULL) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Py_SETREF(ctx->ctx_vars, new_vars); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-16 02:57:58 +08:00
										 |  |  | #ifndef Py_GIL_DISABLED
 | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     var->var_cached = val;  /* borrow */ | 
					
						
							|  |  |  |     var->var_cached_tsid = ts->id; | 
					
						
							|  |  |  |     var->var_cached_tsver = ts->context_ver; | 
					
						
							| 
									
										
										
										
											2024-07-16 02:57:58 +08:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | contextvar_del(PyContextVar *var) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-07-16 02:57:58 +08:00
										 |  |  | #ifndef Py_GIL_DISABLED
 | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     var->var_cached = NULL; | 
					
						
							| 
									
										
										
										
											2024-07-16 02:57:58 +08:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     PyContext *ctx = context_get(); | 
					
						
							|  |  |  |     if (ctx == NULL) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     PyHamtObject *vars = ctx->ctx_vars; | 
					
						
							|  |  |  |     PyHamtObject *new_vars = _PyHamt_Without(vars, (PyObject *)var); | 
					
						
							|  |  |  |     if (new_vars == NULL) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (vars == new_vars) { | 
					
						
							|  |  |  |         Py_DECREF(new_vars); | 
					
						
							|  |  |  |         PyErr_SetObject(PyExc_LookupError, (PyObject *)var); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Py_SETREF(ctx->ctx_vars, new_vars); | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static Py_hash_t | 
					
						
							|  |  |  | contextvar_generate_hash(void *addr, PyObject *name) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     /* Take hash of `name` and XOR it with the object's addr.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |        The structure of the tree is encoded in objects' hashes, which | 
					
						
							|  |  |  |        means that sufficiently similar hashes would result in tall trees | 
					
						
							|  |  |  |        with many Collision nodes.  Which would, in turn, result in slower | 
					
						
							|  |  |  |        get and set operations. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |        The XORing helps to ensure that: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |        (1) sequentially allocated ContextVar objects have | 
					
						
							|  |  |  |            different hashes; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |        (2) context variables with equal names have | 
					
						
							|  |  |  |            different hashes. | 
					
						
							|  |  |  |     */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Py_hash_t name_hash = PyObject_Hash(name); | 
					
						
							|  |  |  |     if (name_hash == -1) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Py_hash_t res = _Py_HashPointer(addr) ^ name_hash; | 
					
						
							|  |  |  |     return res == -1 ? -2 : res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyContextVar * | 
					
						
							|  |  |  | contextvar_new(PyObject *name, PyObject *def) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!PyUnicode_Check(name)) { | 
					
						
							|  |  |  |         PyErr_SetString(PyExc_TypeError, | 
					
						
							|  |  |  |                         "context variable name must be a str"); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     PyContextVar *var = PyObject_GC_New(PyContextVar, &PyContextVar_Type); | 
					
						
							|  |  |  |     if (var == NULL) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     var->var_hash = contextvar_generate_hash(var, name); | 
					
						
							|  |  |  |     if (var->var_hash == -1) { | 
					
						
							|  |  |  |         Py_DECREF(var); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-10 11:23:36 +01:00
										 |  |  |     var->var_name = Py_NewRef(name); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-10 11:23:36 +01:00
										 |  |  |     var->var_default = Py_XNewRef(def); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-16 02:57:58 +08:00
										 |  |  | #ifndef Py_GIL_DISABLED
 | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     var->var_cached = NULL; | 
					
						
							|  |  |  |     var->var_cached_tsid = 0; | 
					
						
							|  |  |  |     var->var_cached_tsver = 0; | 
					
						
							| 
									
										
										
										
											2024-07-16 02:57:58 +08:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-25 14:18:55 -05:00
										 |  |  |     if (_PyObject_GC_MAY_BE_TRACKED(name) || | 
					
						
							|  |  |  |             (def != NULL && _PyObject_GC_MAY_BE_TRACKED(def))) | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     { | 
					
						
							|  |  |  |         PyObject_GC_Track(var); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return var; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | class _contextvars.ContextVar "PyContextVar *" "&PyContextVar_Type" | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | /*[clinic end generated code: output=da39a3ee5e6b4b0d input=445da935fa8883c3]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  | #define _PyContextVar_CAST(op)  ((PyContextVar *)(op))
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | static PyObject * | 
					
						
							|  |  |  | contextvar_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     static char *kwlist[] = {"", "default", NULL}; | 
					
						
							|  |  |  |     PyObject *name; | 
					
						
							|  |  |  |     PyObject *def = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!PyArg_ParseTupleAndKeywords( | 
					
						
							|  |  |  |             args, kwds, "O|$O:ContextVar", kwlist, &name, &def)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return (PyObject *)contextvar_new(name, def); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  | contextvar_tp_clear(PyObject *op) | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     PyContextVar *self = _PyContextVar_CAST(op); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     Py_CLEAR(self->var_name); | 
					
						
							|  |  |  |     Py_CLEAR(self->var_default); | 
					
						
							| 
									
										
										
										
											2024-07-16 02:57:58 +08:00
										 |  |  | #ifndef Py_GIL_DISABLED
 | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     self->var_cached = NULL; | 
					
						
							|  |  |  |     self->var_cached_tsid = 0; | 
					
						
							|  |  |  |     self->var_cached_tsver = 0; | 
					
						
							| 
									
										
										
										
											2024-07-16 02:57:58 +08:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  | contextvar_tp_traverse(PyObject *op, visitproc visit, void *arg) | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     PyContextVar *self = _PyContextVar_CAST(op); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     Py_VISIT(self->var_name); | 
					
						
							|  |  |  |     Py_VISIT(self->var_default); | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  | contextvar_tp_dealloc(PyObject *self) | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							|  |  |  |     PyObject_GC_UnTrack(self); | 
					
						
							|  |  |  |     (void)contextvar_tp_clear(self); | 
					
						
							|  |  |  |     Py_TYPE(self)->tp_free(self); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static Py_hash_t | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  | contextvar_tp_hash(PyObject *op) | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     PyContextVar *self = _PyContextVar_CAST(op); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     return self->var_hash; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  | contextvar_tp_repr(PyObject *op) | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     PyContextVar *self = _PyContextVar_CAST(op); | 
					
						
							| 
									
										
										
										
											2024-06-20 21:56:47 +02:00
										 |  |  |     // Estimation based on the shortest name and default value,
 | 
					
						
							|  |  |  |     // but maximize the pointer size.
 | 
					
						
							|  |  |  |     // "<ContextVar name='a' at 0x1234567812345678>"
 | 
					
						
							|  |  |  |     // "<ContextVar name='a' default=1 at 0x1234567812345678>"
 | 
					
						
							|  |  |  |     Py_ssize_t estimate = self->var_default ? 53 : 43; | 
					
						
							|  |  |  |     PyUnicodeWriter *writer = PyUnicodeWriter_Create(estimate); | 
					
						
							|  |  |  |     if (writer == NULL) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-20 21:56:47 +02:00
										 |  |  |     if (PyUnicodeWriter_WriteUTF8(writer, "<ContextVar name=", 17) < 0) { | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |         goto error; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-06-20 21:56:47 +02:00
										 |  |  |     if (PyUnicodeWriter_WriteRepr(writer, self->var_name) < 0) { | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |         goto error; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (self->var_default != NULL) { | 
					
						
							| 
									
										
										
										
											2024-06-20 21:56:47 +02:00
										 |  |  |         if (PyUnicodeWriter_WriteUTF8(writer, " default=", 9) < 0) { | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |             goto error; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-06-20 21:56:47 +02:00
										 |  |  |         if (PyUnicodeWriter_WriteRepr(writer, self->var_default) < 0) { | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |             goto error; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-20 21:56:47 +02:00
										 |  |  |     if (PyUnicodeWriter_Format(writer, " at %p>", self) < 0) { | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |         goto error; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-06-20 21:56:47 +02:00
										 |  |  |     return PyUnicodeWriter_Finish(writer); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | error: | 
					
						
							| 
									
										
										
										
											2024-06-20 21:56:47 +02:00
										 |  |  |     PyUnicodeWriter_Discard(writer); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | _contextvars.ContextVar.get | 
					
						
							|  |  |  |     default: object = NULL | 
					
						
							|  |  |  |     / | 
					
						
							| 
									
										
										
										
											2018-07-30 16:15:44 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | Return a value for the context variable for the current context. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | If there is no value for the variable in the current context, the method will: | 
					
						
							|  |  |  |  * return the value of the default argument of the method, if provided; or | 
					
						
							|  |  |  |  * return the default value for the context variable, if it was created | 
					
						
							|  |  |  |    with one; or | 
					
						
							|  |  |  |  * raise a LookupError. | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | _contextvars_ContextVar_get_impl(PyContextVar *self, PyObject *default_value) | 
					
						
							| 
									
										
										
										
											2018-07-30 16:15:44 +01:00
										 |  |  | /*[clinic end generated code: output=0746bd0aa2ced7bf input=30aa2ab9e433e401]*/ | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							|  |  |  |     if (!PyContextVar_CheckExact(self)) { | 
					
						
							|  |  |  |         PyErr_SetString( | 
					
						
							|  |  |  |             PyExc_TypeError, "an instance of ContextVar was expected"); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     PyObject *val; | 
					
						
							| 
									
										
										
										
											2018-09-21 15:33:56 -04:00
										 |  |  |     if (PyContextVar_Get((PyObject *)self, default_value, &val) < 0) { | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (val == NULL) { | 
					
						
							|  |  |  |         PyErr_SetObject(PyExc_LookupError, (PyObject *)self); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return val; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | _contextvars.ContextVar.set | 
					
						
							|  |  |  |     value: object | 
					
						
							|  |  |  |     / | 
					
						
							| 
									
										
										
										
											2018-07-30 16:15:44 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | Call to set a new value for the context variable in the current context. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The required value argument is the new value for the context variable. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Returns a Token object that can be used to restore the variable to its previous | 
					
						
							|  |  |  | value via the `ContextVar.reset()` method. | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | _contextvars_ContextVar_set(PyContextVar *self, PyObject *value) | 
					
						
							| 
									
										
										
										
											2018-07-30 16:15:44 +01:00
										 |  |  | /*[clinic end generated code: output=446ed5e820d6d60b input=c0a6887154227453]*/ | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-09-21 15:33:56 -04:00
										 |  |  |     return PyContextVar_Set((PyObject *)self, value); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | _contextvars.ContextVar.reset | 
					
						
							|  |  |  |     token: object | 
					
						
							|  |  |  |     / | 
					
						
							| 
									
										
										
										
											2018-07-30 16:15:44 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | Reset the context variable. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The variable is reset to the value it had before the `ContextVar.set()` that | 
					
						
							|  |  |  | created the token was used. | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | _contextvars_ContextVar_reset(PyContextVar *self, PyObject *token) | 
					
						
							| 
									
										
										
										
											2018-07-30 16:15:44 +01:00
										 |  |  | /*[clinic end generated code: output=d4ee34d0742d62ee input=ebe2881e5af4ffda]*/ | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							|  |  |  |     if (!PyContextToken_CheckExact(token)) { | 
					
						
							|  |  |  |         PyErr_Format(PyExc_TypeError, | 
					
						
							|  |  |  |                      "expected an instance of Token, got %R", token); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-21 15:33:56 -04:00
										 |  |  |     if (PyContextVar_Reset((PyObject *)self, token)) { | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Py_RETURN_NONE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-28 13:20:29 -04:00
										 |  |  | static PyMemberDef PyContextVar_members[] = { | 
					
						
							| 
									
										
										
										
											2023-07-25 15:28:30 +02:00
										 |  |  |     {"name", _Py_T_OBJECT, offsetof(PyContextVar, var_name), Py_READONLY}, | 
					
						
							| 
									
										
										
										
											2018-06-28 13:20:29 -04:00
										 |  |  |     {NULL} | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | static PyMethodDef PyContextVar_methods[] = { | 
					
						
							|  |  |  |     _CONTEXTVARS_CONTEXTVAR_GET_METHODDEF | 
					
						
							|  |  |  |     _CONTEXTVARS_CONTEXTVAR_SET_METHODDEF | 
					
						
							|  |  |  |     _CONTEXTVARS_CONTEXTVAR_RESET_METHODDEF | 
					
						
							| 
									
										
										
										
											2021-09-19 18:05:30 +03:00
										 |  |  |     {"__class_getitem__", Py_GenericAlias, | 
					
						
							| 
									
										
										
										
											2020-04-14 16:14:15 -07:00
										 |  |  |     METH_O|METH_CLASS,       PyDoc_STR("See PEP 585")}, | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     {NULL, NULL} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyTypeObject PyContextVar_Type = { | 
					
						
							|  |  |  |     PyVarObject_HEAD_INIT(&PyType_Type, 0) | 
					
						
							| 
									
										
										
										
											2020-11-04 16:33:55 +01:00
										 |  |  |     "_contextvars.ContextVar", | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     sizeof(PyContextVar), | 
					
						
							|  |  |  |     .tp_methods = PyContextVar_methods, | 
					
						
							| 
									
										
										
										
											2018-06-28 13:20:29 -04:00
										 |  |  |     .tp_members = PyContextVar_members, | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     .tp_dealloc = contextvar_tp_dealloc, | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     .tp_getattro = PyObject_GenericGetAttr, | 
					
						
							|  |  |  |     .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     .tp_traverse = contextvar_tp_traverse, | 
					
						
							|  |  |  |     .tp_clear = contextvar_tp_clear, | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     .tp_new = contextvar_tp_new, | 
					
						
							|  |  |  |     .tp_free = PyObject_GC_Del, | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     .tp_hash = contextvar_tp_hash, | 
					
						
							|  |  |  |     .tp_repr = contextvar_tp_repr, | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /////////////////////////// Token
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * get_token_missing(void); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | class _contextvars.Token "PyContextToken *" "&PyContextToken_Type" | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | /*[clinic end generated code: output=da39a3ee5e6b4b0d input=338a5e2db13d3f5b]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  | #define _PyContextToken_CAST(op)    ((PyContextToken *)(op))
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | static PyObject * | 
					
						
							|  |  |  | token_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PyErr_SetString(PyExc_RuntimeError, | 
					
						
							|  |  |  |                     "Tokens can only be created by ContextVars"); | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  | token_tp_clear(PyObject *op) | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     PyContextToken *self = _PyContextToken_CAST(op); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     Py_CLEAR(self->tok_ctx); | 
					
						
							|  |  |  |     Py_CLEAR(self->tok_var); | 
					
						
							|  |  |  |     Py_CLEAR(self->tok_oldval); | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  | token_tp_traverse(PyObject *op, visitproc visit, void *arg) | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     PyContextToken *self = _PyContextToken_CAST(op); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     Py_VISIT(self->tok_ctx); | 
					
						
							|  |  |  |     Py_VISIT(self->tok_var); | 
					
						
							|  |  |  |     Py_VISIT(self->tok_oldval); | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  | token_tp_dealloc(PyObject *self) | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							|  |  |  |     PyObject_GC_UnTrack(self); | 
					
						
							|  |  |  |     (void)token_tp_clear(self); | 
					
						
							|  |  |  |     Py_TYPE(self)->tp_free(self); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  | token_tp_repr(PyObject *op) | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     PyContextToken *self = _PyContextToken_CAST(op); | 
					
						
							| 
									
										
										
										
											2024-10-10 01:37:14 +02:00
										 |  |  |     PyUnicodeWriter *writer = PyUnicodeWriter_Create(0); | 
					
						
							|  |  |  |     if (writer == NULL) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (PyUnicodeWriter_WriteUTF8(writer, "<Token", 6) < 0) { | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |         goto error; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (self->tok_used) { | 
					
						
							| 
									
										
										
										
											2024-10-10 01:37:14 +02:00
										 |  |  |         if (PyUnicodeWriter_WriteUTF8(writer, " used", 5) < 0) { | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |             goto error; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-10-10 01:37:14 +02:00
										 |  |  |     if (PyUnicodeWriter_WriteUTF8(writer, " var=", 5) < 0) { | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |         goto error; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-10-10 01:37:14 +02:00
										 |  |  |     if (PyUnicodeWriter_WriteRepr(writer, (PyObject *)self->tok_var) < 0) { | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |         goto error; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-10-10 01:37:14 +02:00
										 |  |  |     if (PyUnicodeWriter_Format(writer, " at %p>", self) < 0) { | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |         goto error; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-10-10 01:37:14 +02:00
										 |  |  |     return PyUnicodeWriter_Finish(writer); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | error: | 
					
						
							| 
									
										
										
										
											2024-10-10 01:37:14 +02:00
										 |  |  |     PyUnicodeWriter_Discard(writer); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  | token_get_var(PyObject *op, void *Py_UNUSED(ignored)) | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     PyContextToken *self = _PyContextToken_CAST(op); | 
					
						
							| 
									
										
										
										
											2022-11-10 11:23:36 +01:00
										 |  |  |     return Py_NewRef(self->tok_var);; | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  | token_get_old_value(PyObject *op, void *Py_UNUSED(ignored)) | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     PyContextToken *self = _PyContextToken_CAST(op); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     if (self->tok_oldval == NULL) { | 
					
						
							|  |  |  |         return get_token_missing(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-10 11:23:36 +01:00
										 |  |  |     return Py_NewRef(self->tok_oldval); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyGetSetDef PyContextTokenType_getsetlist[] = { | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     {"var", token_get_var, NULL, NULL}, | 
					
						
							|  |  |  |     {"old_value", token_get_old_value, NULL, NULL}, | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     {NULL} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-14 16:14:15 -07:00
										 |  |  | static PyMethodDef PyContextTokenType_methods[] = { | 
					
						
							| 
									
										
										
										
											2021-09-19 18:05:30 +03:00
										 |  |  |     {"__class_getitem__",    Py_GenericAlias, | 
					
						
							| 
									
										
										
										
											2020-04-14 16:14:15 -07:00
										 |  |  |     METH_O|METH_CLASS,       PyDoc_STR("See PEP 585")}, | 
					
						
							|  |  |  |     {NULL} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | PyTypeObject PyContextToken_Type = { | 
					
						
							|  |  |  |     PyVarObject_HEAD_INIT(&PyType_Type, 0) | 
					
						
							| 
									
										
										
										
											2020-11-04 16:33:55 +01:00
										 |  |  |     "_contextvars.Token", | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     sizeof(PyContextToken), | 
					
						
							| 
									
										
										
										
											2020-04-14 16:14:15 -07:00
										 |  |  |     .tp_methods = PyContextTokenType_methods, | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     .tp_getset = PyContextTokenType_getsetlist, | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     .tp_dealloc = token_tp_dealloc, | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     .tp_getattro = PyObject_GenericGetAttr, | 
					
						
							|  |  |  |     .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     .tp_traverse = token_tp_traverse, | 
					
						
							|  |  |  |     .tp_clear = token_tp_clear, | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     .tp_new = token_tp_new, | 
					
						
							|  |  |  |     .tp_free = PyObject_GC_Del, | 
					
						
							|  |  |  |     .tp_hash = PyObject_HashNotImplemented, | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     .tp_repr = token_tp_repr, | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyContextToken * | 
					
						
							|  |  |  | token_new(PyContext *ctx, PyContextVar *var, PyObject *val) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PyContextToken *tok = PyObject_GC_New(PyContextToken, &PyContextToken_Type); | 
					
						
							|  |  |  |     if (tok == NULL) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-10 11:23:36 +01:00
										 |  |  |     tok->tok_ctx = (PyContext*)Py_NewRef(ctx); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-10 11:23:36 +01:00
										 |  |  |     tok->tok_var = (PyContextVar*)Py_NewRef(var); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-10 11:23:36 +01:00
										 |  |  |     tok->tok_oldval = Py_XNewRef(val); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     tok->tok_used = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     PyObject_GC_Track(tok); | 
					
						
							|  |  |  |     return tok; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /////////////////////////// Token.MISSING
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | context_token_missing_tp_repr(PyObject *self) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return PyUnicode_FromString("<Token.MISSING>"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-16 09:54:28 -07:00
										 |  |  | static void | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  | context_token_missing_tp_dealloc(PyObject *Py_UNUSED(self)) | 
					
						
							| 
									
										
										
										
											2022-11-16 09:54:28 -07:00
										 |  |  | { | 
					
						
							|  |  |  | #ifdef Py_DEBUG
 | 
					
						
							|  |  |  |     /* The singleton is statically allocated. */ | 
					
						
							|  |  |  |     _Py_FatalRefcountError("deallocating the token missing singleton"); | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-22 18:55:48 +01:00
										 |  |  | PyTypeObject _PyContextTokenMissing_Type = { | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     PyVarObject_HEAD_INIT(&PyType_Type, 0) | 
					
						
							|  |  |  |     "Token.MISSING", | 
					
						
							| 
									
										
										
										
											2022-11-16 09:54:28 -07:00
										 |  |  |     sizeof(_PyContextTokenMissing), | 
					
						
							| 
									
										
										
										
											2025-01-08 14:52:27 +01:00
										 |  |  |     .tp_dealloc = context_token_missing_tp_dealloc, | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     .tp_getattro = PyObject_GenericGetAttr, | 
					
						
							|  |  |  |     .tp_flags = Py_TPFLAGS_DEFAULT, | 
					
						
							|  |  |  |     .tp_repr = context_token_missing_tp_repr, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | get_token_missing(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-08-04 16:24:50 -07:00
										 |  |  |     return (PyObject *)&_Py_SINGLETON(context_token_missing); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ///////////////////////////
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-09 12:59:26 -07:00
										 |  |  | PyStatus | 
					
						
							| 
									
										
										
										
											2022-01-22 18:55:48 +01:00
										 |  |  | _PyContext_Init(PyInterpreterState *interp) | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-12-09 12:59:26 -07:00
										 |  |  |     if (!_Py_IsMainInterpreter(interp)) { | 
					
						
							|  |  |  |         return _PyStatus_OK(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     PyObject *missing = get_token_missing(); | 
					
						
							|  |  |  |     if (PyDict_SetItemString( | 
					
						
							| 
									
										
										
										
											2023-05-01 20:34:43 -06:00
										 |  |  |         _PyType_GetDict(&PyContextToken_Type), "MISSING", missing)) | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     { | 
					
						
							|  |  |  |         Py_DECREF(missing); | 
					
						
							| 
									
										
										
										
											2021-12-09 12:59:26 -07:00
										 |  |  |         return _PyStatus_ERR("can't init context types"); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  |     } | 
					
						
							|  |  |  |     Py_DECREF(missing); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-09 12:59:26 -07:00
										 |  |  |     return _PyStatus_OK(); | 
					
						
							| 
									
										
										
										
											2018-01-22 19:11:18 -05:00
										 |  |  | } |