QGIS 4 / Qt6 Compatibility Issues - Grouped Summary
This document groups the 47 compatibility issues by type/pattern for easier understanding.
Issue Categories
- Build & Configuration Issues (3 issues)
- Qt Enum Reorganizations (35 issues)
- API Renames & Removals (3 issues)
- Type Strictness (int -> enum) (5 issues)
- Plugin-Specific Bugs (1 issue)
1. Build & Configuration Issues
Issue 1: Version Constraint Too Restrictive
File: config.json:5
qgisMaximumVersion set to 3.99.
Fix: Change to 4.99
Issue 2: Direct PyQt5 Import
File: gui/scenario_item_widget.py:6
Direct import from PyQt5 instead of using qgis.PyQt compatibility layer.
Fix: Use from qgis.PyQt.QtWidgets import ...
Issue 3: Compiled Resources Using pyrcc5
Files: admin.py:319, generated resources.py
pyrcc5 generates PyQt5-specific code, but it's deprecated in Qt6.
Fix: Resources are handled differently in Qt6.
2. Qt Enum Reorganizations
Pattern: Qt6 moved most enums into typed sub-namespaces.
- Qt5:
Qt.AlignLeft, QDialog.Accepted, etc.
- Qt6:
Qt.AlignmentFlag.AlignLeft, QDialog.DialogCode.Accepted, etc.
Possible Solution: Create file e.g. qt_compat.py with compatibility layer providing unified names for both Qt5 and Qt6.
Affected Enum Categories
A. Qt Core Enums (Issues 4, 7, 12, 16, 17, 22, 23, 24, 34, 35, 46)
| Issue |
Enum Type |
Qt5 Example |
Qt6 Namespace |
| 4 |
Alignment flags |
Qt.AlignLeft |
Qt.AlignmentFlag.AlignLeft |
| 7 |
User role |
Qt.UserRole |
Qt.ItemDataRole.UserRole |
| 12 |
Sort order |
Qt.AscendingOrder |
Qt.SortOrder.AscendingOrder |
| 16 |
Orientation |
Qt.Horizontal |
Qt.Orientation.Horizontal |
| 17 |
Check state |
Qt.Checked |
Qt.CheckState.Checked |
| 22 |
Display role |
Qt.DisplayRole |
Qt.ItemDataRole.DisplayRole |
| 23 |
Colors |
Qt.red |
Qt.GlobalColor.red |
| 24 |
Case sensitivity |
Qt.CaseSensitive |
Qt.CaseSensitivity.CaseSensitive |
| 34 |
Event types |
QEvent.Resize |
QEvent.Type.Resize |
| 35 |
Window flags |
Qt.WindowMinimizeButtonHint |
Qt.WindowType.WindowMinimizeButtonHint |
| 46 |
Item data roles |
Qt.DisplayRole |
Qt.ItemDataRole.DisplayRole |
Files affected: 50+ across gui/, models/, lib/
QtCompat names: AlignLeft, UserRole, SortAscending, Horizontal, CheckStateChecked, DisplayRole, ColorRed, CaseSensitive, EventResize, WindowMinimizeButtonHint
B. Widget Enums (Issues 8, 9, 10, 11, 15, 21, 26, 27, 28, 29, 30, 31, 32, 33, 47)
| Issue |
Widget Class |
Qt5 Example |
Qt6 Namespace |
| 8 |
QToolButton |
QToolButton.MenuButtonPopup |
QToolButton.ToolButtonPopupMode.MenuButtonPopup |
| 9 |
QSizePolicy |
QSizePolicy.Fixed |
QSizePolicy.Policy.Fixed |
| 10 |
QAbstractItemView |
QAbstractItemView.ExtendedSelection |
QAbstractItemView.SelectionMode.ExtendedSelection |
| 11 |
QAbstractItemView |
QAbstractItemView.InternalMove |
QAbstractItemView.DragDropMode.InternalMove |
| 15 |
Qt Item flags |
Qt.ItemIsEnabled |
Qt.ItemFlag.ItemIsEnabled |
| 21 |
QHeaderView |
QHeaderView.Stretch |
QHeaderView.ResizeMode.Stretch |
| 26 |
QDialog |
QDialog.Accepted |
QDialog.DialogCode.Accepted |
| 27 |
QWizard pixmaps |
QWizard.LogoPixmap |
QWizard.WizardPixmap.LogoPixmap |
| 28 |
QDialogButtonBox |
QDialogButtonBox.Ok |
QDialogButtonBox.StandardButton.Ok |
| 29 |
QFrame |
QFrame.StyledPanel |
QFrame.Shape.StyledPanel |
| 30 |
QWizard buttons |
QWizard.HelpButton |
QWizard.WizardButton.HelpButton |
| 31 |
Brush styles |
Qt.SolidPattern |
Qt.BrushStyle.SolidPattern |
| 32 |
Match flags |
Qt.MatchFixedString |
Qt.MatchFlag.MatchFixedString |
| 33 |
QItemSelectionModel |
QItemSelectionModel.ClearAndSelect |
QItemSelectionModel.SelectionFlag.ClearAndSelect |
| 47 |
QStyle |
QStyle.SP_DialogCloseButton |
QStyle.StandardPixmap.SP_DialogCloseButton |
Files affected: 40+ across gui/, models/
QtCompat names: MenuButtonPopup, SizePolicyFixed, SelectionExtendedSelection, DragDropInternalMove, ItemIsEnabled, HeaderStretch, DialogAccepted, WizardLogoPixmap, ButtonOk, FrameStyledPanel, WizardHelpButton, BrushSolidPattern, MatchFixedString, SelectionClearAndSelect, StyleSP_DialogCloseButton
C. File Dialog Enums (Issue 19)
| Qt5 |
Qt6 |
QFileDialog.DontUseNativeDialog |
QFileDialog.Option.DontUseNativeDialog |
Files: gui/qgis_cplus_main.py, gui/activity_widget.py
QtCompat name: FileDialogDontUseNativeDialog
D. Network Enums (Issues 36, 37, 40, 44)
| Issue |
Enum Type |
Qt5 Example |
Qt6 Namespace |
| 36 |
Network errors |
QNetworkReply.NoError |
QNetworkReply.NetworkError.NoError |
| 37 |
Request attributes |
QNetworkRequest.HttpStatusCodeAttribute |
QNetworkRequest.Attribute.HttpStatusCodeAttribute |
| 40 |
Known headers |
QNetworkRequest.ContentTypeHeader |
QNetworkRequest.KnownHeaders.ContentTypeHeader |
| 44 |
Known headers |
QNetworkRequest.ETagHeader |
QNetworkRequest.KnownHeaders.ETagHeader |
Files: api/request.py, trends_earth/api.py, trends_earth/download.py
QtCompat names: NetworkNoError, RequestHttpStatusCodeAttribute, RequestContentTypeHeader, RequestETagHeader
E. Other Qt Enums (Issues 38, 42)
| Issue |
Enum Type |
Qt5 Example |
Qt6 Namespace |
| 38 |
QTextCursor |
QTextCursor.End |
QTextCursor.MoveOperation.End |
| 42 |
QIODevice |
QIODevice.ReadOnly |
QIODevice.OpenModeFlag.ReadOnly |
Files: gui/qgis_cplus_main.py, lib/reports/generator.py, gui/component_item_model.py
QtCompat names: CursorEnd, IODeviceReadOnly
3. API Renames & Removals
Issue 5: QStandardItem.UserType Renamed
Pattern: UserType -> UserType()
Files: 11 occurrences across gui/
Fix: Added item_user_type() helper function
Issue 6: QTreeWidgetItem.UserType Renamed
Pattern: UserType -> UserType()
Files: 2 occurrences
Fix: Added tree_item_user_type() helper function
Issue 14: QFontDatabase API Changed to Static Methods
Pattern: Instance methods -> static methods
Example: QFontDatabase().families() -> QFontDatabase.families()
Files: lib/reports/generator.py:2140,2180
Issue 18: Qt.ItemIsTristate Removed
Qt5: Qt.ItemIsTristate existed
Qt6: Removed entirely
Files: gui/qgis_cplus_main.py:904
Fix: Removed usage, functionality unchanged
Issue 25: QDialog.exec_() Renamed to exec()
Pattern: exec_() -> exec()
Reason: Python 3 no longer has exec keyword
Files: 35 occurrences across 16 files
Fix: Used sed to replace all exec_() calls
4. Type Strictness (int -> enum)
Pattern: QGIS 4/Qt6 APIs that previously accepted integers now require proper enum types.
Issue 20: QgsMessageLog.logMessage() Level Parameter
File: utils.py:96
Problem: level parameter rejects int, requires Qgis.MessageLevel enum
Fix: Use try/except to handle both Qgis.MessageLevel.Info (QGIS 4) and Qgis.Info (QGIS 3)
Issue 39: Qgis.MessageLevel Enum
File: utils.py:96-111
Problem: Similar to #20, cascading effects from int level usage
Fix: Proper enum usage with try/except fallback
Issue 41: QgsMessageBar.pushMessage() Level Parameter
File: gui/qgis_cplus_main.py:2805-2835
Problem: level parameter rejects int
Fix: Added int-to-enum conversion map in show_message() method:
if isinstance(level, int):
level_map = {
0: Qgis.MessageLevel.Info,
1: Qgis.MessageLevel.Warning,
2: Qgis.MessageLevel.Critical,
3: Qgis.MessageLevel.Success,
}
level = level_map.get(level, level)
Issue 45: QgsLayoutTableColumn.setHAlignment() Requires Enum
File: models/report.py:143
Problem: When MetricColumn dataclass is deserialized from storage, alignment enum becomes int
Fix: Added int-to-enum conversion in to_qgs_column():
if isinstance(alignment, int):
alignment_map = {
1: QtCompat.AlignLeft,
2: QtCompat.AlignRight,
4: QtCompat.AlignHCenter,
}
alignment = alignment_map.get(alignment, QtCompat.AlignHCenter)
Issue 13: Qt Dock Widget Area Enums (also type strictness)
Similar pattern where DockWidgetArea enums now require proper types.
5. Plugin-Specific Bugs
Issue 43: Settings Enum Not Converted Before QSettings Usage
File: conf.py:318, 340-343
Problem: set_value() and get_value() converted Settings enum to .value AFTER using it in f-string
Symptom: "Empty key passed" warnings, memory corruption crash
Root cause:
# WRONG:
self.settings.setValue(f"{BASE_GROUP_NAME}/{name}", value) # name is enum
if isinstance(name, Settings):
name = name.value # Too late!
# CORRECT:
if isinstance(name, Settings):
name = name.value # Convert BEFORE using
self.settings.setValue(f"{BASE_GROUP_NAME}/{name}", value)
Why it crashed: When enum used in f-string without .value, Python called __str__() producing "Settings.BASE_DIR" instead of "advanced/base_dir". Qt6 stricter validation led to memory corruption.
Summary Statistics
- Total Issues: 47
- Qt Enum Reorganizations: 35 (74%)
- API Renames: 3 (6%)
- Type Strictness: 5 (11%)
- Build/Config: 3 (6%)
- Plugin Bugs: 1 (2%)
Key Takeaways
- Vast majority (74%) are Qt6 enum reorganizations following the same pattern
- Single solution handles most issues: The
qt_compat.py compatibility layer
- Type strictness is new: Qt6/QGIS 4 no longer accept integers where enums are expected
- Systematic approach works: Find enum usage -> Add to QtCompat -> Replace usage -> Test
Testing Environment
- QGIS Version: 3.99.0 Master (Qt6 build)
- Build Source: Local build from QGIS master branch
- OS: Fedora 43 Linux
- Python: 3.10.x
Note: For detailed information about each issue including error messages, code examples, and specific file locations, see QGIS4_COMPATIBILITY_ISSUES.
QGIS 4 / Qt6 Compatibility Issues - Grouped Summary
This document groups the 47 compatibility issues by type/pattern for easier understanding.
Issue Categories
1. Build & Configuration Issues
Issue 1: Version Constraint Too Restrictive
File:
config.json:5qgisMaximumVersionset to3.99.Fix: Change to
4.99Issue 2: Direct PyQt5 Import
File:
gui/scenario_item_widget.py:6Direct import from PyQt5 instead of using qgis.PyQt compatibility layer.
Fix: Use
from qgis.PyQt.QtWidgets import ...Issue 3: Compiled Resources Using pyrcc5
Files:
admin.py:319, generatedresources.pypyrcc5 generates PyQt5-specific code, but it's deprecated in Qt6.
Fix: Resources are handled differently in Qt6.
2. Qt Enum Reorganizations
Pattern: Qt6 moved most enums into typed sub-namespaces.
Qt.AlignLeft,QDialog.Accepted, etc.Qt.AlignmentFlag.AlignLeft,QDialog.DialogCode.Accepted, etc.Possible Solution: Create file e.g.
qt_compat.pywith compatibility layer providing unified names for both Qt5 and Qt6.Affected Enum Categories
A. Qt Core Enums (Issues 4, 7, 12, 16, 17, 22, 23, 24, 34, 35, 46)
Qt.AlignLeftQt.AlignmentFlag.AlignLeftQt.UserRoleQt.ItemDataRole.UserRoleQt.AscendingOrderQt.SortOrder.AscendingOrderQt.HorizontalQt.Orientation.HorizontalQt.CheckedQt.CheckState.CheckedQt.DisplayRoleQt.ItemDataRole.DisplayRoleQt.redQt.GlobalColor.redQt.CaseSensitiveQt.CaseSensitivity.CaseSensitiveQEvent.ResizeQEvent.Type.ResizeQt.WindowMinimizeButtonHintQt.WindowType.WindowMinimizeButtonHintQt.DisplayRoleQt.ItemDataRole.DisplayRoleFiles affected: 50+ across gui/, models/, lib/
QtCompat names:
AlignLeft,UserRole,SortAscending,Horizontal,CheckStateChecked,DisplayRole,ColorRed,CaseSensitive,EventResize,WindowMinimizeButtonHintB. Widget Enums (Issues 8, 9, 10, 11, 15, 21, 26, 27, 28, 29, 30, 31, 32, 33, 47)
QToolButton.MenuButtonPopupQToolButton.ToolButtonPopupMode.MenuButtonPopupQSizePolicy.FixedQSizePolicy.Policy.FixedQAbstractItemView.ExtendedSelectionQAbstractItemView.SelectionMode.ExtendedSelectionQAbstractItemView.InternalMoveQAbstractItemView.DragDropMode.InternalMoveQt.ItemIsEnabledQt.ItemFlag.ItemIsEnabledQHeaderView.StretchQHeaderView.ResizeMode.StretchQDialog.AcceptedQDialog.DialogCode.AcceptedQWizard.LogoPixmapQWizard.WizardPixmap.LogoPixmapQDialogButtonBox.OkQDialogButtonBox.StandardButton.OkQFrame.StyledPanelQFrame.Shape.StyledPanelQWizard.HelpButtonQWizard.WizardButton.HelpButtonQt.SolidPatternQt.BrushStyle.SolidPatternQt.MatchFixedStringQt.MatchFlag.MatchFixedStringQItemSelectionModel.ClearAndSelectQItemSelectionModel.SelectionFlag.ClearAndSelectQStyle.SP_DialogCloseButtonQStyle.StandardPixmap.SP_DialogCloseButtonFiles affected: 40+ across gui/, models/
QtCompat names:
MenuButtonPopup,SizePolicyFixed,SelectionExtendedSelection,DragDropInternalMove,ItemIsEnabled,HeaderStretch,DialogAccepted,WizardLogoPixmap,ButtonOk,FrameStyledPanel,WizardHelpButton,BrushSolidPattern,MatchFixedString,SelectionClearAndSelect,StyleSP_DialogCloseButtonC. File Dialog Enums (Issue 19)
QFileDialog.DontUseNativeDialogQFileDialog.Option.DontUseNativeDialogFiles:
gui/qgis_cplus_main.py,gui/activity_widget.pyQtCompat name:
FileDialogDontUseNativeDialogD. Network Enums (Issues 36, 37, 40, 44)
QNetworkReply.NoErrorQNetworkReply.NetworkError.NoErrorQNetworkRequest.HttpStatusCodeAttributeQNetworkRequest.Attribute.HttpStatusCodeAttributeQNetworkRequest.ContentTypeHeaderQNetworkRequest.KnownHeaders.ContentTypeHeaderQNetworkRequest.ETagHeaderQNetworkRequest.KnownHeaders.ETagHeaderFiles:
api/request.py,trends_earth/api.py,trends_earth/download.pyQtCompat names:
NetworkNoError,RequestHttpStatusCodeAttribute,RequestContentTypeHeader,RequestETagHeaderE. Other Qt Enums (Issues 38, 42)
QTextCursor.EndQTextCursor.MoveOperation.EndQIODevice.ReadOnlyQIODevice.OpenModeFlag.ReadOnlyFiles:
gui/qgis_cplus_main.py,lib/reports/generator.py,gui/component_item_model.pyQtCompat names:
CursorEnd,IODeviceReadOnly3. API Renames & Removals
Issue 5: QStandardItem.UserType Renamed
Pattern:
UserType->UserType()Files: 11 occurrences across gui/
Fix: Added
item_user_type()helper functionIssue 6: QTreeWidgetItem.UserType Renamed
Pattern:
UserType->UserType()Files: 2 occurrences
Fix: Added
tree_item_user_type()helper functionIssue 14: QFontDatabase API Changed to Static Methods
Pattern: Instance methods -> static methods
Example:
QFontDatabase().families()->QFontDatabase.families()Files:
lib/reports/generator.py:2140,2180Issue 18: Qt.ItemIsTristate Removed
Qt5:
Qt.ItemIsTristateexistedQt6: Removed entirely
Files:
gui/qgis_cplus_main.py:904Fix: Removed usage, functionality unchanged
Issue 25: QDialog.exec_() Renamed to exec()
Pattern:
exec_()->exec()Reason: Python 3 no longer has
execkeywordFiles: 35 occurrences across 16 files
Fix: Used sed to replace all
exec_()calls4. Type Strictness (int -> enum)
Pattern: QGIS 4/Qt6 APIs that previously accepted integers now require proper enum types.
Issue 20: QgsMessageLog.logMessage() Level Parameter
File:
utils.py:96Problem:
levelparameter rejects int, requiresQgis.MessageLevelenumFix: Use try/except to handle both
Qgis.MessageLevel.Info(QGIS 4) andQgis.Info(QGIS 3)Issue 39: Qgis.MessageLevel Enum
File:
utils.py:96-111Problem: Similar to #20, cascading effects from int level usage
Fix: Proper enum usage with try/except fallback
Issue 41: QgsMessageBar.pushMessage() Level Parameter
File:
gui/qgis_cplus_main.py:2805-2835Problem:
levelparameter rejects intFix: Added int-to-enum conversion map in
show_message()method:Issue 45: QgsLayoutTableColumn.setHAlignment() Requires Enum
File:
models/report.py:143Problem: When
MetricColumndataclass is deserialized from storage, alignment enum becomes intFix: Added int-to-enum conversion in
to_qgs_column():Issue 13: Qt Dock Widget Area Enums (also type strictness)
Similar pattern where DockWidgetArea enums now require proper types.
5. Plugin-Specific Bugs
Issue 43: Settings Enum Not Converted Before QSettings Usage
File:
conf.py:318, 340-343Problem:
set_value()andget_value()converted Settings enum to.valueAFTER using it in f-stringSymptom: "Empty key passed" warnings, memory corruption crash
Root cause:
Why it crashed: When enum used in f-string without
.value, Python called__str__()producing "Settings.BASE_DIR" instead of "advanced/base_dir". Qt6 stricter validation led to memory corruption.Summary Statistics
Key Takeaways
qt_compat.pycompatibility layerTesting Environment
Note: For detailed information about each issue including error messages, code examples, and specific file locations, see QGIS4_COMPATIBILITY_ISSUES.