aboutsummaryrefslogtreecommitdiffstats
path: root/sources
diff options
context:
space:
mode:
authorFriedemann Kleint <[email protected]>2020-10-12 08:17:07 +0200
committerFriedemann Kleint <[email protected]>2020-10-12 08:17:07 +0200
commit30724622333ffc8bce61f7e19217977eebbf9564 (patch)
tree172487d1478cc478857d46cb445db59ca3601448 /sources
parent1a66d7be29902fc041fe53ef280c237d3c3f216b (diff)
parent8847a47aad95d7f85d5e184071bf95c44826c4c7 (diff)
Merge remote-tracking branch 'origin/5.15' into dev
Diffstat (limited to 'sources')
-rw-r--r--sources/pyside2/libpyside/feature_select.cpp79
-rw-r--r--sources/shiboken2/libshiboken/pep384impl.cpp3
-rw-r--r--sources/shiboken2/libshiboken/pep384impl.h2
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 c349572f6..fa31ce43f 100644
--- a/sources/shiboken2/libshiboken/pep384impl.cpp
+++ b/sources/shiboken2/libshiboken/pep384impl.cpp
@@ -91,6 +91,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)
@@ -114,6 +115,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},
@@ -163,6 +165,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;