PyQGIS linter warnings
troopa81 opened this issue · comments
Date 2024/03/12
Author Julien Cabieces (@troopa81)
Contact julien dot cabieces at oslandia dot com
maintainer @troopa81
Version QGIS 3.40
Summary
As we get closer to a fully Qt 6 support and a potential QGIS 4.0 release, plugins migrations from QGIS 3 to QGIS 4 becomes more and more important.
The migration could be painfull (as it was when switching from QGIS 2 to QGIS 3), and so this QEP proposes to smooth things out by advertising publicly plugin developers/mainteners that some modifications are highly recommended and will be required with QGIS 4.0.
To do so, this QEP proposes to:
- Provide a static linter able to detect QGIS deprecated classes and methods
- Provide a static linter able to detect Qt 5 deprecated classes and methods
- Document the way to use those linters
- Trigger those linters on the plugins.qgis.org plateform in order to inform plugin owner with current warnings
Proposed Solution
Deprecated method
For now, thanks to the SIP Deprecated annotation, a message is displayed whenever a deprecated method/class is used, but there is no easy way to find out all deprecated use in a plugin.
According to quite recent PEP 702 targeted for python version 3.13, it will be possible to add deprecated decorator to functions and classes so they could be identified statically by linter.
So far, SIP doesn't set this decorator, but we can hope it would do in the future.
Deprecated decorator needs to be added in each module pyi file for every methods/classes marked with SIP_DEPRECATED
For instance in _core.pyi
file within QgsProject
class
...
@deprecated("deprecated since QGIS 3.2 use absoluteFilePath(), baseName() or lastModifiedTime() instead")
def fileInfo(self) -> QtCore.QFileInfo: ...
This way, it could then be detected by linter, for instance PyRight, one of the few linter which support the PEP 702 for now.
$ pyright
deprecated_qgis.py
deprecated_qgis.py:12:27 - error: The method "fileInfo" in class "QgsProject" is deprecated
deprecated since QGIS 3.2 use absoluteFilePath(), baseName() or lastModifiedTime() instead (reportDeprecated)
1 error, 0 warnings, 0 informations
How to
In order to add the deprecated decorators, it is needed to update pyi files right after their generation by SIP. To properly modify those files, it is necessary to:
- Extract deprecated classes/methods and the associated
\deprecated
message from header files.
We could use clang C++ parser python binding to extract them instead of relying on sipify script which has proven to be hard to maintain - Modify pyi files to add decorator on extracted classes/methods with their associated deprecated message
ast and tokenize_rt modules can be used to modify properly the pyi in a way similar to pyqt5_to_pyqt6.py
As the deprecated decorator is still not avaible in our current python version, it's necessary to import it from typing-extensions module within pyi files
Qt 5 deprecated methods
pyqt5_to_pyqt6.py allows already to migrate python source files to be compatible with both Qt 5 and Qt 6
The script has to be modified in order to be able to only report elements needing to be fixed without actually modifying the source code, hence allowing to launch the script as a linter only.
Documentation
PyQGIS developer cookbook tips and tricks chapter needs to be updated to describe how to use the 2 linters above.
Trigger linters on plugins.qgis.org
In order to enforce migration of plugins, plugins.qgis.org automatic plugin verifications needs to integrate the 2 linters so the plateform could report the detected errors to the plugin maintainer.
Those errors are considered non blocking and doesn't prevent plugin approval. They shall be reported as warning the same way it as be done for license requirement
Affected Files
- pyqt5_to_pyqt6.py
- .pyi files (core, gui, server, analysis, 3d)
Performance Implications
None
Further Considerations/Improvements
Besides this proposal, we (Oslandia) also plan to update QGIS Plugin templater so it could trigger those linters in GitHub/GitLab CI. It could also serve as examples on how to correctly set up GitHub/GitLab CI for plugin maintainer who doesn't use this plugin.
Backwards Compatibility
No impact on backwards compatibility
Issue Tracking ID(s)
None
Votes
(required)