aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside6/libpyside/pysideproperty.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sources/pyside6/libpyside/pysideproperty.cpp')
-rw-r--r--sources/pyside6/libpyside/pysideproperty.cpp320
1 files changed, 146 insertions, 174 deletions
diff --git a/sources/pyside6/libpyside/pysideproperty.cpp b/sources/pyside6/libpyside/pysideproperty.cpp
index 9f9340e19..457415479 100644
--- a/sources/pyside6/libpyside/pysideproperty.cpp
+++ b/sources/pyside6/libpyside/pysideproperty.cpp
@@ -1,50 +1,14 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt for Python.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <sbkpython.h>
#include "pysideproperty.h"
#include "pysideproperty_p.h"
-#include "dynamicqmetaobject_p.h"
#include "pysidesignal.h"
#include "pysidesignal_p.h"
#include <shiboken.h>
+#include <pep384ext.h>
#include <signature.h>
using namespace Shiboken;
@@ -95,96 +59,150 @@ static PyGetSetDef PySidePropertyType_getset[] = {
{nullptr, nullptr, nullptr, nullptr, nullptr}
};
-static PyType_Slot PySidePropertyType_slots[] = {
- {Py_tp_dealloc, reinterpret_cast<void *>(qpropertyDeAlloc)},
- {Py_tp_call, reinterpret_cast<void *>(qPropertyCall)},
- {Py_tp_traverse, reinterpret_cast<void *>(qpropertyTraverse)},
- {Py_tp_clear, reinterpret_cast<void *>(qpropertyClear)},
- {Py_tp_methods, reinterpret_cast<void *>(PySidePropertyMethods)},
- {Py_tp_init, reinterpret_cast<void *>(qpropertyTpInit)},
- {Py_tp_new, reinterpret_cast<void *>(qpropertyTpNew)},
- {Py_tp_getset, PySidePropertyType_getset},
- {0, nullptr}
-};
+static PyTypeObject *createPropertyType()
+{
+ PyType_Slot PySidePropertyType_slots[] = {
+ {Py_tp_dealloc, reinterpret_cast<void *>(qpropertyDeAlloc)},
+ {Py_tp_call, reinterpret_cast<void *>(qPropertyCall)},
+ {Py_tp_traverse, reinterpret_cast<void *>(qpropertyTraverse)},
+ {Py_tp_clear, reinterpret_cast<void *>(qpropertyClear)},
+ {Py_tp_methods, reinterpret_cast<void *>(PySidePropertyMethods)},
+ {Py_tp_init, reinterpret_cast<void *>(qpropertyTpInit)},
+ {Py_tp_new, reinterpret_cast<void *>(qpropertyTpNew)},
+ {Py_tp_getset, PySidePropertyType_getset},
+ {Py_tp_del, reinterpret_cast<void *>(PyObject_GC_Del)},
+ {0, nullptr}
+ };
-static PyType_Spec PySidePropertyType_spec = {
- "2:PySide6.QtCore.Property",
- sizeof(PySideProperty),
- 0,
- Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_BASETYPE,
- PySidePropertyType_slots,
-};
+ PyType_Spec PySidePropertyType_spec = {
+ "2:PySide6.QtCore.Property",
+ sizeof(PySideProperty),
+ 0,
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_BASETYPE,
+ PySidePropertyType_slots,
+ };
+ return SbkType_FromSpec(&PySidePropertyType_spec);
+}
-PyTypeObject *PySidePropertyTypeF(void)
+PyTypeObject *PySideProperty_TypeF(void)
{
- static auto *type = SbkType_FromSpec(&PySidePropertyType_spec);
+ static auto *type = createPropertyType();
return type;
}
-static void qpropertyMetaCall(PySideProperty *pp, PyObject *self, QMetaObject::Call call, void **args)
+PySidePropertyPrivate::PySidePropertyPrivate() noexcept = default;
+PySidePropertyPrivate::~PySidePropertyPrivate() = default;
+
+PyObject *PySidePropertyPrivate::getValue(PyObject *source)
{
- Shiboken::Conversions::SpecificConverter converter(pp->d->typeName);
- Q_ASSERT(converter);
+ if (fget) {
+ Shiboken::AutoDecRef args(PyTuple_New(1));
+ Py_INCREF(source);
+ PyTuple_SET_ITEM(args, 0, source);
+ return PyObject_CallObject(fget, args);
+ }
+ return nullptr;
+}
- switch(call) {
- case QMetaObject::ReadProperty:
- {
- Shiboken::GilState gil;
- PyObject *value = PySide::Property::getValue(pp, self);
- if (value) {
- converter.toCpp(value, args[0]);
- Py_DECREF(value);
+int PySidePropertyPrivate::setValue(PyObject *source, PyObject *value)
+{
+ if (fset && value) {
+ Shiboken::AutoDecRef args(PyTuple_New(2));
+ PyTuple_SET_ITEM(args, 0, source);
+ PyTuple_SET_ITEM(args, 1, value);
+ Py_INCREF(source);
+ Py_INCREF(value);
+ Shiboken::AutoDecRef result(PyObject_CallObject(fset, args));
+ return (result.isNull() ? -1 : 0);
+ }
+ if (fdel) {
+ Shiboken::AutoDecRef args(PyTuple_New(1));
+ PyTuple_SET_ITEM(args, 0, source);
+ Py_INCREF(source);
+ Shiboken::AutoDecRef result(PyObject_CallObject(fdel, args));
+ return (result.isNull() ? -1 : 0);
+ }
+ PyErr_SetString(PyExc_AttributeError, "Attribute is read only");
+ return -1;
+}
+
+int PySidePropertyPrivate::reset(PyObject *source)
+{
+ if (freset) {
+ Shiboken::AutoDecRef args(PyTuple_New(1));
+ Py_INCREF(source);
+ PyTuple_SET_ITEM(args, 0, source);
+ Shiboken::AutoDecRef result(PyObject_CallObject(freset, args));
+ return (result.isNull() ? -1 : 0);
+ }
+ return -1;
+}
+
+void PySidePropertyPrivate::metaCall(PyObject *source, QMetaObject::Call call, void **args)
+{
+ switch (call) {
+ case QMetaObject::ReadProperty: {
+ AutoDecRef value(getValue(source));
+ auto *obValue = value.object();
+ if (obValue) {
+ Conversions::SpecificConverter converter(typeName);
+ if (converter) {
+ converter.toCpp(obValue, args[0]);
+ } else {
+ // PYSIDE-2160: Report an unknown type name to the caller `qtPropertyMetacall`.
+ PyErr_SetObject(PyExc_StopIteration, obValue);
}
- break;
}
-
- case QMetaObject::WriteProperty:
- {
- Shiboken::GilState gil;
- Shiboken::AutoDecRef value(converter.toPython(args[0]));
- PySide::Property::setValue(pp, self, value);
- break;
+ }
+ break;
+
+ case QMetaObject::WriteProperty: {
+ Conversions::SpecificConverter converter(typeName);
+ if (converter) {
+ AutoDecRef value(converter.toPython(args[0]));
+ setValue(source, value);
+ } else {
+ // PYSIDE-2160: Report an unknown type name to the caller `qtPropertyMetacall`.
+ PyErr_SetNone(PyExc_StopIteration);
}
+ }
+ break;
- case QMetaObject::ResetProperty:
- {
- Shiboken::GilState gil;
- PySide::Property::reset(pp, self);
- break;
- }
+ case QMetaObject::ResetProperty:
+ reset(source);
+ break;
- // just to avoid gcc warnings
- case QMetaObject::BindableProperty:
- case QMetaObject::InvokeMetaMethod:
- case QMetaObject::CreateInstance:
- case QMetaObject::IndexOfMethod:
- case QMetaObject::RegisterPropertyMetaType:
- case QMetaObject::RegisterMethodArgumentMetaType:
- break;
+ default:
+ break;
}
}
-
static PyObject *qpropertyTpNew(PyTypeObject *subtype, PyObject * /* args */, PyObject * /* kwds */)
{
- PySideProperty *me = reinterpret_cast<PySideProperty *>(subtype->tp_alloc(subtype, 0));
+ auto *me = PepExt_TypeCallAlloc<PySideProperty>(subtype, 0);
me->d = new PySidePropertyPrivate;
return reinterpret_cast<PyObject *>(me);
}
static int qpropertyTpInit(PyObject *self, PyObject *args, PyObject *kwds)
{
- PyObject *type = nullptr;
+ PyObject *type{};
auto data = reinterpret_cast<PySideProperty *>(self);
PySidePropertyPrivate *pData = data->d;
- pData->metaCallHandler = &qpropertyMetaCall;
static const char *kwlist[] = {"type", "fget", "fset", "freset", "fdel", "doc", "notify",
"designable", "scriptable", "stored",
"user", "constant", "final", nullptr};
char *doc{};
+ Py_CLEAR(pData->pyTypeObject);
+ Py_CLEAR(pData->fget);
+ Py_CLEAR(pData->fset);
+ Py_CLEAR(pData->freset);
+ Py_CLEAR(pData->fdel);
+ Py_CLEAR(pData->notify);
+
if (!PyArg_ParseTupleAndKeywords(args, kwds,
"O|OOOOsObbbbbb:QtCore.Property",
const_cast<char **>(kwlist),
@@ -206,6 +224,8 @@ static int qpropertyTpInit(PyObject *self, PyObject *args, PyObject *kwds)
else
pData->doc.clear();
+ pData->pyTypeObject = type;
+ Py_XINCREF(pData->pyTypeObject);
pData->typeName = PySide::Signal::getTypeName(type);
if (pData->typeName.isEmpty())
@@ -238,13 +258,17 @@ static void qpropertyDeAlloc(PyObject *self)
// This was not needed before Python 3.8 (Python issue 35810)
Py_DECREF(Py_TYPE(self));
}
- Py_TYPE(self)->tp_free(self);
+ PyObject_GC_UnTrack(self);
+ PepExt_TypeCallFree(self);
}
+// Create a copy of the property to prevent the @property.setter from modifying
+// the property in place and avoid strange side effects in derived classes
+// (cf https://bugs.python.org/issue1620).
static PyObject *
_property_copy(PyObject *old, PyObject *get, PyObject *set, PyObject *reset, PyObject *del)
{
- PySideProperty *pold = reinterpret_cast<PySideProperty *>(old);
+ auto *pold = reinterpret_cast<PySideProperty *>(old);
PySidePropertyPrivate *pData = pold->d;
AutoDecRef type(PyObject_Type(old));
@@ -276,9 +300,8 @@ _property_copy(PyObject *old, PyObject *get, PyObject *set, PyObject *reset, PyO
auto notify = pData->notify ? pData->notify : Py_None;
- PyObject *typeName = String::fromCString(pData->typeName);
PyObject *obNew = PyObject_CallFunction(type, const_cast<char *>("OOOOOsO" "bbb" "bbb"),
- typeName, get, set, reset, del, doc.data(), notify,
+ pData->pyTypeObject, get, set, reset, del, doc.data(), notify,
pData->designable, pData->scriptable, pData->stored,
pData->user, pData->constant, pData->final);
@@ -356,10 +379,10 @@ static PyObject *qPropertyDocGet(PyObject *self, void *)
if (pData->fget != nullptr) {
// PYSIDE-1019: Fetch the default `__doc__` from fget. We do it late.
AutoDecRef get_doc(PyObject_GetAttr(pData->fget, PyMagicName::doc()));
- if (!get_doc.isNull()) {
+ if (!get_doc.isNull() && get_doc.object() != Py_None) {
pData->doc = String::toCString(get_doc);
pData->getter_doc = true;
- if (Py_TYPE(self) == PySidePropertyTypeF())
+ if (Py_TYPE(self) == PySideProperty_TypeF())
return qPropertyDocGet(self, nullptr);
/*
* If this is a property subclass, put __doc__ in dict of the
@@ -399,6 +422,7 @@ static int qpropertyTraverse(PyObject *self, visitproc visit, void *arg)
Py_VISIT(data->freset);
Py_VISIT(data->fdel);
Py_VISIT(data->notify);
+ Py_VISIT(data->pyTypeObject);
return 0;
}
@@ -413,7 +437,7 @@ static int qpropertyClear(PyObject *self)
Py_CLEAR(data->freset);
Py_CLEAR(data->fdel);
Py_CLEAR(data->notify);
-
+ Py_CLEAR(data->pyTypeObject);
delete data;
reinterpret_cast<PySideProperty *>(self)->d = nullptr;
@@ -422,16 +446,14 @@ static int qpropertyClear(PyObject *self)
} // extern "C"
-namespace {
-
static PyObject *getFromType(PyTypeObject *type, PyObject *name)
{
- PyObject *attr = nullptr;
- attr = PyDict_GetItem(type->tp_dict, name);
+ AutoDecRef tpDict(PepType_GetDict(type));
+ auto *attr = PyDict_GetItem(tpDict.object(), name);
if (!attr) {
PyObject *bases = type->tp_bases;
- int size = PyTuple_GET_SIZE(bases);
- for(int i=0; i < size; i++) {
+ const Py_ssize_t size = PyTuple_GET_SIZE(bases);
+ for (Py_ssize_t i = 0; i < size; ++i) {
PyObject *base = PyTuple_GET_ITEM(bases, i);
attr = getFromType(reinterpret_cast<PyTypeObject *>(base), name);
if (attr)
@@ -441,17 +463,13 @@ static PyObject *getFromType(PyTypeObject *type, PyObject *name)
return attr;
}
-} //namespace
-
-
-namespace PySide { namespace Property {
+namespace PySide::Property {
static const char *Property_SignatureStrings[] = {
"PySide6.QtCore.Property(self,type:type,fget:typing.Callable=None,fset:typing.Callable=None,"
"freset:typing.Callable=None,fdel:typing.Callable=None,doc:str=None,"
"notify:typing.Callable=None,designable:bool=True,scriptable:bool=True,"
- "stored:bool=True,user:bool=False,constant:bool=False,final:bool=False)"
- "->PySide6.QtCore.Property",
+ "stored:bool=True,user:bool=False,constant:bool=False,final:bool=False)",
"PySide6.QtCore.Property.deleter(self,fdel:typing.Callable)->PySide6.QtCore.Property",
"PySide6.QtCore.Property.getter(self,fget:typing.Callable)->PySide6.QtCore.Property",
"PySide6.QtCore.Property.read(self,fget:typing.Callable)->PySide6.QtCore.Property",
@@ -461,68 +479,34 @@ static const char *Property_SignatureStrings[] = {
void init(PyObject *module)
{
- if (InitSignatureStrings(PySidePropertyTypeF(), Property_SignatureStrings) < 0)
+ if (InitSignatureStrings(PySideProperty_TypeF(), Property_SignatureStrings) < 0)
return;
- Py_INCREF(PySidePropertyTypeF());
- PyModule_AddObject(module, "Property", reinterpret_cast<PyObject *>(PySidePropertyTypeF()));
+ Py_INCREF(PySideProperty_TypeF());
+ PyModule_AddObject(module, "Property", reinterpret_cast<PyObject *>(PySideProperty_TypeF()));
}
bool checkType(PyObject *pyObj)
{
if (pyObj) {
- return PyType_IsSubtype(Py_TYPE(pyObj), PySidePropertyTypeF());
+ return PyType_IsSubtype(Py_TYPE(pyObj), PySideProperty_TypeF());
}
return false;
}
-int setValue(PySideProperty *self, PyObject *source, PyObject *value)
+PyObject *getValue(PySideProperty *self, PyObject *source)
{
- PyObject *fset = self->d->fset;
- if (fset && value) {
- Shiboken::AutoDecRef args(PyTuple_New(2));
- PyTuple_SET_ITEM(args, 0, source);
- PyTuple_SET_ITEM(args, 1, value);
- Py_INCREF(source);
- Py_INCREF(value);
- Shiboken::AutoDecRef result(PyObject_CallObject(fset, args));
- return (result.isNull() ? -1 : 0);
- }
- PyObject *fdel = self->d->fdel;
- if (fdel) {
- Shiboken::AutoDecRef args(PyTuple_New(1));
- PyTuple_SET_ITEM(args, 0, source);
- Py_INCREF(source);
- Shiboken::AutoDecRef result(PyObject_CallObject(fdel, args));
- return (result.isNull() ? -1 : 0);
- }
- PyErr_SetString(PyExc_AttributeError, "Attibute read only");
- return -1;
+ return self->d->getValue(source);
}
-PyObject *getValue(PySideProperty *self, PyObject *source)
+int setValue(PySideProperty *self, PyObject *source, PyObject *value)
{
- PyObject *fget = self->d->fget;
- if (fget) {
- Shiboken::AutoDecRef args(PyTuple_New(1));
- Py_INCREF(source);
- PyTuple_SET_ITEM(args, 0, source);
- return PyObject_CallObject(fget, args);
- }
- return nullptr;
+ return self->d->setValue(source, value);
}
int reset(PySideProperty *self, PyObject *source)
{
- PyObject *freset = self->d->freset;
- if (freset) {
- Shiboken::AutoDecRef args(PyTuple_New(1));
- Py_INCREF(source);
- PyTuple_SET_ITEM(args, 0, source);
- Shiboken::AutoDecRef result(PyObject_CallObject(freset, args));
- return (result.isNull() ? -1 : 0);
- }
- return -1;
+ return self->d->reset(source);
}
const char *getTypeName(const PySideProperty *self)
@@ -594,34 +578,22 @@ bool isFinal(const PySideProperty *self)
const char *getNotifyName(PySideProperty *self)
{
if (self->d->notifySignature.isEmpty()) {
- PyObject *str = PyObject_Str(self->d->notify);
+ AutoDecRef str(PyObject_Str(self->d->notify));
self->d->notifySignature = Shiboken::String::toCString(str);
- Py_DECREF(str);
}
return self->d->notifySignature.isEmpty()
? nullptr : self->d->notifySignature.constData();
}
-void setMetaCallHandler(PySideProperty *self, MetaCallHandler handler)
-{
- self->d->metaCallHandler = handler;
-}
-
void setTypeName(PySideProperty *self, const char *typeName)
{
self->d->typeName = typeName;
}
-void setUserData(PySideProperty *self, void *data)
-{
- self->d->userData = data;
-}
-
-void *userData(PySideProperty *self)
+PyObject *getTypeObject(const PySideProperty *self)
{
- return self->d->userData;
+ return self->d->pyTypeObject;
}
-} //namespace Property
-} //namespace PySide
+} //namespace PySide::Property