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 | |
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>
-rw-r--r-- | sources/pyside2/libpyside/feature_select.cpp | 79 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/pep384impl.cpp | 3 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/pep384impl.h | 2 |
3 files changed, 80 insertions, 4 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 diff --git a/sources/shiboken2/libshiboken/pep384impl.cpp b/sources/shiboken2/libshiboken/pep384impl.cpp index 6e4926370..cb8042561 100644 --- a/sources/shiboken2/libshiboken/pep384impl.cpp +++ b/sources/shiboken2/libshiboken/pep384impl.cpp @@ -95,6 +95,7 @@ static PyMemberDef probe_members[] = { #define probe_tp_members probe_members #define probe_tp_getset probe_getseters #define probe_tp_descr_get make_dummy(10) +#define probe_tp_descr_set make_dummy(18) #define probe_tp_init make_dummy(11) #define probe_tp_alloc make_dummy(12) #define probe_tp_new make_dummy(13) @@ -118,6 +119,7 @@ static PyType_Slot typeprobe_slots[] = { {Py_tp_members, probe_tp_members}, {Py_tp_getset, probe_tp_getset}, {Py_tp_descr_get, probe_tp_descr_get}, + {Py_tp_descr_set, probe_tp_descr_set}, {Py_tp_init, probe_tp_init}, {Py_tp_alloc, probe_tp_alloc}, {Py_tp_new, probe_tp_new}, @@ -167,6 +169,7 @@ check_PyTypeObject_valid() || !PyDict_Check(check->tp_dict) || !PyDict_GetItemString(check->tp_dict, "dummy") || probe_tp_descr_get != check->tp_descr_get + || probe_tp_descr_set != check->tp_descr_set || probe_tp_dictoffset != typetype->tp_dictoffset || probe_tp_init != check->tp_init || probe_tp_alloc != check->tp_alloc diff --git a/sources/shiboken2/libshiboken/pep384impl.h b/sources/shiboken2/libshiboken/pep384impl.h index 4b3e32ea2..7a6f57fcd 100644 --- a/sources/shiboken2/libshiboken/pep384impl.h +++ b/sources/shiboken2/libshiboken/pep384impl.h @@ -115,7 +115,7 @@ typedef struct _typeobject { struct _typeobject *tp_base; PyObject *tp_dict; descrgetfunc tp_descr_get; - void *X33; // descrsetfunc tp_descr_set; + descrsetfunc tp_descr_set; Py_ssize_t tp_dictoffset; initproc tp_init; allocfunc tp_alloc; |