Created
October 12, 2025 19:44
-
-
Save Vizonex/9419eeca3e9015b2615fff919a8eba74 to your computer and use it in GitHub Desktop.
propcache under_cached_property CPython Concept for moving propcache over to CPython instead of Cython for higher control over Refs and optimizing performance, this is currently incomplete hence me uploading it here.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* This was a backup plan I had in mind if cimporting propcache from cython gets rejected | |
| My main reason behind trying to force it in CPython or Cython is actually to come up with a new library | |
| that deprecates property types (including cached properties) without needing to write | |
| @deprecated(reason="blah blah blah") | |
| @property | |
| It is easier said as | |
| @deprecated_property(reason="blah blah blah") | |
| and it enhances readability | |
| Adding propcache into this newly made deprecated properties library will help optimize | |
| this section when it comes time for me to subclass | |
| it in cython (if the cimporting idea gets rejected), otherwise I will have to play it dirty and copy and paste all of propcache's | |
| code (it's minimal but rather costly) Licensing is not a concern since I will be using Appache 2.0 / MIT anyways... | |
| */ | |
| #include "Python.h" | |
| typedef struct under_cached_property_object_s { | |
| PyObject_HEAD | |
| PyObject *wrapped; | |
| PyObject *name; | |
| } UnderCachedProperty; | |
| static PyTypeObject UnderCachedProperty_Type; | |
| #define UnderCachedProperty_CAST(op) ((UnderCachedProperty *)(op)) | |
| #define UnderCachedProperty_Check(v) PyObject_TypeCheck(v, &); | |
| static int under_cached_property_init( | |
| UnderCachedProperty* self, | |
| PyObject* args, | |
| PyObject* kw | |
| ){ | |
| PyObject* wrapped; | |
| PyObject* name; | |
| if (!PyArg_ParseTupleAndKeywords(args, kw, "O:__init__", wrapped)){ | |
| return -1; | |
| } | |
| Py_INCREF(wrapped); | |
| self->wrapped = wrapped; | |
| name = PyObject_GetAttrString(wrapped, "__name__"); | |
| if (name == NULL){ | |
| return -1; | |
| } | |
| Py_INCREF(name); | |
| self->name = name; | |
| return 0; | |
| } | |
| /* under_cached_property.__get__ */ | |
| static PyObject * under_cached_property_tp_descr_get(PyObject *op, PyObject *obj, PyObject *type){ | |
| PyObject* cache; | |
| PyObject* val; | |
| UnderCachedProperty* self ; | |
| if (Py_IsNone(obj)){ | |
| Py_INCREF(op); | |
| return op; | |
| }; | |
| cache = PyObject_GetAttrString(obj, "_cache"); | |
| if (cache == NULL){ | |
| return NULL; | |
| } | |
| if (!PyDict_Check(cache)){ | |
| PyErr_Format(PyExc_TypeError, "Excepted _cache to be a dictionary like object not %R", cache); | |
| return NULL; | |
| } | |
| Py_INCREF(cache); | |
| self = UnderCachedProperty_CAST(op); | |
| val = PyDict_GetItem(cache, self->name); | |
| if (val == NULL){ | |
| val = PyObject_CallOneArg(self->wrapped, obj); | |
| if (PyDict_SetItem(cache, self->name, val) < 0){ | |
| Py_DECREF(val); | |
| Py_DECREF(cache); | |
| return NULL; | |
| }; | |
| Py_DECREF(val); | |
| } | |
| Py_DECREF(cache); | |
| return val; | |
| }; | |
| /* under_cached_property.__set__ */ | |
| static int under_cached_property_tp_descr_set(PyObject *self, PyObject *obj, PyObject *value){ | |
| PyErr_SetString(PyExc_AttributeError, "cached property is read-only"); | |
| return -1; | |
| }; | |
| /* under_cached_property memebers */ | |
| static PyObject* under_cached_property_get__doc__(PyObject* self){ | |
| return PyObject_GetAttrString(UnderCachedProperty_CAST(self)->wrapped, "__doc__"); | |
| } | |
| static PyObject* under_cached_property_get_wrapped(PyObject* op){ | |
| PyObject* wrapped = UnderCachedProperty_CAST(op)->wrapped; | |
| Py_INCREF(wrapped); | |
| return wrapped; | |
| } | |
| /* under_cached_property tp_traverse */ | |
| static int under_cached_property_tp_traverse(PyObject *op, visitproc visit, void *arg){ | |
| UnderCachedProperty* self = UnderCachedProperty_CAST(op); | |
| Py_VISIT(self->wrapped); | |
| Py_VISIT(self->name); | |
| return 0; | |
| }; | |
| static int under_cached_property_tp_clear(PyObject* op){ | |
| UnderCachedProperty* self = UnderCachedProperty_CAST(op); | |
| Py_CLEAR(self->name); | |
| Py_CLEAR(self->wrapped); | |
| return 0; | |
| } | |
| static int under_cached_property_tp_dealloc(PyObject* op){ | |
| PyObject_GC_UnTrack(op); | |
| UnderCachedProperty* self = UnderCachedProperty_CAST(op); | |
| Py_CLEAR(self->name); | |
| Py_CLEAR(self->wrapped); | |
| Py_TYPE(op)->tp_free(op); | |
| return 0; | |
| } | |
| static struct PyGetSetDef under_cached_property_getsetdef[] = { | |
| {"__doc__", under_cached_property_get__doc__, 0, 0, 0}, | |
| {"wrapped", under_cached_property_get_wrapped, 0, 0, 0}, | |
| {0, 0, 0, 0, 0} | |
| }; | |
| static PyType_Slot under_cached_property_tp_slots[] = { | |
| {Py_tp_init, under_cached_property_init}, | |
| {Py_tp_descr_get, (void*)(under_cached_property_tp_descr_get)}, | |
| {Py_tp_descr_set, (void*)(under_cached_property_tp_descr_set)}, | |
| {0, NULL}, | |
| }; | |
| // static PyTypeObject UnderCachedProperty_Type = { | |
| // PyVarObject_HEAD_INIT(0, 0) | |
| // "propcache._helpers_c.""under_cached_property", /*tp_name*/ | |
| // sizeof(UnderCachedProperty), /*tp_basicsize*/ | |
| // 0, /*tp_itemsize*/ | |
| // under_cached_property_tp_dealloc, /*tp_dealloc*/ | |
| // #if PY_VERSION_HEX < 0x030800b4 | |
| // 0, /*tp_print*/ | |
| // #endif | |
| // #if PY_VERSION_HEX >= 0x030800b4 | |
| // 0, /*tp_vectorcall_offset*/ | |
| // #endif | |
| // } | |
| // static PyType_Spec under_cached_property_spec = { | |
| // .name = "_helpers_c.under_cached_property", | |
| // .basicsize = sizeof(UnderCachedProperty), | |
| // .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE), | |
| // .slots = un, | |
| // }; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment