diff options
19 files changed, 257 insertions, 77 deletions
diff --git a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml index bacccebe5..c4e35f5df 100644 --- a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml +++ b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml @@ -319,12 +319,17 @@ <extra-includes> <include file-name="pysidemetatype.h" location="global"/> </extra-includes> - <enum-type name="Type"/> + <enum-type name="Type" python-type="IntEnum"/> <enum-type name="TypeFlag" flags="TypeFlags"/> <add-function signature="QMetaType(PyTypeObject*)"> <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="metatype-from-type"/> </add-function> + <!-- 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> @@ -517,7 +522,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"/> @@ -548,7 +553,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"/> @@ -556,11 +561,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"/> @@ -586,7 +591,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"/> @@ -603,7 +608,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\)$" @@ -859,6 +864,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"> @@ -1287,10 +1296,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"/> @@ -1785,9 +1794,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"/> @@ -2569,7 +2578,7 @@ </object-type> <object-type name="QEvent" polymorphic-id-expression="%1->type() == QEvent::None" qt-register-metatype="base"> - <enum-type name="Type"/> + <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"/> @@ -2589,7 +2598,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 49399bc72..923abfd2a 100644 --- a/sources/pyside6/PySide6/QtGui/typesystem_gui_common.xml +++ b/sources/pyside6/PySide6/QtGui/typesystem_gui_common.xml @@ -478,10 +478,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"/> @@ -655,11 +655,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 7d59b4398..3fa7e6e6d 100644 --- a/sources/pyside6/PySide6/QtMultimedia/typesystem_multimedia.xml +++ b/sources/pyside6/PySide6/QtMultimedia/typesystem_multimedia.xml @@ -110,7 +110,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 f4cadad7c..87fcc8514 100644 --- a/sources/pyside6/PySide6/QtQuick/typesystem_quick.xml +++ b/sources/pyside6/PySide6/QtQuick/typesystem_quick.xml @@ -103,7 +103,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 b49abacc6..929a8e909 100644 --- a/sources/pyside6/PySide6/QtSerialPort/typesystem_serialport.xml +++ b/sources/pyside6/PySide6/QtSerialPort/typesystem_serialport.xml @@ -6,7 +6,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 fe8aced95..3f2afbdeb 100644 --- a/sources/pyside6/PySide6/QtWidgets/typesystem_widgets_common.xml +++ b/sources/pyside6/PySide6/QtWidgets/typesystem_widgets_common.xml @@ -183,7 +183,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"/> @@ -475,7 +475,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"/> @@ -1120,17 +1120,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"> @@ -1748,7 +1748,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&)" allow-thread="yes"> <modify-argument index="1" invalidate-after-use="yes"/> </modify-function> @@ -1757,7 +1757,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&,QListWidget*,int)"> <modify-argument index="this"> <parent index="2" action="add"/> @@ -1817,7 +1817,7 @@ </object-type> <object-type name="QTreeWidgetItem" hash-function="qHash" parent-management="true"> <enum-type name="ChildIndicatorPolicy"/> - <enum-type name="ItemType"/> + <enum-type name="ItemType" python-type="IntEnum"/> <modify-function signature="read(QDataStream&)" allow-thread="yes"> <modify-argument index="1" invalidate-after-use="yes"/> </modify-function> @@ -2251,7 +2251,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"/> @@ -2706,8 +2706,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"/> @@ -2861,7 +2861,7 @@ <object-type name="QCommandLinkButton"/> <!-- FIXME PYSIDE7: Move to QtGui --> <object-type name="QFileSystemModel" polymorphic-id-expression="qobject_cast<QFileSystemModel*>(%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 68fcdcd05..7d1928c00 100644 --- a/sources/pyside6/PySide6/glue/qtcore.cpp +++ b/sources/pyside6/PySide6/glue/qtcore.cpp @@ -128,6 +128,15 @@ else { %0 = new %TYPE(PySide::qMetaTypeFromPyType(reinterpret_cast<PyTypeObject *&>(%1))); // @snippet metatype-from-type +// @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); %out = PySide::qMetaTypeFromPyType(pyType); @@ -403,6 +412,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 1c853877b..adcdcbacd 100644 --- a/sources/pyside6/tests/QtCore/qenum_test.py +++ b/sources/pyside6/tests/QtCore/qenum_test.py @@ -19,7 +19,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) @@ -30,6 +30,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") @@ -79,18 +80,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 a42b42f04..9c9a9e08f 100644 --- a/sources/pyside6/tests/QtCore/qflags_test.py +++ b/sources/pyside6/tests/QtCore/qflags_test.py @@ -94,6 +94,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 e45bfbc54..a25f7d115 100644 --- a/sources/pyside6/tests/QtCore/qsysinfo_test.py +++ b/sources/pyside6/tests/QtCore/qsysinfo_test.py @@ -14,13 +14,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 9e788bdb3..f526cc120 100644 --- a/sources/pyside6/tests/QtGui/qpen_test.py +++ b/sources/pyside6/tests/QtGui/qpen_test.py @@ -26,7 +26,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 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 2b55d7bc2..c2790cabf 100644 --- a/sources/pyside6/tests/QtSql/qvarianttype_test.py +++ b/sources/pyside6/tests/QtSql/qvarianttype_test.py @@ -17,11 +17,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 f68efee63..b0dfc96a8 100644 --- a/sources/pyside6/tests/pysidetest/qvariant_test.py +++ b/sources/pyside6/tests/pysidetest/qvariant_test.py @@ -21,7 +21,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 99cac73d0..c523a00db 100644 --- a/sources/shiboken6/generator/shiboken/cppgenerator.cpp +++ b/sources/shiboken6/generator/shiboken/cppgenerator.cpp @@ -373,15 +373,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'"'; } @@ -705,7 +792,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; @@ -6035,10 +6122,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 90c70cf63..b96db47e0 100644 --- a/sources/shiboken6/libshiboken/basewrapper_p.h +++ b/sources/shiboken6/libshiboken/basewrapper_p.h @@ -114,7 +114,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 68cbfd097..a36dfd176 100644 --- a/sources/shiboken6/libshiboken/sbkenum.cpp +++ b/sources/shiboken6/libshiboken/sbkenum.cpp @@ -399,6 +399,7 @@ static PyObject *PyEnum{}; static PyObject *PyIntEnum{}; static PyObject *PyFlag{}; static PyObject *PyIntFlag{}; +static PyObject *PyFlag_KEEP{}; PyTypeObject *getPyEnumMeta() { @@ -416,8 +417,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; @@ -953,6 +958,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. @@ -972,6 +988,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()); @@ -979,7 +1009,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(); @@ -993,7 +1024,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); @@ -1004,10 +1043,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 01206fbb2..756aab2b5 100644 --- a/sources/shiboken6/libshiboken/sbkenum_p.h +++ b/sources/shiboken6/libshiboken/sbkenum_p.h @@ -16,6 +16,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 368c37f9c..1db7ae681 100644 --- a/sources/shiboken6/libshiboken/sbkfeature_base.cpp +++ b/sources/shiboken6/libshiboken/sbkfeature_base.cpp @@ -173,22 +173,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) @@ -251,12 +261,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 9414e9773..5bb678e3e 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 @@ -139,7 +139,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]) @@ -156,7 +158,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() |