aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken6/libshiboken/sbktypefactory.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken6/libshiboken/sbktypefactory.cpp')
-rw-r--r--sources/shiboken6/libshiboken/sbktypefactory.cpp69
1 files changed, 63 insertions, 6 deletions
diff --git a/sources/shiboken6/libshiboken/sbktypefactory.cpp b/sources/shiboken6/libshiboken/sbktypefactory.cpp
index 0da1a8e23..079548eed 100644
--- a/sources/shiboken6/libshiboken/sbktypefactory.cpp
+++ b/sources/shiboken6/libshiboken/sbktypefactory.cpp
@@ -7,6 +7,8 @@
extern "C"
{
+using Shiboken::AutoDecRef;
+
PyTypeObject *SbkType_FromSpec(PyType_Spec *spec)
{
return SbkType_FromSpec_BMDWB(spec, nullptr, nullptr, 0, 0, nullptr);
@@ -37,6 +39,60 @@ static PyObject *_PyType_FromSpecWithBases(PyType_Spec *, PyObject *);
#endif // PYPY_VERSION
+// PYSIDE-2230: Not so temporary fix for Python 3.12.
+// A tp_new is no longer allowed in a meta class.
+// Hopefully, the Python devs will supply the missing support.
+// It turned out that they will not fix that, as expected.
+// Note: Python 3.12 is the first version that grabs the metaclass from base classes.
+static PyObject *_PyType_FromSpecWithBasesHack(PyType_Spec *spec,
+ PyObject *bases,
+ PyTypeObject *meta)
+{
+ PyTypeObject *keepMeta{};
+ newfunc keepNew{};
+ AutoDecRef basesPatch{};
+
+ if (bases) {
+ if (bases == Py_None) {
+ // PYSIDE-2230: This is the SbkObject entry which has no base to provide
+ // the metaclass. We patch it in by modifying `object`s class.
+ assert(meta);
+ auto *base = reinterpret_cast<PyObject *>(&PyBaseObject_Type);
+ base->ob_type = meta;
+ basesPatch.reset(Py_BuildValue("(O)", &PyBaseObject_Type));
+ bases = basesPatch.object();
+ }
+
+ Py_ssize_t n = PyTuple_GET_SIZE(bases);
+ for (auto idx = 0; idx < n; ++idx) {
+ PyTypeObject *base = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(bases, idx));
+ PyTypeObject *meta = Py_TYPE(base);
+ if (meta->tp_new != PyType_Type.tp_new) {
+ // make sure there is no second meta class
+ assert(keepMeta == nullptr);
+ keepMeta = meta;
+ keepNew = meta->tp_new;
+ meta->tp_new = PyType_Type.tp_new;
+ }
+ }
+ }
+
+#if !defined(Py_LIMITED_API) && PY_VERSION_HEX >= 0x030C0000
+ auto *ret = PyType_FromMetaclass(meta, nullptr /*module*/, spec, bases);
+#else
+ auto *ret = _PyType_FromSpecWithBases(spec, bases);
+#endif
+
+ if (keepMeta)
+ keepMeta->tp_new = keepNew;
+ if (basesPatch.object()) {
+ // undo the metaclass patch.
+ auto *base = PyTuple_GET_ITEM(basesPatch.object(), 0);
+ base->ob_type = &PyType_Type;
+ }
+ return ret;
+}
+
PyTypeObject *SbkType_FromSpec_BMDWB(PyType_Spec *spec,
PyObject *bases,
PyTypeObject *meta,
@@ -61,7 +117,7 @@ PyTypeObject *SbkType_FromSpec_BMDWB(PyType_Spec *spec,
int package_level = atoi(spec->name);
const char *mod = new_spec.name = colon + 1;
- PyObject *obType = _PyType_FromSpecWithBases(&new_spec, bases);
+ PyObject *obType = _PyType_FromSpecWithBasesHack(&new_spec, bases, meta);
if (obType == nullptr)
return nullptr;
@@ -73,8 +129,8 @@ PyTypeObject *SbkType_FromSpec_BMDWB(PyType_Spec *spec,
qual = dot + 1;
}
int mlen = qual - mod - 1;
- Shiboken::AutoDecRef module(Shiboken::String::fromCString(mod, mlen));
- Shiboken::AutoDecRef qualname(Shiboken::String::fromCString(qual));
+ AutoDecRef module(Shiboken::String::fromCString(mod, mlen));
+ AutoDecRef qualname(Shiboken::String::fromCString(qual));
auto *type = reinterpret_cast<PyTypeObject *>(obType);
@@ -98,9 +154,10 @@ PyTypeObject *SbkType_FromSpec_BMDWB(PyType_Spec *spec,
// PyType_Ready too early. (at least in PyPy, which caused pretty long debugging.)
auto *ht = reinterpret_cast<PyHeapTypeObject *>(type);
ht->ht_qualname = qualname;
- if (PyDict_SetItem(type->tp_dict, Shiboken::PyMagicName::qualname(), qualname))
+ AutoDecRef tpDict(PepType_GetDict(type));
+ if (PyDict_SetItem(tpDict.object(), Shiboken::PyMagicName::qualname(), qualname))
return nullptr;
- if (PyDict_SetItem(type->tp_dict, Shiboken::PyMagicName::module(), module))
+ if (PyDict_SetItem(tpDict.object(), Shiboken::PyMagicName::module(), module))
return nullptr;
PyType_Ready(type);
#else
@@ -329,7 +386,7 @@ _PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
/// Here is the only change needed: Do not finalize type creation.
// if (PyType_Ready(type) < 0)
// goto fail;
- type->tp_dict = PyDict_New();
+ PepType_SetDict(type, PyDict_New());
/// This is not found in PyPy:
// if (type->tp_dictoffset) {
// res->ht_cached_keys = _PyDict_NewKeysForClass();