diff options
Diffstat (limited to 'sources/pyside6/libpyside/pysideproperty.cpp')
-rw-r--r-- | sources/pyside6/libpyside/pysideproperty.cpp | 320 |
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 |