diff options
Diffstat (limited to 'sources/pyside6/libpyside/class_property.cpp')
-rw-r--r-- | sources/pyside6/libpyside/class_property.cpp | 178 |
1 files changed, 89 insertions, 89 deletions
diff --git a/sources/pyside6/libpyside/class_property.cpp b/sources/pyside6/libpyside/class_property.cpp index 63850be07..2bed97ef5 100644 --- a/sources/pyside6/libpyside/class_property.cpp +++ b/sources/pyside6/libpyside/class_property.cpp @@ -1,47 +1,11 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#include "pyside.h" +// 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 "class_property.h" #include "pysidestaticstrings.h" #include "feature_select.h" -#include "class_property.h" +#include <pep384ext.h> #include <shiboken.h> #include <sbkstaticstrings.h> @@ -58,56 +22,97 @@ extern "C" { */ // `class_property.__get__()`: Always pass the class instead of the instance. -static PyObject *PyClassProperty_get(PyObject *self, PyObject * /*ob*/, PyObject *cls) +static PyObject *PyClassProperty_descr_get(PyObject *self, PyObject * /*ob*/, PyObject *cls) { - return PyProperty_Type.tp_descr_get(self, cls, cls); + return PepExt_Type_GetDescrGetSlot(&PyProperty_Type)(self, cls, cls); } // `class_property.__set__()`: Just like the above `__get__()`. -static int PyClassProperty_set(PyObject *self, PyObject *obj, PyObject *value) +static int PyClassProperty_descr_set(PyObject *self, PyObject *obj, PyObject *value) { PyObject *cls = PyType_Check(obj) ? obj : reinterpret_cast<PyObject *>(Py_TYPE(obj)); - return PyProperty_Type.tp_descr_set(self, cls, value); + return PepExt_Type_GetDescrSetSlot(&PyProperty_Type)(self, cls, value); +} + +// PYSIDE-2230: Why is this metaclass necessary? +// +// The problem is that the property object already exists as a Python +// object. We derive a subclass for class properties, without +// repeating everything but just by adding something to support +// the class-ness. +// +// But this Python property has as metaclass `type` which is incompatible +// now with SbkObjectType, which generates physically larger types that +// are incompatible with properties by using PEP 697. +// Adding a compatible metaclass that is unrelated to `SbkObjectType` +// is the correct solution. Re-using `SbkObjectType` was actually an abuse, +// since Python properties are in no way PySide objects. + +static PyTypeObject *createClassPropertyTypeType() +{ + PyType_Slot PyClassPropertyType_Type_slots[] = { + {Py_tp_base, static_cast<void *>(&PyType_Type)}, + {Py_tp_alloc, reinterpret_cast<void *>(PyType_GenericAlloc)}, + {Py_tp_free, reinterpret_cast<void *>(PyObject_GC_Del)}, + {0, nullptr} + }; + + PyType_Spec PyClassPropertyType_Type_spec = { + "1:Shiboken.ClassPropertyType", + 0, + 0, // sizeof(PyMemberDef), not for PyPy without a __len__ defined + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_TYPE_SUBCLASS, + PyClassPropertyType_Type_slots, + }; + + return SbkType_FromSpec(&PyClassPropertyType_Type_spec); +} + +PyTypeObject *PyClassPropertyType_TypeF() +{ + static auto *type = createClassPropertyTypeType(); + return type; } // The property `__doc__` default does not work for class properties // because PyProperty_Type.tp_init thinks this is a subclass which needs PyObject_SetAttr. // We call `__init__` while pretending to be a PyProperty_Type instance. -static int PyClassProperty_init(PyObject *self, PyObject *args, PyObject *kwargs) +static int PyClassProperty_tp_init(PyObject *self, PyObject *args, PyObject *kwargs) { auto hold = Py_TYPE(self); - Py_TYPE(self) = &PyProperty_Type; - auto ret = PyProperty_Type.tp_init(self, args, kwargs); - Py_TYPE(self) = hold; + self->ob_type = &PyProperty_Type; + auto ret = PepExt_Type_GetInitSlot(&PyProperty_Type)(self, args, kwargs); + self->ob_type = hold; return ret; } -static PyType_Slot PyClassProperty_slots[] = { - {Py_tp_getset, nullptr}, // will be set below - {Py_tp_base, reinterpret_cast<void *>(&PyProperty_Type)}, - {Py_tp_descr_get, reinterpret_cast<void *>(PyClassProperty_get)}, - {Py_tp_descr_set, reinterpret_cast<void *>(PyClassProperty_set)}, - {Py_tp_init, reinterpret_cast<void *>(PyClassProperty_init)}, - {0, 0} -}; - -static PyType_Spec PyClassProperty_spec = { - "PySide6.QtCore.PyClassProperty", - sizeof(propertyobject), - 0, - Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, - PyClassProperty_slots, -}; - -PyTypeObject *PyClassPropertyTypeF() +static PyTypeObject *createPyClassPropertyType() +{ + PyType_Slot PyClassProperty_slots[] = { + {Py_tp_getset, reinterpret_cast<void *>(PyProperty_Type.tp_getset)}, // will be set below + {Py_tp_base, reinterpret_cast<void *>(&PyProperty_Type)}, + {Py_tp_descr_get, reinterpret_cast<void *>(PyClassProperty_descr_get)}, + {Py_tp_descr_set, reinterpret_cast<void *>(PyClassProperty_descr_set)}, + {Py_tp_init, reinterpret_cast<void *>(PyClassProperty_tp_init)}, + {0, nullptr} + }; + + PyType_Spec PyClassProperty_spec = { + "2:PySide6.QtCore.PyClassProperty", + sizeof(propertyobject), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, + PyClassProperty_slots, + }; + + if (_PepRuntimeVersion() >= 0x030A00) + PyClassProperty_spec.basicsize = sizeof(propertyobject310); + return SbkType_FromSpecWithMeta(&PyClassProperty_spec, PyClassPropertyType_TypeF()); +} + +PyTypeObject *PyClassProperty_TypeF() { - static PyTypeObject *type = nullptr; - if (type == nullptr) { - // Provide the same `tp_getset`, which is not inherited. - PyClassProperty_slots[0].pfunc = PyProperty_Type.tp_getset; - type = reinterpret_cast<PyTypeObject *>( - PyType_FromSpec(&PyClassProperty_spec)); - } + static auto *type = createPyClassPropertyType(); return type; } @@ -129,16 +134,14 @@ static int SbkObjectType_meta_setattro(PyObject *obj, PyObject *name, PyObject * // 1. `Type.class_prop = value` --> descr_set: `Type.class_prop.__set__(value)` // 2. `Type.class_prop = other_class_prop` --> setattro: replace existing `class_prop` // 3. `Type.regular_attribute = value` --> setattro: regular attribute assignment - const auto class_prop = reinterpret_cast<PyObject *>(PyClassPropertyTypeF()); + const auto class_prop = reinterpret_cast<PyObject *>(PyClassProperty_TypeF()); const auto call_descr_set = descr && PyObject_IsInstance(descr, class_prop) && !PyObject_IsInstance(value, class_prop); if (call_descr_set) { // Call `class_property.__set__()` instead of replacing the `class_property`. - return Py_TYPE(descr)->tp_descr_set(descr, obj, value); - } else { - // Replace existing attribute. - return PyType_Type.tp_setattro(obj, name, value); - } + return PepExt_Type_GetDescrSetSlot(Py_TYPE(descr))(descr, obj, value); + } // Replace existing attribute. + return PepExt_Type_GetSetAttroSlot(&PyType_Type)(obj, name, value); } } // extern "C" @@ -146,15 +149,14 @@ static int SbkObjectType_meta_setattro(PyObject *obj, PyObject *name, PyObject * /* * These functions are added to the SbkObjectType_TypeF() dynamically. */ -namespace PySide { namespace ClassProperty { +namespace PySide::ClassProperty { static const char *PyClassProperty_SignatureStrings[] = { "PySide6.QtCore.PyClassProperty(cls," "fget:typing.Optional[typing.Callable[[typing.Any],typing.Any]]=None," "fset:typing.Optional[typing.Callable[[typing.Any,typing.Any],None]]=None," "fdel:typing.Optional[typing.Callable[[typing.Any],None]]=None," - "doc:typing.Optional[str]=None)" - "->PySide6.QtCore.PyClassProperty", + "doc:typing.Optional[str]=None)", "PySide6.QtCore.PyClassProperty.getter(cls,fget:typing.Callable[[typing.Any],typing.Any])->PySide6.QtCore.PyClassProperty", "PySide6.QtCore.PyClassProperty.setter(cls,fset:typing.Callable[[typing.Any,typing.Any],None])->PySide6.QtCore.PyClassProperty", "PySide6.QtCore.PyClassProperty.deleter(cls,fdel:typing.Callable[[typing.Any],None])->PySide6.QtCore.PyClassProperty", @@ -164,15 +166,13 @@ void init(PyObject *module) { PyTypeObject *type = SbkObjectType_TypeF(); type->tp_setattro = SbkObjectType_meta_setattro; - Py_TYPE(PyClassPropertyTypeF()) = type; - if (InitSignatureStrings(PyClassPropertyTypeF(), PyClassProperty_SignatureStrings) < 0) + if (InitSignatureStrings(PyClassProperty_TypeF(), PyClassProperty_SignatureStrings) < 0) return; - Py_INCREF(PyClassPropertyTypeF()); - auto classproptype = reinterpret_cast<PyObject *>(PyClassPropertyTypeF()); + Py_INCREF(PyClassProperty_TypeF()); + auto classproptype = reinterpret_cast<PyObject *>(PyClassProperty_TypeF()); PyModule_AddObject(module, "PyClassProperty", classproptype); } -} // namespace ClassProperty -} // namespace PySide +} // namespace PySide::ClassProperty |