diff options
-rw-r--r-- | sources/shiboken6/libshiboken/sbkenum.cpp | 117 | ||||
-rw-r--r-- | sources/shiboken6/libshiboken/sbkenum.h | 3 | ||||
-rw-r--r-- | sources/shiboken6/libshiboken/signature/signature_globals.cpp | 3 | ||||
-rw-r--r-- | sources/shiboken6/tests/samplebinding/enum_test.py | 15 |
4 files changed, 88 insertions, 50 deletions
diff --git a/sources/shiboken6/libshiboken/sbkenum.cpp b/sources/shiboken6/libshiboken/sbkenum.cpp index 28840a7de..d57106cd3 100644 --- a/sources/shiboken6/libshiboken/sbkenum.cpp +++ b/sources/shiboken6/libshiboken/sbkenum.cpp @@ -45,13 +45,13 @@ #include "basewrapper.h" #include "autodecref.h" #include "sbkpython.h" +#include "signature.h" #include <string.h> #include <cstring> #include <vector> -#define SBK_ENUM(ENUM) reinterpret_cast<SbkEnumObject *>(ENUM) -#define SBK_TYPE_CHECK(o) (strcmp(Py_TYPE(Py_TYPE(o))->tp_name, "Shiboken.EnumType") == 0) +#define SbkEnumType_Check(o) (Py_TYPE(Py_TYPE(o)) == SbkEnumType_TypeF()) typedef PyObject *(*enum_func)(PyObject *, PyObject *); extern "C" @@ -76,9 +76,11 @@ struct SbkEnumObject PyObject *ob_name; }; +static PyTypeObject *SbkEnum_TypeF(); // forward + static PyObject *SbkEnumObject_repr(PyObject *self) { - const SbkEnumObject *enumObj = SBK_ENUM(self); + const SbkEnumObject *enumObj = reinterpret_cast<SbkEnumObject *>(self); if (enumObj->ob_name) return Shiboken::String::fromFormat("%s.%s", (Py_TYPE(self))->tp_name, PyBytes_AS_STRING(enumObj->ob_name)); else @@ -87,7 +89,7 @@ static PyObject *SbkEnumObject_repr(PyObject *self) static PyObject *SbkEnumObject_name(PyObject *self, void *) { - auto *enum_self = SBK_ENUM(self); + auto *enum_self = reinterpret_cast<SbkEnumObject *>(self); if (enum_self->ob_name == nullptr) Py_RETURN_NONE; @@ -102,6 +104,11 @@ static PyObject *SbkEnum_tp_new(PyTypeObject *type, PyObject *args, PyObject *) if (!PyArg_ParseTuple(args, "|l:__new__", &itemValue)) return nullptr; + if (type == SbkEnum_TypeF()) { + PyErr_Format(PyExc_TypeError, "You cannot use %s directly", type->tp_name); + return nullptr; + } + SbkEnumObject *self = PyObject_New(SbkEnumObject, type); if (!self) return nullptr; @@ -111,6 +118,10 @@ static PyObject *SbkEnum_tp_new(PyTypeObject *type, PyObject *args, PyObject *) return reinterpret_cast<PyObject *>(self); } +static const char *SbkEnum_SignatureStrings[] = { + "Shiboken.Enum(self,itemValue:int=0)", + nullptr}; // Sentinel + void enum_object_dealloc(PyObject *ob) { auto self = reinterpret_cast<SbkEnumObject *>(ob); @@ -118,7 +129,7 @@ void enum_object_dealloc(PyObject *ob) Sbk_object_dealloc(ob); } -static PyObject *enum_op(enum_func f, PyObject *a, PyObject *b) { +static PyObject *_enum_op(enum_func f, PyObject *a, PyObject *b) { PyObject *valA = a; PyObject *valB = b; PyObject *result = nullptr; @@ -128,12 +139,12 @@ static PyObject *enum_op(enum_func f, PyObject *a, PyObject *b) { // We are not allowing floats if (!PyFloat_Check(valA) && !PyFloat_Check(valB)) { // Check if both variables are SbkEnumObject - if (SBK_TYPE_CHECK(valA)) { - valA = PyLong_FromLong(SBK_ENUM(valA)->ob_value); + if (SbkEnumType_Check(valA)) { + valA = PyLong_FromLong(reinterpret_cast<SbkEnumObject *>(valA)->ob_value); enumA = true; } - if (SBK_TYPE_CHECK(valB)) { - valB = PyLong_FromLong(SBK_ENUM(valB)->ob_value); + if (SbkEnumType_Check(valB)) { + valB = PyLong_FromLong(reinterpret_cast<SbkEnumObject *>(valB)->ob_value); enumB = true; } } @@ -151,7 +162,6 @@ static PyObject *enum_op(enum_func f, PyObject *a, PyObject *b) { Py_DECREF(valA); if (enumB) Py_DECREF(valB); - return result; } @@ -165,42 +175,42 @@ static PyObject *enum_op(enum_func f, PyObject *a, PyObject *b) { */ static PyObject *enum_int(PyObject *v) { - return PyInt_FromLong(SBK_ENUM(v)->ob_value); + return PyInt_FromLong(reinterpret_cast<SbkEnumObject *>(v)->ob_value); } static PyObject *enum_and(PyObject *self, PyObject *b) { - return enum_op(PyNumber_And, self, b); + return _enum_op(PyNumber_And, self, b); } static PyObject *enum_or(PyObject *self, PyObject *b) { -return enum_op(PyNumber_Or, self, b); + return _enum_op(PyNumber_Or, self, b); } static PyObject *enum_xor(PyObject *self, PyObject *b) { - return enum_op(PyNumber_Xor, self, b); + return _enum_op(PyNumber_Xor, self, b); } static int enum_bool(PyObject *v) { - return (SBK_ENUM(v)->ob_value > 0); + return (reinterpret_cast<SbkEnumObject *>(v)->ob_value > 0); } static PyObject *enum_add(PyObject *self, PyObject *v) { - return enum_op(PyNumber_Add, self, v); + return _enum_op(PyNumber_Add, self, v); } static PyObject *enum_subtract(PyObject *self, PyObject *v) { - return enum_op(PyNumber_Subtract, self, v); + return _enum_op(PyNumber_Subtract, self, v); } static PyObject *enum_multiply(PyObject *self, PyObject *v) { -return enum_op(PyNumber_Multiply, self, v); + return _enum_op(PyNumber_Multiply, self, v); } static PyObject *enum_richcompare(PyObject *self, PyObject *other, int op) @@ -215,12 +225,12 @@ static PyObject *enum_richcompare(PyObject *self, PyObject *other, int op) if (!PyFloat_Check(valA) && !PyFloat_Check(valB)) { // Check if both variables are SbkEnumObject - if (SBK_TYPE_CHECK(valA)) { - valA = PyLong_FromLong(SBK_ENUM(valA)->ob_value); + if (SbkEnumType_Check(valA)) { + valA = PyLong_FromLong(reinterpret_cast<SbkEnumObject *>(valA)->ob_value); enumA = true; } - if (SBK_TYPE_CHECK(valB)) { - valB = PyLong_FromLong(SBK_ENUM(valB)->ob_value); + if (SbkEnumType_Check(valB)) { + valB = PyLong_FromLong(reinterpret_cast<SbkEnumObject *>(valB)->ob_value); enumB =true; } } @@ -259,16 +269,6 @@ static PyObject *SbkEnumTypeTpNew(PyTypeObject *metatype, PyObject *args, PyObje static PyType_Slot SbkEnumType_Type_slots[] = { {Py_tp_dealloc, (void *)SbkEnumTypeDealloc}, - {Py_nb_add, (void *)enum_add}, - {Py_nb_subtract, (void *)enum_subtract}, - {Py_nb_multiply, (void *)enum_multiply}, - {Py_nb_positive, (void *)enum_int}, - {Py_nb_bool, (void *)enum_bool}, - {Py_nb_and, (void *)enum_and}, - {Py_nb_xor, (void *)enum_xor}, - {Py_nb_or, (void *)enum_or}, - {Py_nb_int, (void *)enum_int}, - {Py_nb_index, (void *)enum_int}, {Py_tp_base, (void *)&PyType_Type}, {Py_tp_alloc, (void *)PyType_GenericAlloc}, {Py_tp_new, (void *)SbkEnumTypeTpNew}, @@ -276,7 +276,7 @@ static PyType_Slot SbkEnumType_Type_slots[] = { {0, nullptr} }; static PyType_Spec SbkEnumType_Type_spec = { - "1:Shiboken.EnumType", + "1:Shiboken.EnumMeta", 0, // filled in later sizeof(PyMemberDef), Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, @@ -334,8 +334,6 @@ PyObject *SbkEnumTypeTpNew(PyTypeObject *metatype, PyObject *args, PyObject *kwd // extern "C" { -static void init_enum(); // forward - static PyObject *enum_unpickler = nullptr; // Pickling: reduce the Qt Enum object @@ -405,16 +403,23 @@ static bool _init_enum() PyErr_Clear(); mod = shibo.object(); } + // publish Shiboken.Enum so that the signature gets initialized + if (PyObject_SetAttrString(mod, "Enum", reinterpret_cast<PyObject *>(SbkEnum_TypeF())) < 0) + return false; + if (InitSignatureStrings(SbkEnum_TypeF(), SbkEnum_SignatureStrings) < 0) + return false; enum_unpickler = PyObject_GetAttrString(mod, "_unpickle_enum"); if (enum_unpickler == nullptr) return false; return true; } -static void init_enum() +void init_enum() { - if (!(enum_unpickler || _init_enum())) + static bool is_initialized = false; + if (!(is_initialized || enum_unpickler || _init_enum())) Py_FatalError("could not load enum pickling helper function"); + is_initialized = true; } static PyMethodDef SbkEnumObject_Methods[] = { @@ -588,7 +593,10 @@ newItem(PyTypeObject *enumType, long itemValue, const char *itemName) return reinterpret_cast<PyObject *>(enumObj); } -static PyType_Slot SbkNewType_slots[] = { +} // namespace Shiboken +} // namespace Enum + +static PyType_Slot SbkNewEnum_slots[] = { {Py_tp_repr, (void *)SbkEnumObject_repr}, {Py_tp_str, (void *)SbkEnumObject_repr}, {Py_tp_getset, (void *)SbkEnumGetSetList}, @@ -609,14 +617,22 @@ static PyType_Slot SbkNewType_slots[] = { {Py_tp_dealloc, (void *)enum_object_dealloc}, {0, nullptr} }; -static PyType_Spec SbkNewType_spec = { - "missing Enum name", // to be inserted later +static PyType_Spec SbkNewEnum_spec = { + "1:Shiboken.Enum", sizeof(SbkEnumObject), 0, - Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES, - SbkNewType_slots, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, + SbkNewEnum_slots, }; +static PyTypeObject *SbkEnum_TypeF() +{ + static auto type = SbkType_FromSpec(&SbkNewEnum_spec); + return reinterpret_cast<PyTypeObject *>(type); +} + +namespace Shiboken { namespace Enum { + static void copyNumberMethods(PyTypeObject *flagsType, PyType_Slot number_slots[], @@ -674,20 +690,23 @@ newTypeWithName(const char *name, PyType_Slot newslots[99] = {}; // enough but not too big for the stack PyType_Spec newspec; newspec.name = strdup(name); - newspec.basicsize = SbkNewType_spec.basicsize; - newspec.itemsize = SbkNewType_spec.itemsize; - newspec.flags = SbkNewType_spec.flags; + newspec.basicsize = SbkNewEnum_spec.basicsize; + newspec.itemsize = SbkNewEnum_spec.itemsize; + newspec.flags = SbkNewEnum_spec.flags; // we must append all the number methods, so rebuild everything: int idx = 0; - while (SbkNewType_slots[idx].slot) { - newslots[idx].slot = SbkNewType_slots[idx].slot; - newslots[idx].pfunc = SbkNewType_slots[idx].pfunc; + while (SbkNewEnum_slots[idx].slot) { + newslots[idx].slot = SbkNewEnum_slots[idx].slot; + newslots[idx].pfunc = SbkNewEnum_slots[idx].pfunc; ++idx; } if (numbers_fromFlag) copyNumberMethods(numbers_fromFlag, newslots, &idx); newspec.slots = newslots; - auto *type = reinterpret_cast<PyTypeObject *>(SbkType_FromSpec(&newspec)); + Shiboken::AutoDecRef bases(PyTuple_New(1)); + static auto basetype = SbkEnum_TypeF(); + PyTuple_SetItem(bases, 0, reinterpret_cast<PyObject *>(basetype)); + auto *type = reinterpret_cast<PyTypeObject *>(SbkType_FromSpecWithBases(&newspec, bases)); Py_TYPE(type) = SbkEnumType_TypeF(); auto *enumType = reinterpret_cast<SbkEnumType *>(type); diff --git a/sources/shiboken6/libshiboken/sbkenum.h b/sources/shiboken6/libshiboken/sbkenum.h index c294c17d9..236f4a15e 100644 --- a/sources/shiboken6/libshiboken/sbkenum.h +++ b/sources/shiboken6/libshiboken/sbkenum.h @@ -46,6 +46,9 @@ extern "C" { +/// exposed for the signature module +LIBSHIBOKEN_API void init_enum(); + extern LIBSHIBOKEN_API PyTypeObject *SbkEnumType_TypeF(void); struct SbkObjectType; struct SbkConverter; diff --git a/sources/shiboken6/libshiboken/signature/signature_globals.cpp b/sources/shiboken6/libshiboken/signature/signature_globals.cpp index 6af64682e..d23ae15d0 100644 --- a/sources/shiboken6/libshiboken/signature/signature_globals.cpp +++ b/sources/shiboken6/libshiboken/signature/signature_globals.cpp @@ -48,6 +48,7 @@ #include "sbkstring.h" #include "sbkstaticstrings.h" #include "sbkstaticstrings_p.h" +#include "sbkenum.h" #include "signature_p.h" @@ -289,6 +290,8 @@ void init_module_2(void) // Therefore we set init_done prior to init_phase_2(). init_done = 1; init_phase_2(pyside_globals, signature_methods); + // Enum must be initialized when signatures exist, not earlier. + init_enum(); } } diff --git a/sources/shiboken6/tests/samplebinding/enum_test.py b/sources/shiboken6/tests/samplebinding/enum_test.py index e425cb6ba..10c18c3bc 100644 --- a/sources/shiboken6/tests/samplebinding/enum_test.py +++ b/sources/shiboken6/tests/samplebinding/enum_test.py @@ -3,7 +3,7 @@ # ############################################################################# ## -## Copyright (C) 2016 The Qt Company Ltd. +## Copyright (C) 2021 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of the test suite of Qt for Python. @@ -141,6 +141,19 @@ class EnumTest(unittest.TestCase): self.assertEqual(SampleNamespace.enumArgumentWithDefaultValue(), SampleNamespace.UnixTime) self.assertEqual(SampleNamespace.enumArgumentWithDefaultValue(SampleNamespace.RandomNumber), SampleNamespace.RandomNumber) + def testSignature(self): + enum = SampleNamespace.Option(1) + types = type(enum).mro() + klass = types[0] + base = types[1] + # The class has an empty signature. + self.assertEqual(klass.__signature__, None) + # The base class must be Enum + self.assertNotEqual(base.__signature__, None) + # It contains an int annotation. + param = base.__signature__.parameters["itemValue"] + self.assertEqual(param.annotation, int) + class MyEvent(Event): def __init__(self): |