aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sources/pyside2/tests/QtCore/qenum_test.py33
-rw-r--r--sources/shiboken2/libshiboken/pep384impl.cpp32
-rw-r--r--sources/shiboken2/libshiboken/pep384impl.h9
-rw-r--r--sources/shiboken2/libshiboken/sbkenum.cpp102
-rw-r--r--sources/shiboken2/libshiboken/sbkenum.h2
-rw-r--r--sources/shiboken2/shibokenmodule/typesystem_shiboken.xml6
6 files changed, 183 insertions, 1 deletions
diff --git a/sources/pyside2/tests/QtCore/qenum_test.py b/sources/pyside2/tests/QtCore/qenum_test.py
index dd91d1581..ed58f4f20 100644
--- a/sources/pyside2/tests/QtCore/qenum_test.py
+++ b/sources/pyside2/tests/QtCore/qenum_test.py
@@ -32,13 +32,15 @@
import os
import sys
+import pickle
import unittest
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from init_paths import init_test_paths
init_test_paths(False)
-from PySide2.QtCore import *
+from PySide2.QtCore import Qt, QIODevice
+
class TestEnum(unittest.TestCase):
@@ -73,6 +75,7 @@ class TestEnum(unittest.TestCase):
with self.assertRaises(TypeError):
a = k*2.0
+
class TestQFlags(unittest.TestCase):
def testToItn(self):
om = QIODevice.NotOpen
@@ -94,5 +97,33 @@ class TestQFlags(unittest.TestCase):
except:
pass
+
+# PYSIDE-15: Pickling of enums
+class TestEnumPickling(unittest.TestCase):
+ def testPickleEnum(self):
+
+ # Pickling of enums with different depth works.
+ ret = pickle.loads(pickle.dumps(QIODevice.Append))
+ self.assertEqual(ret, QIODevice.Append)
+
+ ret = pickle.loads(pickle.dumps(Qt.Key.Key_Asterisk))
+ self.assertEqual(ret, Qt.Key.Key_Asterisk)
+ self.assertEqual(ret, Qt.Key(42))
+
+ # We can also pickle the whole enum class (built in):
+ ret = pickle.loads(pickle.dumps(QIODevice))
+
+ # This works also with nested classes for Python 3, after we
+ # introduced the correct __qualname__ attribute.
+
+ # Note: For Python 2, we would need quite strange patches.
+ func = lambda: pickle.loads(pickle.dumps(Qt.Key))
+ if sys.version_info[0] < 3:
+ with self.assertRaises(pickle.PicklingError):
+ func()
+ else:
+ func()
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/sources/shiboken2/libshiboken/pep384impl.cpp b/sources/shiboken2/libshiboken/pep384impl.cpp
index c04848eb3..6405d777a 100644
--- a/sources/shiboken2/libshiboken/pep384impl.cpp
+++ b/sources/shiboken2/libshiboken/pep384impl.cpp
@@ -638,6 +638,38 @@ PepType_GetNameStr(PyTypeObject *type)
/*****************************************************************************
*
+ * Newly introduced convenience functions
+ *
+ */
+#if PY_VERSION_HEX < 0x03070000
+
+PyObject *
+PyImport_GetModule(PyObject *name)
+{
+ PyObject *m;
+ PyObject *modules = PyImport_GetModuleDict();
+ if (modules == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "unable to get sys.modules");
+ return NULL;
+ }
+ Py_INCREF(modules);
+ if (PyDict_CheckExact(modules)) {
+ m = PyDict_GetItemWithError(modules, name); /* borrowed */
+ Py_XINCREF(m);
+ }
+ else {
+ m = PyObject_GetItem(modules, name);
+ if (m == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
+ PyErr_Clear();
+ }
+ }
+ Py_DECREF(modules);
+ return m;
+}
+
+#endif // PY_VERSION_HEX < 0x03070000
+/*****************************************************************************
+ *
* Extra support for name mangling
*
*/
diff --git a/sources/shiboken2/libshiboken/pep384impl.h b/sources/shiboken2/libshiboken/pep384impl.h
index e735095e8..c180a06c1 100644
--- a/sources/shiboken2/libshiboken/pep384impl.h
+++ b/sources/shiboken2/libshiboken/pep384impl.h
@@ -523,6 +523,15 @@ extern LIBSHIBOKEN_API PyTypeObject *PepMethodDescr_TypePtr;
/*****************************************************************************
*
+ * Newly introduced convenience functions
+ *
+ */
+#if PY_VERSION_HEX < 0x03070000
+LIBSHIBOKEN_API PyObject *PyImport_GetModule(PyObject *name);
+#endif // PY_VERSION_HEX < 0x03070000
+
+/*****************************************************************************
+ *
* Runtime support for Python 3.8 incompatibilities
*
*/
diff --git a/sources/shiboken2/libshiboken/sbkenum.cpp b/sources/shiboken2/libshiboken/sbkenum.cpp
index 2b80da112..5b9718738 100644
--- a/sources/shiboken2/libshiboken/sbkenum.cpp
+++ b/sources/shiboken2/libshiboken/sbkenum.cpp
@@ -361,6 +361,107 @@ PyObject *SbkEnumTypeTpNew(PyTypeObject *metatype, PyObject *args, PyObject *kwd
} // extern "C"
+///////////////////////////////////////////////////////////////
+//
+// PYSIDE-15: Pickling Support for Qt Enum objects
+// This works very well and fixes the issue.
+//
+extern "C" {
+
+static void init_enum(); // forward
+
+static PyObject *enum_unpickler = nullptr;
+
+// Pickling: reduce the Qt Enum object
+static PyObject *enum___reduce__(PyObject *obj)
+{
+ init_enum();
+ return Py_BuildValue("O(Ni)",
+ enum_unpickler,
+ Py_BuildValue("s", Py_TYPE(obj)->tp_name),
+ PyInt_AS_LONG(obj));
+}
+
+} // extern "C"
+
+namespace Shiboken { namespace Enum {
+
+// Unpickling: rebuild the Qt Enum object
+PyObject *unpickleEnum(PyObject *enum_class_name, PyObject *value)
+{
+ Shiboken::AutoDecRef parts(PyObject_CallMethod(enum_class_name,
+ const_cast<char *>("split"), const_cast<char *>("s"), "."));
+ if (parts.isNull())
+ return nullptr;
+ PyObject *top_name = PyList_GetItem(parts, 0); // borrowed ref
+ if (top_name == nullptr)
+ return nullptr;
+ PyObject *module = PyImport_GetModule(top_name);
+ if (module == nullptr) {
+ PyErr_Format(PyExc_ImportError, "could not import module %.200s",
+ Shiboken::String::toCString(top_name));
+ return nullptr;
+ }
+ Shiboken::AutoDecRef cur_thing(module);
+ int len = PyList_Size(parts);
+ for (int idx = 1; idx < len; ++idx) {
+ PyObject *name = PyList_GetItem(parts, idx); // borrowed ref
+ PyObject *thing = PyObject_GetAttr(cur_thing, name);
+ if (thing == nullptr) {
+ PyErr_Format(PyExc_ImportError, "could not import Qt Enum type %.200s",
+ Shiboken::String::toCString(enum_class_name));
+ return nullptr;
+ }
+ cur_thing.reset(thing);
+ }
+ PyObject *klass = cur_thing;
+ return PyObject_CallFunctionObjArgs(klass, value, nullptr);
+}
+
+} // namespace Enum
+} // namespace Shiboken
+
+extern "C" {
+
+// Initialization
+static bool _init_enum()
+{
+ static PyObject *shiboken_name = Py_BuildValue("s", "shiboken2");
+ if (shiboken_name == nullptr)
+ return false;
+ Shiboken::AutoDecRef shibo(PyImport_GetModule(shiboken_name));
+ if (shibo.isNull())
+ return false;
+ Shiboken::AutoDecRef sub(PyObject_GetAttr(shibo, shiboken_name));
+ PyObject *mod = sub.object();
+ if (mod == nullptr) {
+ // We are in the build dir and already in shiboken.
+ PyErr_Clear();
+ mod = shibo.object();
+ }
+ enum_unpickler = PyObject_GetAttrString(mod, "_unpickle_enum");
+ if (enum_unpickler == nullptr)
+ return false;
+ return true;
+}
+
+static void init_enum()
+{
+ if (!(enum_unpickler || _init_enum()))
+ Py_FatalError("could not load enum helper functions");
+}
+
+static PyMethodDef SbkEnumObject_Methods[] = {
+ {const_cast<char *>("__reduce__"), reinterpret_cast<PyCFunction>(enum___reduce__),
+ METH_NOARGS, nullptr},
+ {nullptr, nullptr, 0, nullptr} // Sentinel
+};
+
+} // extern "C"
+
+//
+///////////////////////////////////////////////////////////////
+
namespace Shiboken {
class DeclaredEnumTypes
@@ -521,6 +622,7 @@ static PyType_Slot SbkNewType_slots[] = {
{Py_tp_repr, (void *)SbkEnumObject_repr},
{Py_tp_str, (void *)SbkEnumObject_repr},
{Py_tp_getset, (void *)SbkEnumGetSetList},
+ {Py_tp_methods, (void *)SbkEnumObject_Methods},
{Py_tp_new, (void *)SbkEnum_tp_new},
{Py_nb_add, (void *)enum_add},
{Py_nb_subtract, (void *)enum_subtract},
diff --git a/sources/shiboken2/libshiboken/sbkenum.h b/sources/shiboken2/libshiboken/sbkenum.h
index 759d72636..c294c17d9 100644
--- a/sources/shiboken2/libshiboken/sbkenum.h
+++ b/sources/shiboken2/libshiboken/sbkenum.h
@@ -114,6 +114,8 @@ namespace Enum
LIBSHIBOKEN_API void setTypeConverter(PyTypeObject *enumType, SbkConverter *converter);
/// Returns the converter assigned to the enum \p type.
LIBSHIBOKEN_API SbkConverter *getTypeConverter(PyTypeObject *enumType);
+
+ LIBSHIBOKEN_API PyObject *unpickleEnum(PyObject *, PyObject *);
}
} // namespace Shiboken
diff --git a/sources/shiboken2/shibokenmodule/typesystem_shiboken.xml b/sources/shiboken2/shibokenmodule/typesystem_shiboken.xml
index bdb0c9338..3eba557fb 100644
--- a/sources/shiboken2/shibokenmodule/typesystem_shiboken.xml
+++ b/sources/shiboken2/shibokenmodule/typesystem_shiboken.xml
@@ -103,6 +103,12 @@
</inject-code>
</add-function>
+ <add-function signature="_unpickle_enum(PyObject*, PyObject*)" return-type="PyObject*">
+ <inject-code>
+ %PYARG_0 = Shiboken::Enum::unpickleEnum(%1, %2);
+ </inject-code>
+ </add-function>
+
<extra-includes>
<include file-name="sbkversion.h" location="local"/>
<include file-name="voidptr.h" location="local"/>