aboutsummaryrefslogtreecommitdiffstats
path: root/sources
diff options
context:
space:
mode:
authorChristian Tismer <tismer@stackless.com>2022-06-14 17:07:58 +0200
committerChristian Tismer <tismer@stackless.com>2022-06-15 08:58:56 +0200
commit4131e4549108bc53149a45b24ccc5b3a40b6cf60 (patch)
tree7ccc460a29b14824a027585883cef8579401c20e /sources
parentd78151f89b2c374af366bee536c8ceeae3b2ab5e (diff)
QEnum: Adapt to the new enum implementation
QEnum was implemented with Python enums, as opposed to the old C++ enums. Now that support for Python enums is built into PySide, it is necessary to keep the implementing Python modules always the same. This patch prepares QEnum and PyEnum compatibility for the upcoming embedding of old enum implementations. As a side effect: Python 3.6 and 3.7 had a hard-to-find refcount error when creating new enums. Task-number: PYSIDE-1735 Change-Id: Ic44459c8e319d6d0308c7366beafa6fe7df41b79 Pick-to: 6.3 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
Diffstat (limited to 'sources')
-rw-r--r--sources/pyside6/libpyside/pysideqenum.cpp32
-rw-r--r--sources/pyside6/tests/QtCore/qenum_test.py2
-rw-r--r--sources/shiboken6/libshiboken/sbkenum.cpp22
-rw-r--r--sources/shiboken6/libshiboken/sbkenum_p.h2
4 files changed, 28 insertions, 30 deletions
diff --git a/sources/pyside6/libpyside/pysideqenum.cpp b/sources/pyside6/libpyside/pysideqenum.cpp
index 3713e3c57..4ccbcbaff 100644
--- a/sources/pyside6/libpyside/pysideqenum.cpp
+++ b/sources/pyside6/libpyside/pysideqenum.cpp
@@ -111,38 +111,14 @@ int isFlag(PyObject *obType)
* The function is called in MetaObjectBuilderPrivate::parsePythonType
* again to obtain the flag value.
*/
- if (!PyType_Check(obType)) {
- PyErr_Format(PyExc_TypeError, "a class argument was expected, not a '%.200s' instance",
- Py_TYPE(obType)->tp_name);
- return -1;
- };
- auto *type = reinterpret_cast<PyTypeObject *>(obType);
- PyObject *mro = type->tp_mro;
- Py_ssize_t i, n = PyTuple_GET_SIZE(mro);
- bool right_module = false;
- bool have_enum = false;
- bool have_flag = false;
- bool have_members = PyObject_HasAttr(obType, PyMagicName::members());
- for (i = 0; i < n; i++) {
- obType = PyTuple_GET_ITEM(mro, i);
- type = reinterpret_cast<PyTypeObject *>(obType);
- AutoDecRef mod(PyObject_GetAttr(obType, PyMagicName::module()));
- QByteArray cmod = String::toCString(mod);
- QByteArray cname = type->tp_name;
- if (cmod == "enum") {
- right_module = true;
- if (cname == "Enum")
- have_enum = true;
- else if (cname == "Flag")
- have_flag = true;
- }
- }
- if (!right_module || !(have_enum || have_flag) || !have_members) {
+ int res = enumIsFlag(obType);
+ if (res < 0) {
+ auto *type = reinterpret_cast<PyTypeObject *>(obType);
PyErr_Format(PyExc_TypeError, "type %.200s does not inherit from 'Enum' or 'Flag'",
type->tp_name);
return -1;
}
- return bool(have_flag);
+ return bool(res);
}
PyObject *QEnumMacro(PyObject *pyenum, bool flag)
diff --git a/sources/pyside6/tests/QtCore/qenum_test.py b/sources/pyside6/tests/QtCore/qenum_test.py
index 141c48f31..aa9dfbb60 100644
--- a/sources/pyside6/tests/QtCore/qenum_test.py
+++ b/sources/pyside6/tests/QtCore/qenum_test.py
@@ -184,12 +184,10 @@ class SomeClass(QObject):
@unittest.skipUnless(HAVE_ENUM, "requires 'enum' module (use 'pip install enum34' for Python 2)")
class TestQEnumMacro(unittest.TestCase):
def testTopLevel(self):
- self.assertEqual(type(OuterEnum).__module__, "enum")
self.assertEqual(type(OuterEnum).__name__, "EnumMeta")
self.assertEqual(len(OuterEnum.__members__), 2)
def testSomeClass(self):
- self.assertEqual(type(SomeClass.SomeEnum).__module__, "enum")
self.assertEqual(type(SomeClass.SomeEnum).__name__, "EnumMeta")
self.assertEqual(len(SomeClass.SomeEnum.__members__), 3)
with self.assertRaises(TypeError):
diff --git a/sources/shiboken6/libshiboken/sbkenum.cpp b/sources/shiboken6/libshiboken/sbkenum.cpp
index 17abb43ce..b9427142d 100644
--- a/sources/shiboken6/libshiboken/sbkenum.cpp
+++ b/sources/shiboken6/libshiboken/sbkenum.cpp
@@ -444,6 +444,24 @@ void init_enum()
is_initialized = true;
}
+// PYSIDE-1735: Helper function supporting QEnum
+int enumIsFlag(PyObject *ob_type)
+{
+ init_enum();
+
+ auto *metatype = Py_TYPE(ob_type);
+ if (metatype != reinterpret_cast<PyTypeObject *>(PyEnumMeta))
+ return -1;
+ auto *mro = reinterpret_cast<PyTypeObject *>(ob_type)->tp_mro;
+ Py_ssize_t idx, n = PyTuple_GET_SIZE(mro);
+ for (idx = 0; idx < n; idx++) {
+ auto *sub_type = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, idx));
+ if (sub_type == reinterpret_cast<PyTypeObject *>(PyFlag))
+ return 1;
+ }
+ return 0;
+}
+
} // extern "C"
//
@@ -986,6 +1004,10 @@ PyTypeObject *morphLastEnumToPython()
}
// Protect against double initialization
setp->replacementType = newType;
+#if PY_VERSION_HEX < 0x03080000
+ // PYSIDE-1735: Old Python versions can't stand the early enum deallocation.
+ Py_INCREF(enumType);
+#endif
return newType;
}
diff --git a/sources/shiboken6/libshiboken/sbkenum_p.h b/sources/shiboken6/libshiboken/sbkenum_p.h
index 77561a232..76d28bc26 100644
--- a/sources/shiboken6/libshiboken/sbkenum_p.h
+++ b/sources/shiboken6/libshiboken/sbkenum_p.h
@@ -22,6 +22,8 @@ LIBSHIBOKEN_API PyTypeObject *mapFlagsToSameEnum(PyTypeObject *FType, PyTypeObje
/// PYSIDE-1735: Make sure that we can import the Python enum implementation.
LIBSHIBOKEN_API PyTypeObject *getPyEnumMeta();
+// PYSIDE-1735: Helper function supporting QEnum
+LIBSHIBOKEN_API int enumIsFlag(PyObject *ob_enum);
}