diff options
author | Christian Tismer <tismer@stackless.com> | 2020-10-07 19:25:47 +0200 |
---|---|---|
committer | Christian Tismer <tismer@stackless.com> | 2020-10-09 22:51:46 +0200 |
commit | 8847a47aad95d7f85d5e184071bf95c44826c4c7 (patch) | |
tree | fa68d8a0f6d481b73d305cbb63ca70d289c4be14 /sources/pyside2/libpyside | |
parent | 9d8a918d35c8de3400a5e0471e37981a2514c96f (diff) |
feature_select: finish properties and postpone static properties
Static properties are not easy to support.
They need an extra property subtype and support in the meta-class.
A problem is that the implementation needs to go deeply into the
innards of things and need to use `_PyType_Lookup`.
That is hard to circumvent when the limited API is used.
Therefore, the current implementation will be it for 5.15 .
At most we might add a few missing properties through XML.
Task-number: PYSIDE-1019
Change-Id: I56a9eabe5f774c1ff04c149227e06318c8bf4f29
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
Diffstat (limited to 'sources/pyside2/libpyside')
-rw-r--r-- | sources/pyside2/libpyside/feature_select.cpp | 79 |
1 files changed, 76 insertions, 3 deletions
diff --git a/sources/pyside2/libpyside/feature_select.cpp b/sources/pyside2/libpyside/feature_select.cpp index b26810add..6a21d168d 100644 --- a/sources/pyside2/libpyside/feature_select.cpp +++ b/sources/pyside2/libpyside/feature_select.cpp @@ -445,6 +445,8 @@ void finalize() Py_DECREF(fast_id_array[idx]); } +static bool patch_property_impl(); + void init() { // This function can be called multiple times. @@ -457,6 +459,7 @@ void init() featurePointer = featureProcArray; initSelectableFeature(SelectFeatureSet); registerCleanupFunction(finalize); + patch_property_impl(); is_initialized = true; } // Reset the cache. This is called at any "from __feature__ import". @@ -551,9 +554,8 @@ static PyObject *createProperty(PyObject *getter, PyObject *setter) assert(getter != nullptr); if (setter == nullptr) setter = Py_None; - PyObject *prop = PyObject_CallObject(reinterpret_cast<PyObject *>(&PyProperty_Type), nullptr); - AutoDecRef args(Py_BuildValue("OO", getter, setter)); - PyProperty_Type.tp_init(prop, args, nullptr); + auto obtype = reinterpret_cast<PyObject *>(&PyProperty_Type); + PyObject *prop = PyObject_CallFunctionObjArgs(obtype, getter, setter, nullptr); return prop; } @@ -635,6 +637,77 @@ static bool feature_02_true_property(PyTypeObject *type, PyObject *prev_dict, in ////////////////////////////////////////////////////////////////////////////// // +// These are a number of patches to make Python's property object better +// suitable for us. +// We turn `__doc__` into a lazy attribute saving signature initialization. +// +// Currently, there is no static extension planned, because _PyType_Lookup +// and Limited_API are hard to use at the same time. +// + +typedef struct { + PyObject_HEAD + PyObject *prop_get; + PyObject *prop_set; + PyObject *prop_del; + PyObject *prop_doc; + int getter_doc; +} propertyobject; + +static PyObject *property_doc_get(PyObject *self, void *) +{ + auto po = reinterpret_cast<propertyobject *>(self); + + if (po->prop_doc != nullptr && po->prop_doc != Py_None) { + Py_INCREF(po->prop_doc); + return po->prop_doc; + } + if (po->prop_get) { + // PYSIDE-1019: Fetch the default `__doc__` from fget. We do it late. + auto txt = PyObject_GetAttr(po->prop_get, PyMagicName::doc()); + if (txt != nullptr) { + Py_INCREF(txt); + po->prop_doc = txt; + Py_INCREF(txt); + return txt; + } + PyErr_Clear(); + } + Py_RETURN_NONE; +} + +static int property_doc_set(PyObject *self, PyObject *value, void *) +{ + auto po = reinterpret_cast<propertyobject *>(self); + + Py_INCREF(value); + po->prop_doc = value; + return 0; +} + +static PyGetSetDef property_getset[] = { + // This gets added to the existing getsets + {const_cast<char *>("__doc__"), property_doc_get, property_doc_set, nullptr, nullptr}, + {nullptr, nullptr, nullptr, nullptr, nullptr} +}; + +static bool patch_property_impl() +{ + // Turn `__doc__` into a computed attribute without changing writability. + auto gsp = property_getset; + auto type = &PyProperty_Type; + auto dict = type->tp_dict; + AutoDecRef descr(PyDescr_NewGetSet(type, gsp)); + if (descr.isNull()) + return false; + if (PyDict_SetItemString(dict, gsp->name, descr) < 0) + return false; + // Replace property_descr_get/set by slightly changed versions + return true; +} + +////////////////////////////////////////////////////////////////////////////// +// // PYSIDE-1019: Support switchable extensions // // Feature 0x04..0x40: A fake switchable option for testing |