1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
// Copyright (C) 2025 Ford Motor Company
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "pysidedynamiccommon_p.h"
#include "pysidedynamicenum_p.h"
#include <sbkstring.h>
#include <QtCore/qmetaobject.h>
int capsule_count = 0;
using namespace Shiboken;
PyObject *toPython(const QVariant &variant)
{
auto metaType = variant.metaType();
Conversions::SpecificConverter converter(metaType.name());
auto *value = converter.toPython(variant.data());
if (metaType.flags().testFlag(QMetaType::IsGadget)) {
// A single converter is used for all POD types - it converts to a Python
// tuple. We need an additional step to convert to our Python type for the POD.
// Thankfully, the converter stores the specific type we created, so we can call
// the constructor with the tuple.
auto *podType = Conversions::getPythonTypeObject(converter);
if (!podType) {
Py_DECREF(value);
PyErr_SetString(PyExc_RuntimeError, "Failed to get Python type for POD");
return nullptr;
}
PyObject *podValue = PyObject_CallObject(reinterpret_cast<PyObject *>(podType), value);
Py_DECREF(value);
if (!podValue) {
PyErr_SetString(PyExc_RuntimeError, "Failed to create POD instance");
return nullptr;
}
return podValue;
}
if (metaType.flags().testFlag(QMetaType::IsEnumeration)) {
// Enums are converted to Python ints
auto *enumType = Conversions::getPythonTypeObject(converter);
if (!enumType) {
Py_DECREF(value);
PyErr_SetString(PyExc_RuntimeError, "Failed to get Python type for enum");
return nullptr;
}
PyObject *enumValue = PyObject_CallFunctionObjArgs(reinterpret_cast<PyObject *>(enumType),
value, nullptr);
Py_DECREF(value);
if (!enumValue) {
PyErr_Print();
PyErr_SetString(PyExc_RuntimeError, "Failed to create enum instance");
return nullptr;
}
return enumValue;
}
return value;
}
/**
* @brief Creates and manages memory for Python enum types for each QEnum in the
* provided QMetaObject.
*
* This function iterates over the enumerators in the provided QMetaObject,
* creates corresponding Python enum types, and stores them in a dictionary.
* The dictionary is then set as an attribute ()"_enum_data") on the provided
* Python object, to be accessed by the _get_enum that has been added to each
* of our dynamic types.
*
* These are "managed" in the sense that the enums clean up their converters
* using our PyCapsule method, and by adding the dictionary as a Python attribute,
* the dictionary will be cleaned up when the containing type is garbage
* collected.
*
* @param self A pointer to the Python object where the enum data will be stored.
* @param meta A pointer to the QMetaObject containing the enumerators.
* @return Returns 0 on success, or -1 on failure.
*/
int create_managed_py_enums(PyObject *self, QMetaObject *meta)
{
PyObject *enum_data = PyDict_New();
for (int i = meta->enumeratorOffset(); i < meta->enumeratorCount(); ++i) {
auto metaEnum = meta->enumerator(i);
auto *enumType = createEnumType(&metaEnum);
if (!enumType) {
PyErr_Print();
PyErr_Format(PyExc_RuntimeError, "Failed to create enum type for POD '%s'",
meta->className());
return -1;
}
PyDict_SetItemString(enum_data, metaEnum.enumName(),
reinterpret_cast<PyObject *>(enumType));
Py_DECREF(enumType);
}
if (PyObject_SetAttrString(self, "_enum_data", enum_data) < 0) {
PyErr_Print();
qWarning() << "Failed to set _enum_data attribute on type"
<< reinterpret_cast<PyTypeObject *>(self)->tp_name;
return -1;
}
Py_DECREF(enum_data);
return 0;
}
PyObject *DynamicType_get_enum(PyObject *self, PyObject *name)
{
// Our enum types are always stored in a dictionary attribute named "_enum_data"
PyObject *enum_dict = PyObject_GetAttrString(self, "_enum_data");
if (!enum_dict) {
PyErr_SetString(PyExc_RuntimeError, "Failed to get _enum_data attribute");
return nullptr;
}
PyObject *enum_type = PyDict_GetItem(enum_dict, name);
Py_DECREF(enum_dict);
if (!enum_type) {
PyErr_Format(PyExc_KeyError, "Enum '%s' not found", String::toCString(name));
return nullptr;
}
Py_INCREF(enum_type);
return enum_type;
}
|