aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside2/libpyside/feature_select.cpp
diff options
context:
space:
mode:
authorChristian Tismer <tismer@stackless.com>2020-10-14 09:59:10 +0200
committerChristian Tismer <tismer@stackless.com>2020-10-27 13:13:46 +0000
commitdb03fa66435949c4c75658bbdfdaacbeedfa0413 (patch)
tree5c94ce063981982c7a50b3b190e758f202b063a3 /sources/pyside2/libpyside/feature_select.cpp
parent1d044f467070a040713c9566a8a8de3a56c571e7 (diff)
feature-select: implement class properties
After implementing property objects for PySide, the static properties (properties for static functions) were quite missing, for instance from QtCore.QCoreApplication and QtWidgets.QApplication . This implementation uses the normal Python properties and derives a PySide.ClassProperty class which works almost the same on classes. The static methods had to be mutated to class methods explicitly. That would be automated by PyType_Ready, but here we are doing this after class initialization. Task-number: PYSIDE-1019 Change-Id: Iabe00be18e25881cc7a97507b6fdae3e2d57ff7a Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io> Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
Diffstat (limited to 'sources/pyside2/libpyside/feature_select.cpp')
-rw-r--r--sources/pyside2/libpyside/feature_select.cpp71
1 files changed, 51 insertions, 20 deletions
diff --git a/sources/pyside2/libpyside/feature_select.cpp b/sources/pyside2/libpyside/feature_select.cpp
index 6a21d168d..660547d99 100644
--- a/sources/pyside2/libpyside/feature_select.cpp
+++ b/sources/pyside2/libpyside/feature_select.cpp
@@ -40,12 +40,11 @@
#include "feature_select.h"
#include "pyside.h"
#include "pysidestaticstrings.h"
+#include "class_property.h"
#include <shiboken.h>
#include <sbkstaticstrings.h>
-#include <QtCore/QtGlobal>
-
//////////////////////////////////////////////////////////////////////////////
//
// PYSIDE-1019: Support switchable extensions
@@ -418,6 +417,13 @@ void Select(PyObject *obj)
type->tp_dict = SelectFeatureSet(type);
}
+PyObject *Select(PyTypeObject *type)
+{
+ if (featurePointer != nullptr)
+ type->tp_dict = SelectFeatureSet(type);
+ return type->tp_dict;
+}
+
static bool feature_01_addLowerNames(PyTypeObject *type, PyObject *prev_dict, int id);
static bool feature_02_true_property(PyTypeObject *type, PyObject *prev_dict, int id);
static bool feature_04_addDummyNames(PyTypeObject *type, PyObject *prev_dict, int id);
@@ -460,6 +466,7 @@ void init()
initSelectableFeature(SelectFeatureSet);
registerCleanupFunction(finalize);
patch_property_impl();
+ PySide::ClassProperty::init();
is_initialized = true;
}
// Reset the cache. This is called at any "from __feature__ import".
@@ -549,12 +556,47 @@ static bool feature_01_addLowerNames(PyTypeObject *type, PyObject *prev_dict, in
// Feature 0x02: Use true properties instead of getters and setters
//
-static PyObject *createProperty(PyObject *getter, PyObject *setter)
+// This is the Python 2 version for inspection of m_ml, only.
+// The actual Python 3 version is larget.
+
+typedef struct {
+ PyObject_HEAD
+ PyMethodDef *m_ml; /* Description of the C function to call */
+ PyObject *m_self; /* Passed as 'self' arg to the C func, can be NULL */
+ PyObject *m_module; /* The __module__ attribute, can be anything */
+} PyCFunctionObject;
+
+static PyObject *modifyStaticToClassMethod(PyTypeObject *type, PyObject *sm)
{
+ AutoDecRef func_ob(PyObject_GetAttr(sm, PyMagicName::func()));
+ if (func_ob.isNull())
+ return nullptr;
+ auto func = reinterpret_cast<PyCFunctionObject *>(func_ob.object());
+ auto new_func = new PyMethodDef;
+ new_func->ml_name = func->m_ml->ml_name;
+ new_func->ml_meth = func->m_ml->ml_meth;
+ new_func->ml_flags = (func->m_ml->ml_flags & ~METH_STATIC) | METH_CLASS;
+ new_func->ml_doc = func->m_ml->ml_doc;
+ auto cfunc = PyCFunction_NewEx(new_func, nullptr, nullptr);
+ cfunc = PyDescr_NewClassMethod(type, new_func);
+ return cfunc;
+}
+
+static PyObject *createProperty(PyTypeObject *type, PyObject *getter, PyObject *setter)
+{
+ bool chassprop = false;
assert(getter != nullptr);
if (setter == nullptr)
setter = Py_None;
- auto obtype = reinterpret_cast<PyObject *>(&PyProperty_Type);
+ auto ptype = &PyProperty_Type;
+ if (Py_TYPE(getter) == PepStaticMethod_TypePtr) {
+ ptype = PyClassPropertyTypeF();
+ chassprop = true;
+ getter = modifyStaticToClassMethod(type, getter);
+ if (setter != Py_None)
+ setter = modifyStaticToClassMethod(type, setter);
+ }
+ auto obtype = reinterpret_cast<PyObject *>(ptype);
PyObject *prop = PyObject_CallFunctionObjArgs(obtype, getter, setter, nullptr);
return prop;
}
@@ -612,13 +654,12 @@ static bool feature_02_true_property(PyTypeObject *type, PyObject *prev_dict, in
PyObject *read = make_snake_case(fields[1], lower);
PyObject *write = haveWrite ? make_snake_case(fields[2], lower) : nullptr;
PyObject *getter = PyDict_GetItem(prev_dict, read);
- if (getter == nullptr || Py_TYPE(getter) != PepMethodDescr_TypePtr)
+ if (getter == nullptr || !(Py_TYPE(getter) == PepMethodDescr_TypePtr ||
+ Py_TYPE(getter) == PepStaticMethod_TypePtr))
continue;
PyObject *setter = haveWrite ? PyDict_GetItem(prev_dict, write) : nullptr;
- if (setter != nullptr && Py_TYPE(setter) != PepMethodDescr_TypePtr)
- continue;
- AutoDecRef PyProperty(createProperty(getter, setter));
+ AutoDecRef PyProperty(createProperty(type, getter, setter));
if (PyProperty.isNull())
return false;
if (PyDict_SetItem(prop_dict, name, PyProperty) < 0)
@@ -641,19 +682,10 @@ static bool feature_02_true_property(PyTypeObject *type, PyObject *prev_dict, in
// 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.
+// There is now also a class property implementation which inherits
+// from this one.
//
-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);
@@ -702,7 +734,6 @@ static bool patch_property_impl()
return false;
if (PyDict_SetItemString(dict, gsp->name, descr) < 0)
return false;
- // Replace property_descr_get/set by slightly changed versions
return true;
}