aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Tismer <tismer@stackless.com>2022-08-03 16:30:51 +0200
committerChristian Tismer <tismer@stackless.com>2022-08-15 10:08:46 +0200
commite0687b1d5157125ba67dfaaa6da48136594158b3 (patch)
treeb7b86db7241c74ffcda94584ca45cd978c9815ea
parent0c68fb19e4827f9cae3096d466079db812272b61 (diff)
PyEnum: Define a fixed list of Int(Enum|Flag) decisions
This was "PyEnum: Write a default Int decisor for Enum and Flag". Historically, C++ enums were all compatible with int. The new Python enums are more diverse here. There are the basic types Enum/IntEnum and Flag/IntFlag. We have tried a lot to come up with a sensible default heuristic computed from the data. In the end, this was reverted and replaced by a fixed list that was collected from similar implementations. By the move away from Int inheritance, a few classes needed extra support. Python 3.11.0b5 also required the Flag creation parameter "boundary=KEEP". It is not clear if this is correct, yet. [ChangeLog][shiboken6] Most former IntEnum/IntFlag are replaced by pure Enum/Flag classes in a generally compatible way to other implementations. Change-Id: I1dbe7b0556a3375df89eb40e9d9f495f14bf42b1 Task-number: PYSIDE-1735 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Shyamnath Premnadh <Shyamnath.Premnadh@qt.io> Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io> (cherry picked from commit 0f5dcb03eb258280acd10a0f4f2889301a9ef365)
-rw-r--r--sources/pyside6/PySide6/QtCore/typesystem_core_common.xml38
-rw-r--r--sources/pyside6/PySide6/QtGui/typesystem_gui_common.xml10
-rw-r--r--sources/pyside6/PySide6/QtMultimedia/typesystem_multimedia.xml2
-rw-r--r--sources/pyside6/PySide6/QtQuick/typesystem_quick.xml2
-rw-r--r--sources/pyside6/PySide6/QtSerialPort/typesystem_serialport.xml2
-rw-r--r--sources/pyside6/PySide6/QtWidgets/typesystem_widgets_common.xml34
-rw-r--r--sources/pyside6/PySide6/glue/qtcore.cpp15
-rw-r--r--sources/pyside6/tests/QtCore/qenum_test.py14
-rw-r--r--sources/pyside6/tests/QtCore/qflags_test.py1
-rw-r--r--sources/pyside6/tests/QtCore/qsysinfo_test.py10
-rw-r--r--sources/pyside6/tests/QtGui/qpen_test.py3
-rw-r--r--sources/pyside6/tests/QtSql/qvarianttype_test.py7
-rw-r--r--sources/pyside6/tests/pysidetest/qvariant_test.py2
-rw-r--r--sources/shiboken6/generator/shiboken/cppgenerator.cpp108
-rw-r--r--sources/shiboken6/libshiboken/basewrapper_p.h3
-rw-r--r--sources/shiboken6/libshiboken/sbkenum.cpp52
-rw-r--r--sources/shiboken6/libshiboken/sbkenum_p.h3
-rw-r--r--sources/shiboken6/libshiboken/sbkfeature_base.cpp24
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py7
19 files changed, 259 insertions, 78 deletions
diff --git a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml
index c471cecef..2942e3d38 100644
--- a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml
+++ b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml
@@ -331,8 +331,13 @@
<value-type name="QKeyCombination"/>
<value-type name="QMetaType">
- <enum-type name="Type"/>
+ <enum-type name="Type" python-type="IntEnum"/>
<enum-type name="TypeFlag" flags="TypeFlags"/>
+ <!-- PYSIDE-1735: The class QMetaType.Type must be allowed because int is gone -->
+ <add-function signature="QMetaType(QMetaType::Type)">
+ <inject-code class="target" position="beginning" file="../glue/qtcore.cpp"
+ snippet="metatype-from-metatype-type"/>
+ </add-function>
<conversion-rule>
<native-to-target file="../glue/qtcore.cpp" snippet="conversion-qmetatype-pytypeobject"/>
<target-to-native>
@@ -525,7 +530,7 @@
<extra-includes>
<include file-name="QtCore/QProperty" location="global"/>
</extra-includes>
- <enum-type name="AlignmentFlag" flags="Alignment"/>
+ <enum-type name="AlignmentFlag" python-type="IntFlag" flags="Alignment"/>
<enum-type name="AnchorPoint" since="4.6"/>
<enum-type name="ApplicationAttribute"/>
<enum-type name="ApplicationState" flags="ApplicationStates" since="5.1"/>
@@ -556,7 +561,7 @@
<enum-type name="FocusReason"/>
<enum-type name="GestureFlag" flags="GestureFlags" since="4.6"/>
<enum-type name="GestureState" since="4.6"/>
- <enum-type name="GestureType" since="4.6"/>
+ <enum-type name="GestureType" python-type="IntEnum" since="4.6"/>
<enum-type name="GlobalColor"/>
<enum-type name="HighDpiScaleFactorRoundingPolicy" since="5.14"/>
<enum-type name="HitTestAccuracy"/>
@@ -564,11 +569,11 @@
<enum-type name="InputMethodHint" flags="InputMethodHints" since="4.6"/>
<enum-type name="InputMethodQuery" flags="InputMethodQueries"/>
<enum-type name="EnterKeyType" since="5.6"/>
- <enum-type name="ItemDataRole"/>
+ <enum-type name="ItemDataRole" python-type="IntEnum"/>
<enum-type name="ItemFlag" flags="ItemFlags"/>
<enum-type name="ItemSelectionMode"/>
<enum-type name="ItemSelectionOperation" since="5.5"/>
- <enum-type name="Key"/>
+ <enum-type name="Key" python-type="IntEnum"/>
<enum-type name="KeyboardModifier" flags="KeyboardModifiers"/>
<enum-type name="LayoutDirection"/>
<enum-type name="MaskMode"/>
@@ -594,7 +599,7 @@
<enum-type name="SplitBehaviorFlags" flags="SplitBehavior" since="5.14"/>
<enum-type name="TabFocusBehavior" since="5.5"/>
<enum-type name="TextElideMode"/>
- <enum-type name="TextFlag"/>
+ <enum-type name="TextFlag" python-type="IntFlag"/>
<enum-type name="TextFormat"/>
<enum-type name="TextInteractionFlag" flags="TextInteractionFlags"/>
<enum-type name="TileRule" since="4.6"/>
@@ -611,7 +616,7 @@
<enum-type name="WindowFrameSection"/>
<enum-type name="WindowModality"/>
<enum-type name="WindowState" flags="WindowStates"/>
- <enum-type name="WindowType" flags="WindowFlags"/>
+ <enum-type name="WindowType" python-type="IntFlag" flags="WindowFlags"/>
<enum-type name="CursorMoveStyle" since="4.8" revision="4800"/>
<modify-function signature="^operator.\(Qt::AlignmentFlag,Qt::TextFlag\)$"
@@ -867,6 +872,10 @@
<add-function signature="QDateTime(int,int,int,int,int,int)">
<inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qdatetime-2"/>
</add-function>
+ <!-- PYSIDE-1735: Qt::TimeSpec is no more compatible with int -->
+ <add-function signature="QDateTime(int,int,int,int,int,int,int,Qt::TimeSpec=Qt::LocalTime)">
+ <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qdatetime-3"/>
+ </add-function>
<add-function signature="__repr__" return-type="PyObject*">
<inject-code class="target" position="beginning">
<insert-template name="repr_code">
@@ -1295,10 +1304,10 @@
<value-type name="QLocale">
<enum-type name="Country"/>
<enum-type name="DataSizeFormat" flags="DataSizeFormats" since="5.10"/>
- <enum-type name="FloatingPointPrecisionOption" since="5.7"/>
+ <enum-type name="FloatingPointPrecisionOption" python-type="IntEnum" since="5.7"/>
<enum-type name="FormatType"/>
<enum-type name="Language"/>
- <enum-type name="LanguageCodeType" flags="LanguageCodeTypes" since="6.3"/>
+ <enum-type name="LanguageCodeType" python-type="IntFlag" flags="LanguageCodeTypes" since="6.3"/>
<enum-type name="MeasurementSystem"/>
<enum-type name="NumberOption" flags="NumberOptions"/>
<enum-type name="Script" since="4.8" revision="4800"/>
@@ -1793,9 +1802,9 @@
<value-type name="QUrl" hash-function="PySide::hash">
<!-- Qt5: lots of changes -->
- <enum-type name="ComponentFormattingOption" flags="ComponentFormattingOptions,FormattingOptions"/>
+ <enum-type name="ComponentFormattingOption" python-type="IntFlag" flags="ComponentFormattingOptions,FormattingOptions"/>
<!-- note: above duplication of attribute is not by default XML compliant! -->
- <enum-type name="UrlFormattingOption"/>
+ <enum-type name="UrlFormattingOption" python-type="IntFlag"/>
<enum-type name="UserInputResolutionOption" flags="UserInputResolutionOptions"/>
<enum-type name="ParsingMode"/>
<enum-type name="AceProcessingOption" flags="AceProcessingOptions" since="6.3"/>
@@ -2571,8 +2580,9 @@
</inject-documentation>
</add-function>
</object-type>
- <object-type name="QEvent" polymorphic-id-expression="%1-&gt;type() == QEvent::None">
- <enum-type name="Type"/>
+ <object-type name="QEvent" polymorphic-id-expression="%1-&gt;type() == QEvent::None"
+ qt-register-metatype="base">
+ <enum-type name="Type" python-type="IntEnum"/>
<add-function signature="__repr__" return-type="PyObject">
<inject-code class="target" position="beginning"
file="../glue/qtcore.cpp" snippet="repr-qevent"/>
@@ -2592,7 +2602,7 @@
<object-type name="QDataStream" stream="yes">
<enum-type name="FloatingPointPrecision" since="4.6"/>
<enum-type name="Status"/>
- <enum-type name="Version"/>
+ <enum-type name="Version" python-type="IntEnum"/>
<enum-type name="ByteOrder"/>
<extra-includes>
<include file-name="QtCore/QtCore" location="global"/>
diff --git a/sources/pyside6/PySide6/QtGui/typesystem_gui_common.xml b/sources/pyside6/PySide6/QtGui/typesystem_gui_common.xml
index 044cd434e..977bce148 100644
--- a/sources/pyside6/PySide6/QtGui/typesystem_gui_common.xml
+++ b/sources/pyside6/PySide6/QtGui/typesystem_gui_common.xml
@@ -519,10 +519,10 @@
<enum-type name="VerticalAlignment"/>
</value-type>
<value-type name="QTextFormat" >
- <enum-type name="FormatType"/>
- <enum-type name="ObjectTypes"/>
+ <enum-type name="FormatType" python-type="IntEnum"/>
+ <enum-type name="ObjectTypes" python-type="IntEnum"/>
<enum-type name="PageBreakFlag" flags="PageBreakFlags"/>
- <enum-type name="Property"/>
+ <enum-type name="Property" python-type="IntEnum"/>
</value-type>
<value-type name="QTextListFormat">
<enum-type name="Style"/>
@@ -696,11 +696,11 @@
<value-type name="QFont" >
<enum-type name="Capitalization"/>
<enum-type name="SpacingType"/>
- <enum-type name="Stretch"/>
+ <enum-type name="Stretch" python-type="IntEnum"/>
<enum-type name="Style"/>
<enum-type name="StyleHint"/>
<enum-type name="StyleStrategy"/>
- <enum-type name="Weight"/>
+ <enum-type name="Weight" python-type="IntEnum"/>
<enum-type name="HintingPreference" since="4.8" revision="4800"/>
<extra-includes>
<include file-name="QStringList" location="global"/>
diff --git a/sources/pyside6/PySide6/QtMultimedia/typesystem_multimedia.xml b/sources/pyside6/PySide6/QtMultimedia/typesystem_multimedia.xml
index 1bf22761b..1cd3412a3 100644
--- a/sources/pyside6/PySide6/QtMultimedia/typesystem_multimedia.xml
+++ b/sources/pyside6/PySide6/QtMultimedia/typesystem_multimedia.xml
@@ -146,7 +146,7 @@
<enum-type name="MediaStatus"/>
<enum-type name="PlaybackState" since="6.1"/>
<enum-type name="Error"/>
- <enum-type name="Loops" since="6.2.3"/>
+ <enum-type name="Loops" python-type="IntEnum" since="6.2.3"/>
</object-type>
<!-- see qtmultimedia/5773f7214c7430a98dea3974c0597cb3ee0ea7f5 might reappear in 6.3
<object-type name="QMediaPlaylist"/>
diff --git a/sources/pyside6/PySide6/QtQuick/typesystem_quick.xml b/sources/pyside6/PySide6/QtQuick/typesystem_quick.xml
index de257a93c..7fa7260b9 100644
--- a/sources/pyside6/PySide6/QtQuick/typesystem_quick.xml
+++ b/sources/pyside6/PySide6/QtQuick/typesystem_quick.xml
@@ -138,7 +138,7 @@
<object-type name="QSGGeometry">
<enum-type name="DataPattern"/>
<enum-type name="AttributeType" since="5.8"/>
- <enum-type name="DrawingMode" since="5.8"/>
+ <enum-type name="DrawingMode" python-type="IntEnum" since="5.8"/>
<enum-type name="Type" since="5.8"/>
<value-type name="Attribute"/>
<value-type name="AttributeSet"/>
diff --git a/sources/pyside6/PySide6/QtSerialPort/typesystem_serialport.xml b/sources/pyside6/PySide6/QtSerialPort/typesystem_serialport.xml
index 06b04856b..c08d5b2be 100644
--- a/sources/pyside6/PySide6/QtSerialPort/typesystem_serialport.xml
+++ b/sources/pyside6/PySide6/QtSerialPort/typesystem_serialport.xml
@@ -42,7 +42,7 @@
<typesystem package="PySide6.QtSerialPort">
<load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
<object-type name="QSerialPort">
- <enum-type name="BaudRate"/>
+ <enum-type name="BaudRate" python-type="IntEnum"/>
<enum-type name="DataBits"/>
<enum-type name="Direction" flags="Directions"/>
<enum-type name="FlowControl"/>
diff --git a/sources/pyside6/PySide6/QtWidgets/typesystem_widgets_common.xml b/sources/pyside6/PySide6/QtWidgets/typesystem_widgets_common.xml
index 55d45d068..1df831d72 100644
--- a/sources/pyside6/PySide6/QtWidgets/typesystem_widgets_common.xml
+++ b/sources/pyside6/PySide6/QtWidgets/typesystem_widgets_common.xml
@@ -219,7 +219,7 @@
<value-type name="QSizePolicy">
<enum-type name="ControlType" flags="ControlTypes"/>
<enum-type name="Policy"/>
- <enum-type name="PolicyFlag"/>
+ <enum-type name="PolicyFlag" python-type="IntFlag"/>
</value-type>
<value-type name="QTableWidgetSelectionRange"/>
@@ -509,7 +509,7 @@
</object-type>
<object-type name="QDateEdit"/>
<object-type name="QDialog">
- <enum-type name="DialogCode"/>
+ <enum-type name="DialogCode" python-type="IntEnum"/>
<modify-function signature="exec()" allow-thread="yes"/>
<add-function signature="exec_()" return-type="int">
<inject-code file="../glue/qtwidgets.cpp" snippet="qapplication-exec"/>
@@ -1154,17 +1154,17 @@
</add-function>
</object-type>
<object-type name="QStyle">
- <enum-type name="ComplexControl"/>
- <enum-type name="ContentsType"/>
- <enum-type name="ControlElement"/>
- <enum-type name="PixelMetric"/>
- <enum-type name="PrimitiveElement"/>
+ <enum-type name="ComplexControl" python-type="IntEnum"/>
+ <enum-type name="ContentsType" python-type="IntEnum"/>
+ <enum-type name="ControlElement" python-type="IntEnum"/>
+ <enum-type name="PixelMetric" python-type="IntEnum"/>
+ <enum-type name="PrimitiveElement" python-type="IntEnum"/>
<enum-type name="RequestSoftwareInputPanel" since="4.6"/>
- <enum-type name="StandardPixmap"/>
+ <enum-type name="StandardPixmap" python-type="IntEnum"/>
<enum-type name="StateFlag" flags="State"/>
- <enum-type name="StyleHint"/>
+ <enum-type name="StyleHint" python-type="IntEnum"/>
<enum-type name="SubControl" flags="SubControls"/>
- <enum-type name="SubElement"/>
+ <enum-type name="SubElement" python-type="IntEnum"/>
<modify-function signature="drawComplexControl(QStyle::ComplexControl,const QStyleOptionComplex*,QPainter*,const QWidget*)const">
<modify-argument index="3" invalidate-after-use="yes"/>
<modify-argument index="4">
@@ -1782,7 +1782,7 @@
<modify-function signature="closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)" allow-thread="yes"/>
</object-type>
<object-type name="QTableWidgetItem" >
- <enum-type name="ItemType"/>
+ <enum-type name="ItemType" python-type="IntEnum"/>
<modify-function signature="read(QDataStream&amp;)" allow-thread="yes">
<modify-argument index="1" invalidate-after-use="yes"/>
</modify-function>
@@ -1791,7 +1791,7 @@
</modify-function>
</object-type>
<object-type name="QListWidgetItem" >
- <enum-type name="ItemType"/>
+ <enum-type name="ItemType" python-type="IntEnum"/>
<modify-function signature="QListWidgetItem(const QString&amp;,QListWidget*,int)">
<modify-argument index="this">
<parent index="2" action="add"/>
@@ -1851,7 +1851,7 @@
</object-type>
<object-type name="QTreeWidgetItem" hash-function="qHash">
<enum-type name="ChildIndicatorPolicy"/>
- <enum-type name="ItemType"/>
+ <enum-type name="ItemType" python-type="IntEnum"/>
<modify-function signature="read(QDataStream&amp;)" allow-thread="yes">
<modify-argument index="1" invalidate-after-use="yes"/>
</modify-function>
@@ -2285,7 +2285,7 @@
<object-type name="QMessageBox">
<enum-type name="ButtonRole"/>
<enum-type name="Icon"/>
- <enum-type name="StandardButton" flags="StandardButtons"/>
+ <enum-type name="StandardButton" python-type="IntFlag" flags="StandardButtons"/>
<modify-function signature="removeButton(QAbstractButton*)">
<modify-argument index="1">
<parent index="this" action="add"/>
@@ -2740,8 +2740,8 @@
</modify-function>
</object-type>
<object-type name="QFrame">
- <enum-type name="Shadow"/>
- <enum-type name="Shape"/>
+ <enum-type name="Shadow" python-type="IntEnum"/>
+ <enum-type name="Shape" python-type="IntEnum"/>
<enum-type name="StyleMask"/>
</object-type>
<object-type name="QSpinBox"/>
@@ -2895,7 +2895,7 @@
<object-type name="QCommandLinkButton"/>
<!-- FIXME PYSIDE7: Move to QtGui -->
<object-type name="QFileSystemModel" polymorphic-id-expression="qobject_cast&lt;QFileSystemModel*&gt;(%1)">
- <enum-type name="Roles"/>
+ <enum-type name="Roles" python-type="IntEnum"/>
<enum-type name="Option" flags="Options" since="5.14"/>
<modify-function signature="setIconProvider(QAbstractFileIconProvider*)">
<modify-argument index="1">
diff --git a/sources/pyside6/PySide6/glue/qtcore.cpp b/sources/pyside6/PySide6/glue/qtcore.cpp
index 321aa7264..b0af6c354 100644
--- a/sources/pyside6/PySide6/glue/qtcore.cpp
+++ b/sources/pyside6/PySide6/glue/qtcore.cpp
@@ -127,6 +127,15 @@ else {
// @snippet qsettings-value
+// @snippet metatype-from-metatype-type
+Shiboken::AutoDecRef intArg;
+if (usingNewEnum())
+ intArg.reset(PyObject_GetAttrString(%PYARG_1, "value"));
+else
+ intArg.reset(PyObject_CallMethod(%PYARG_1, "__int__", nullptr));
+%0 = new %TYPE(PyLong_AsLong(intArg));
+// @snippet metatype-from-metatype-type
+
// @snippet conversion-pytypeobject-qmetatype
auto *pyType = reinterpret_cast<PyTypeObject *&>(%in);
if (Shiboken::String::checkType(pyType))
@@ -411,6 +420,12 @@ QTime time(%4, %5, %6);
%0 = new %TYPE(date, time);
// @snippet qdatetime-2
+// @snippet qdatetime-3
+QDate date(%1, %2, %3);
+QTime time(%4, %5, %6, %7);
+%0 = new %TYPE(date, time, %8);
+// @snippet qdatetime-3
+
// @snippet qdatetime-topython
QDate date = %CPPSELF.date();
QTime time = %CPPSELF.time();
diff --git a/sources/pyside6/tests/QtCore/qenum_test.py b/sources/pyside6/tests/QtCore/qenum_test.py
index 612a3873b..4514dd256 100644
--- a/sources/pyside6/tests/QtCore/qenum_test.py
+++ b/sources/pyside6/tests/QtCore/qenum_test.py
@@ -45,7 +45,7 @@ from PySide6.QtCore import Qt, QIODevice, QObject, QEnum, QFlag
class TestEnum(unittest.TestCase):
-
+ @unittest.skipIf(sys.pyside63_option_python_enum, "not adequate for new enums to ask the value")
def testToInt(self):
self.assertEqual(QIODevice.NotOpen, 0)
self.assertEqual(QIODevice.ReadOnly, 1)
@@ -56,6 +56,7 @@ class TestEnum(unittest.TestCase):
self.assertEqual(QIODevice.Text, 16)
self.assertEqual(QIODevice.Unbuffered, 32)
+ @unittest.skipIf(sys.pyside63_option_python_enum, "not adequate for new enums to ask the value")
def testToIntInFunction(self):
self.assertEqual(str(int(QIODevice.WriteOnly)), "2")
@@ -105,18 +106,21 @@ class TestEnum(unittest.TestCase):
class TestQFlags(unittest.TestCase):
+ newenum = sys.pyside63_option_python_enum
+
def testToItn(self):
om = QIODevice.NotOpen
+ omcmp = om.value if self.newenum else om
self.assertEqual(om, QIODevice.NotOpen)
- self.assertTrue(om == 0)
+ self.assertTrue(omcmp == 0)
- self.assertTrue(om != QIODevice.ReadOnly)
- self.assertTrue(om != 1)
+ self.assertTrue(omcmp != QIODevice.ReadOnly)
+ self.assertTrue(omcmp != 1)
def testToIntInFunction(self):
om = QIODevice.WriteOnly
- self.assertEqual(int(om), 2)
+ self.assertEqual(int(om.value if self.newenum else om), 2)
def testNonExtensibleEnums(self):
try:
diff --git a/sources/pyside6/tests/QtCore/qflags_test.py b/sources/pyside6/tests/QtCore/qflags_test.py
index 3800a003c..8cc0b36c0 100644
--- a/sources/pyside6/tests/QtCore/qflags_test.py
+++ b/sources/pyside6/tests/QtCore/qflags_test.py
@@ -120,6 +120,7 @@ class QFlagsOnQVariant(unittest.TestCase):
class QFlagsWrongType(unittest.TestCase):
+ @unittest.skipIf(sys.pyside63_option_python_enum, "Qt.ItemFlag is no longer an IntEnum")
def testWrongType(self):
'''Wrong type passed to QFlags binary operators'''
for op in operator.or_, operator.and_, operator.xor:
diff --git a/sources/pyside6/tests/QtCore/qsysinfo_test.py b/sources/pyside6/tests/QtCore/qsysinfo_test.py
index ebd0f82ee..b55d4380c 100644
--- a/sources/pyside6/tests/QtCore/qsysinfo_test.py
+++ b/sources/pyside6/tests/QtCore/qsysinfo_test.py
@@ -39,13 +39,15 @@ from PySide6.QtCore import QSysInfo
class TestQSysInfo(unittest.TestCase):
+ newenum = sys.pyside63_option_python_enum
+
def testEnumEndian(self):
- self.assertEqual(QSysInfo.BigEndian, 0)
- self.assertEqual(QSysInfo.LittleEndian, 1)
- self.assertTrue(QSysInfo.ByteOrder > -1)
+ self.assertEqual(QSysInfo.BigEndian.value if self.newenum else QSysInfo.BigEndian, 0)
+ self.assertEqual(QSysInfo.LittleEndian.value if self.newenum else QSysInfo.LittleEndian, 1)
+ self.assertTrue((QSysInfo.ByteOrder.value if self.newenum else QSysInfo.ByteOrder) > -1)
def testEnumSizes(self):
- self.assertTrue(QSysInfo.WordSize > 0)
+ self.assertTrue((QSysInfo.WordSize.value if self.newenum else QSysInfo.WordSize) > 0)
if __name__ == '__main__':
diff --git a/sources/pyside6/tests/QtGui/qpen_test.py b/sources/pyside6/tests/QtGui/qpen_test.py
index a1148b4fa..3c1ae9f6b 100644
--- a/sources/pyside6/tests/QtGui/qpen_test.py
+++ b/sources/pyside6/tests/QtGui/qpen_test.py
@@ -51,7 +51,8 @@ class Painting(QRasterWindow):
with QPainter(self) as painter:
painter.setPen(Qt.NoPen)
self.penFromEnum = painter.pen()
- painter.setPen(int(Qt.NoPen))
+ intVal = Qt.NoPen.value if sys.pyside63_option_python_enum else int(Qt.NoPen)
+ painter.setPen(intVal)
self.penFromInteger = painter.pen()
QTimer.singleShot(20, self.close)
diff --git a/sources/pyside6/tests/QtSql/qvarianttype_test.py b/sources/pyside6/tests/QtSql/qvarianttype_test.py
index 2b3dfa4b0..c62c7a55f 100644
--- a/sources/pyside6/tests/QtSql/qvarianttype_test.py
+++ b/sources/pyside6/tests/QtSql/qvarianttype_test.py
@@ -42,11 +42,14 @@ from PySide6.QtSql import QSqlField
class QVariantTypeTest(unittest.TestCase):
def testQVariantType(self):
+ new_enum = sys.pyside63_option_python_enum
+ cmp_id = QMetaType.QString.value if new_enum else QMetaType.QString
+
f = QSqlField("name", QMetaType(QMetaType.QString))
- self.assertEqual(f.metaType().id(), QMetaType.QString)
+ self.assertEqual(f.metaType().id(), cmp_id)
f = QSqlField("name", QMetaType.fromName(b"QString"))
- self.assertEqual(f.metaType().id(), QMetaType.QString)
+ self.assertEqual(f.metaType().id(), cmp_id)
f = QSqlField("name", QMetaType.fromName(b"double"))
self.assertEqual(f.metaType(), float)
diff --git a/sources/pyside6/tests/pysidetest/qvariant_test.py b/sources/pyside6/tests/pysidetest/qvariant_test.py
index 637aa95cf..c3d2614df 100644
--- a/sources/pyside6/tests/pysidetest/qvariant_test.py
+++ b/sources/pyside6/tests/pysidetest/qvariant_test.py
@@ -46,7 +46,7 @@ class QVariantTest(UsesQApplication):
def testQKeySequenceQVariantOperator(self):
# bug #775
- ks = QKeySequence(Qt.SHIFT, Qt.CTRL, Qt.Key_P, Qt.Key_R)
+ ks = QKeySequence(Qt.ShiftModifier, Qt.ControlModifier, Qt.Key_P, Qt.Key_R)
self.assertEqual(TestObject.checkType(ks), 4107)
diff --git a/sources/shiboken6/generator/shiboken/cppgenerator.cpp b/sources/shiboken6/generator/shiboken/cppgenerator.cpp
index 25d16615a..ae6d83dd5 100644
--- a/sources/shiboken6/generator/shiboken/cppgenerator.cpp
+++ b/sources/shiboken6/generator/shiboken/cppgenerator.cpp
@@ -388,15 +388,102 @@ static QString _plainName(const QString &s)
return cutPos < 0 ? s : s.right(s.length() - (cutPos + 2));
}
-static QString BuildEnumFlagInfo(const EnumTypeEntry *enumType)
+/**********************************************************************
+ *
+ * Decision whether to use an IntEnum/IntFlag
+ * ------------------------------------------
+ *
+ * Unfortunately, all attempts to drive this decision automagically
+ * did not work out. We therefore compile a list in with known
+ * IntEnum and IntFlag.
+ */
+
+/*
+ * This function is now unused and replaced by TypeSystem::PythonEnumType
+ */
+#if 0
+static QSet<QString> useIntSet()
+{
+ static const QSet<QString> result{
+ /* IntEnum */ u"PySide6.QtCore.QDataStream.Version"_s,
+ /* IntEnum */ u"PySide6.QtCore.QEvent.Type"_s,
+ /* IntEnum */ u"PySide6.QtCore.QLocale.FloatingPointPrecisionOption"_s,
+ /* IntFlag */ u"PySide6.QtCore.QLocale.LanguageCodeType"_s,
+ /* IntFlag */ u"PySide6.QtCore.QUrl.ComponentFormattingOption"_s,
+ // note: "QUrl::UrlFormattingOption" is set as IntFlag without flags
+ /* IntFlag */ u"PySide6.QtCore.QUrl.UrlFormattingOption"_s,
+ /* IntFlag */ u"PySide6.QtCore.Qt.AlignmentFlag"_s,
+ /* IntEnum */ u"PySide6.QtCore.Qt.GestureType"_s,
+ /* IntEnum */ u"PySide6.QtCore.Qt.ItemDataRole"_s,
+ /* IntEnum */ u"PySide6.QtCore.Qt.Key"_s,
+ // note: "Qt::TextFlag" is set as IntFlag without flags
+ /* IntFlag */ u"PySide6.QtCore.Qt.TextFlag"_s,
+ /* IntFlag */ u"PySide6.QtCore.Qt.WindowType"_s,
+ // This is found in QtWidgets but should be in QtGui.
+ /* IntEnum */ u"PySide6.QtGui.QFileSystemModel.Roles"_s,
+ /* IntEnum */ u"PySide6.QtGui.QFont.Stretch"_s,
+ /* IntEnum */ u"PySide6.QtGui.QFont.Weight"_s,
+ /* IntEnum */ u"PySide6.QtGui.QTextFormat.FormatType"_s,
+ /* IntEnum */ u"PySide6.QtGui.QTextFormat.ObjectTypes"_s,
+ /* IntEnum */ u"PySide6.QtGui.QTextFormat.Property"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QDialog.DialogCode"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QFrame.Shadow"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QFrame.Shape"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QListWidgetItem.ItemType"_s,
+ /* IntFlag */ u"PySide6.QtWidgets.QMessageBox.StandardButton"_s,
+ // note: "QSizePolicy::PolicyFlag" is set as IntFlag without flags
+ /* IntFlag */ u"PySide6.QtWidgets.QSizePolicy.PolicyFlag"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QStyle.ComplexControl"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QStyle.ContentsType"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QStyle.ControlElement"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QStyle.PixelMetric"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QStyle.PrimitiveElement"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QStyle.StandardPixmap"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QStyle.StyleHint"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QStyle.SubElement"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QTableWidgetItem.ItemType"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QTreeWidgetItem.ItemType"_s,
+ /* IntEnum */ u"PySide6.QtMultimedia.QMediaPlayer.Loops"_s,
+ /* IntEnum */ u"PySide6.QtQuick.QSGGeometry.DrawingMode"_s,
+ // Added because it should really be used as number
+ /* IntEnum */ u"PySide6.QtCore.QMetaType.Type"_s,
+ /* IntEnum */ u"PySide6.QtSerialPort.QSerialPort.BaudRate"_s
+ };
+ return result;
+}
+#endif
+
+static bool _shouldInheritInt(const AbstractMetaEnum &cppEnum)
+{
+ if (!cppEnum.fullName().startsWith(u"PySide6."_s))
+ return true;
+ // static auto intSet = useIntSet();
+ // return intSet.contains(cppEnum.fullName());
+ return false;
+}
+
+static QString BuildEnumFlagInfo(const AbstractMetaEnum &cppEnum)
{
+ auto *enumType = cppEnum.typeEntry();
QString result = _plainName(enumType->name());
auto flags = enumType->flags();
- if (flags) {
- result += u":IntFlag:"_s + _plainName(flags->flagsName());
- } else {
- result += u":IntEnum"_s;
- }
+ auto decision = enumType->pythonEnumType();
+ bool _int = _shouldInheritInt(cppEnum);
+ bool _flag = bool(flags);
+
+ if (decision != TypeSystem::PythonEnumType::Unspecified) {
+ _int = true;
+ if (!flags && decision == TypeSystem::PythonEnumType::IntFlag) {
+ qWarning() << "\nnote: " << enumType->name() << "is set as IntFlag without flags\n";
+ _flag = true;
+ }
+ if (flags && decision == TypeSystem::PythonEnumType::IntEnum)
+ qWarning() << "\n*** The expression " << enumType->name() << "should be a flag!\n";
+ }
+ result += _flag ? (_int ? u":IntFlag"_s : u":Flag"_s)
+ : (_int ? u":IntEnum"_s : u":Enum"_s);
+ if (flags)
+ result += u':' + _plainName(flags->flagsName());
return u'"' + result + u'"';
}
@@ -694,7 +781,7 @@ void CppGenerator::generateClass(TextStream &s, const GeneratorContext &classCon
// PYSIDE-1735: Write an EnumFlagInfo structure
QStringList sorter;
for (const auto &entry : qAsConst(classEnums))
- sorter.append(BuildEnumFlagInfo(entry.typeEntry()));
+ sorter.append(BuildEnumFlagInfo(entry));
sorter.sort();
if (!sorter.empty()) {
s << "static const char *" << className << "_EnumFlagInfo[] = {\n" << indent;
@@ -5965,10 +6052,11 @@ void CppGenerator::writeClassRegister(TextStream &s,
AbstractMetaEnumList classEnums = metaClass->enums();
metaClass->getEnumsFromInvisibleNamespacesToBeGenerated(&classEnums);
- writeEnumsInitialization(s, classEnums, ErrorReturn::Void);
if (!classContext.forSmartPointer() && !classEnums.isEmpty())
- s << "SbkObjectType_SetEnumFlagInfo(pyType, " << chopType(pyTypeName)
- << "_EnumFlagInfo);\n";
+ s << "// Pass the ..._EnumFlagInfo to the class.\n"
+ << "SbkObjectType_SetEnumFlagInfo(pyType, " << chopType(pyTypeName)
+ << "_EnumFlagInfo);\n\n";
+ writeEnumsInitialization(s, classEnums, ErrorReturn::Void);
if (metaClass->hasSignals())
writeSignalInitialization(s, metaClass);
diff --git a/sources/shiboken6/libshiboken/basewrapper_p.h b/sources/shiboken6/libshiboken/basewrapper_p.h
index 259206d7a..3e9ff17b0 100644
--- a/sources/shiboken6/libshiboken/basewrapper_p.h
+++ b/sources/shiboken6/libshiboken/basewrapper_p.h
@@ -150,7 +150,8 @@ struct SbkObjectTypePrivate
void (*subtype_init)(PyTypeObject *, PyObject *, PyObject *);
const char **propertyStrings;
const char **enumFlagInfo;
- PyObject *flagsDict;
+ PyObject *enumFlagsDict;
+ PyObject *enumIntSet;
};
diff --git a/sources/shiboken6/libshiboken/sbkenum.cpp b/sources/shiboken6/libshiboken/sbkenum.cpp
index baf6f0938..655fd9c58 100644
--- a/sources/shiboken6/libshiboken/sbkenum.cpp
+++ b/sources/shiboken6/libshiboken/sbkenum.cpp
@@ -435,6 +435,7 @@ static PyObject *PyEnum{};
static PyObject *PyIntEnum{};
static PyObject *PyFlag{};
static PyObject *PyIntFlag{};
+static PyObject *PyFlag_KEEP{};
PyTypeObject *getPyEnumMeta()
{
@@ -452,8 +453,12 @@ PyTypeObject *getPyEnumMeta()
PyFlag = PyObject_GetAttrString(mod, "Flag");
if (PyFlag && PyType_Check(PyFlag))
PyIntFlag = PyObject_GetAttrString(mod, "IntFlag");
- if (PyIntFlag && PyType_Check(PyIntFlag))
+ if (PyIntFlag && PyType_Check(PyIntFlag)) {
+ // KEEP is defined from Python 3.11 on.
+ PyFlag_KEEP = PyObject_GetAttrString(mod, "KEEP");
+ PyErr_Clear();
return reinterpret_cast<PyTypeObject *>(PyEnumMeta);
+ }
}
Py_FatalError("Python module 'enum' not found");
return nullptr;
@@ -989,6 +994,17 @@ static PyTypeObject *recordCurrentEnum(PyObject *scopeOrModule,
return nullptr;
}
+static bool is_old_version()
+{
+ auto *sysmodule = PyImport_AddModule("sys");
+ auto *dic = PyModule_GetDict(sysmodule);
+ auto *version = PyDict_GetItemString(dic, "version_info");
+ auto *major = PyTuple_GetItem(version, 0);
+ auto *minor = PyTuple_GetItem(version, 1);
+ auto number = PyLong_AsLong(major) * 1000 + PyLong_AsLong(minor);
+ return number <= 3008;
+}
+
PyTypeObject *morphLastEnumToPython()
{
/// The Python Enum internal structure is way too complicated.
@@ -1008,6 +1024,20 @@ PyTypeObject *morphLastEnumToPython()
// If that happens, use the existing new type to keep type checks correct.
return setp->replacementType;
}
+
+ auto *scopeOrModule = lec.scopeOrModule;
+ bool useInt = true;
+
+ if (PyType_Check(scopeOrModule)) {
+ // For global objects, we have no good solution, yet where to put the int info.
+ auto type = reinterpret_cast<PyTypeObject *>(scopeOrModule);
+ auto *sotp = PepType_SOTP(type);
+ if (!sotp->enumFlagsDict)
+ initEnumFlagsDict(type);
+ if (!PySet_Contains(sotp->enumIntSet, String::fromCString(lec.name)))
+ useInt = false;
+ }
+
PyObject *key, *value;
Py_ssize_t pos = 0;
PyObject *values = PyDict_GetItem(enumType->tp_dict, PyName::values());
@@ -1015,7 +1045,8 @@ PyTypeObject *morphLastEnumToPython()
return nullptr;
// Walk the values dict and create a Python enum type.
- auto *PyEnumType = lec.flagsType ? PyIntFlag : PyIntEnum;
+ auto *PyEnumType = lec.flagsType ? (useInt ? PyIntFlag : PyFlag)
+ : (useInt ? PyIntEnum : PyEnum);
AutoDecRef name(PyUnicode_FromString(lec.name));
AutoDecRef args(PyList_New(0));
auto *pyName = name.object();
@@ -1029,7 +1060,15 @@ PyTypeObject *morphLastEnumToPython()
PyTuple_SET_ITEM(key_value, 1, num);
PyList_Append(pyArgs, key_value);
}
- auto *obNewType = PyObject_CallFunctionObjArgs(PyEnumType, pyName, pyArgs, nullptr);
+ // We now create the new type. Since Python 3.11, we need to pass in
+ // `boundary=KEEP` because the default STRICT crashes on us.
+ // See QDir.Filter.Drives | QDir.Filter.Files
+ AutoDecRef callArgs(Py_BuildValue("(OO)", pyName, pyArgs));
+ AutoDecRef callDict(PyDict_New());
+ static PyObject *boundary = String::createStaticString("boundary");
+ if (PyFlag_KEEP)
+ PyDict_SetItem(callDict, boundary, PyFlag_KEEP);
+ auto *obNewType = PyObject_Call(PyEnumType, callArgs, callDict);
if (!obNewType || PyObject_SetAttr(lec.scopeOrModule, pyName, obNewType) < 0)
return nullptr;
auto *newType = reinterpret_cast<PyTypeObject *>(obNewType);
@@ -1040,10 +1079,11 @@ PyTypeObject *morphLastEnumToPython()
PyObject_SetAttr(obNewType, PyMagicName::module(), module);
// 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
+ static bool old_python_version = is_old_version();
+ if (old_python_version)
+ Py_INCREF(obEnumType);
return newType;
}
diff --git a/sources/shiboken6/libshiboken/sbkenum_p.h b/sources/shiboken6/libshiboken/sbkenum_p.h
index 1d71d7b27..5df8e87af 100644
--- a/sources/shiboken6/libshiboken/sbkenum_p.h
+++ b/sources/shiboken6/libshiboken/sbkenum_p.h
@@ -52,6 +52,9 @@ struct SbkEnumTypePrivate
extern "C" {
+/// PYSIDE-1735: Pass on the Python enum/flag information.
+LIBSHIBOKEN_API void initEnumFlagsDict(PyTypeObject *type);
+
/// PYSIDE-1735: Patching the Enum / Flags implementation. Remove in 6.4
LIBSHIBOKEN_API PyTypeObject *morphLastEnumToPython();
LIBSHIBOKEN_API PyTypeObject *mapFlagsToSameEnum(PyTypeObject *FType, PyTypeObject *EType);
diff --git a/sources/shiboken6/libshiboken/sbkfeature_base.cpp b/sources/shiboken6/libshiboken/sbkfeature_base.cpp
index 770735e5c..096568f4e 100644
--- a/sources/shiboken6/libshiboken/sbkfeature_base.cpp
+++ b/sources/shiboken6/libshiboken/sbkfeature_base.cpp
@@ -209,22 +209,32 @@ static bool currentOpcode_Is_CallMethNoArgs()
return opcode2 == PRECALL && oparg2 == 0;
}
-static void _initFlagsDict(SbkObjectTypePrivate *sotp)
+void initEnumFlagsDict(PyTypeObject *type)
{
+ // We create a dict for all flag enums that holds the original C++ name.
+ // We create a set for all int enums or flags.
static PyObject *const split = Shiboken::String::createStaticString("split");
static PyObject *const colon = Shiboken::String::createStaticString(":");
+ auto sotp = PepType_SOTP(type);
auto **enumFlagInfo = sotp->enumFlagInfo;
auto *dict = PyDict_New();
+ auto *set = PySet_New(nullptr);
for (; *enumFlagInfo; ++enumFlagInfo) {
AutoDecRef line(PyUnicode_FromString(*enumFlagInfo));
AutoDecRef parts(PyObject_CallMethodObjArgs(line, split, colon, nullptr));
+ auto *name = PyList_GetItem(parts, 0);
if (PyList_Size(parts) == 3) {
auto *key = PyList_GetItem(parts, 2);
- auto *value = PyList_GetItem(parts, 0);
+ auto *value = name;
PyDict_SetItem(dict, key, value);
}
+ auto *typeName = PyList_GetItem(parts, 1);
+ bool intFlag = strncmp(String::toCString(typeName), "Int", 3) == 0;
+ if (intFlag)
+ PySet_Add(set, name);
}
- sotp->flagsDict = dict;
+ sotp->enumFlagsDict = dict;
+ sotp->enumIntSet = set;
}
static PyObject *replaceNoArgWithZero(PyObject *callable)
@@ -287,12 +297,12 @@ PyObject *mangled_type_getattro(PyTypeObject *type, PyObject *name)
const char **enumFlagInfo = sotp->enumFlagInfo;
if (!(enumFlagInfo))
continue;
- if (!sotp->flagsDict)
- _initFlagsDict(sotp);
- auto *rename = PyDict_GetItem(sotp->flagsDict, name);
+ if (!sotp->enumFlagsDict)
+ initEnumFlagsDict(type_base);
+ auto *rename = PyDict_GetItem(sotp->enumFlagsDict, name);
if (rename) {
/*
- * Part 1: Look into the flagsDict if we have an old flags name.
+ * Part 1: Look into the enumFlagsDict if we have an old flags name.
* -------------------------------------------------------------
* We need to replace the parameterless
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py
index e7184fa25..6cd402de3 100644
--- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py
@@ -175,7 +175,9 @@ class ExactEnumerator(object):
self.collision_track.add(thing_name)
init_signature = getattr(klass, "__signature__", None)
- enums.sort(key=lambda tup: tup[1 : 3]) # sort by class then enum value
+ new_enum = sys.pyside63_option_python_enum
+ # sort by class then enum value
+ enums.sort(key=lambda tup: (tup[1], tup[2].value if new_enum else tup[2]))
# We want to handle functions and properties together.
func_prop = sorted(functions + properties, key=lambda tup: tup[0])
@@ -192,7 +194,8 @@ class ExactEnumerator(object):
if len(enums):
self.section()
for enum_name, enum_class_name, value in enums:
- with self.fmt.enum(enum_class_name, enum_name, int(value)):
+ with self.fmt.enum(enum_class_name, enum_name,
+ value.value if new_enum else value):
pass
if len(subclasses):
self.section()