aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Tismer <tismer@stackless.com>2021-01-13 13:49:42 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2021-03-03 13:14:41 +0000
commit9819a81a96ce7b504144cfda94c8b70c3ab1671e (patch)
tree81c37093da36ffaf3632f64cee22cb21d1dbbdc6
parent53f9ee38f1f37a8a98373f7a21814159dccdbed6 (diff)
shiboken: Provide the correct inheritance for enum types
Originally, it was planned to follow a competitor and derive enums from int objects. But this was abandoned in favor of Python Enums. We therefore simply leave most code as it is and only insert a Shiboken::Enum class that accepts an optional integer. This class is published by shiboken with signature. Derived classes still have no signature themselves, but they all inherit from this known class Enum. This is intentional to avoid creating useless signatures for every derived Enum. A test was included. Change-Id: Ifaaea40a4ddf2337e565fb57e6a69b7cc9a6040f Fixes: PYSIDE-1347 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io> (cherry picked from commit e6a4a094ace43250e3ffca03a9f8d1f138de1b5a) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--sources/shiboken6/libshiboken/sbkenum.cpp117
-rw-r--r--sources/shiboken6/libshiboken/sbkenum.h3
-rw-r--r--sources/shiboken6/libshiboken/signature/signature_globals.cpp3
-rw-r--r--sources/shiboken6/tests/samplebinding/enum_test.py15
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):