diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index f7dceb7a..186db416 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -27,7 +27,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v5
with:
- python-version: "3.10"
+ python-version: "3.12"
architecture: x64
cache: "pip"
cache-dependency-path: "requirements/dev.txt"
@@ -46,11 +46,10 @@ jobs:
strategy:
matrix:
qgis_version: [
+ # "latest",
"release-3_34",
"release-3_28",
"release-3_22",
- "release-3_16",
-# "latest",
]
steps:
@@ -80,10 +79,10 @@ jobs:
- uses: actions/checkout@v4
- - name: Set up Python 3.10
+ - name: Set up Python
uses: actions/setup-python@v5
with:
- python-version: "3.10"
+ python-version: "3.12"
cache: "pip"
cache-dependency-path: "requirements/packaging.txt"
@@ -115,15 +114,6 @@ jobs:
--osgeo-password ${{ secrets.OSGEO_PASSWORD }}
--create-plugin-repo
- - name: Tweet
- uses: mugi111/tweet-trigger-release@v1.2
- with:
- consumer_key: ${{ secrets.TWITTER_CONSUMER_KEY }}
- consumer_secret: ${{ secrets.TWITTER_CONSUMER_SECRET }}
- access_token_key: ${{ secrets.TWITTER_ACCESS_TOKEN_KEY }}
- access_token_secret: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }}
- tweet_body: "New version of @LizmapForQgis desktop plugin ${{ env.RELEASE_VERSION }} 🦎 on #QGIS https://github.com/3liz/lizmap-plugin/releases"
-
- name: Repository Dispatch
uses: peter-evans/repository-dispatch@v3
with:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 51329292..e0db7e91 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -16,7 +16,7 @@ repos:
- id: check-added-large-files
- repo: https://github.com/pycqa/flake8
- rev: 5.0.4
+ rev: 6.1.0
hooks:
- id: flake8
exclude: lizmap/lizmap_api/
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 56d1a5d4..cb567b4f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,8 @@
## Unreleased
+* Raise QGIS minimum version to 3.22
+
## 4.3.24 - 2024-09-09
* Improve download of QGS project
diff --git a/Makefile b/Makefile
index 0e1c4c8e..0d5acc30 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@ SHELL:=bash
.ONESHELL:
.PHONY: env
-QGIS_VERSION ?= release-3_16
+QGIS_VERSION ?= release-3_22
start_tests:
@echo 'Start docker compose'
diff --git a/lizmap/dialogs/dock_html_preview.py b/lizmap/dialogs/dock_html_preview.py
index e5a5c46f..6d097b4e 100644
--- a/lizmap/dialogs/dock_html_preview.py
+++ b/lizmap/dialogs/dock_html_preview.py
@@ -28,7 +28,6 @@
from lizmap.toolbelt.i18n import tr
from lizmap.toolbelt.resources import resources_path
-from lizmap.toolbelt.version import qgis_version
try:
from qgis.PyQt.QtWebKitWidgets import QWebView
@@ -104,9 +103,8 @@ def __init__(self, parent, *__args):
self.feature.featureChanged.connect(self.update_html)
self.feature.setShowBrowserButtons(True)
- if qgis_version() >= 32000:
- # We don't have a better signal to listen to
- QgsProject.instance().dirtySet.connect(self.update_html)
+ # We don't have a better signal to listen to
+ QgsProject.instance().dirtySet.connect(self.update_html)
self.update_html()
diff --git a/lizmap/dialogs/main.py b/lizmap/dialogs/main.py
index c08440b0..8ffa29d4 100755
--- a/lizmap/dialogs/main.py
+++ b/lizmap/dialogs/main.py
@@ -109,10 +109,7 @@ def __init__(self, parent=None, is_dev_version=True, lwc_version: LwcVersions =
self.label_lizmap_logo.setPixmap(pixmap)
# Initial extent widget
- if qgis_version() >= 31800:
- self.widget_initial_extent.setMapCanvas(iface.mapCanvas(), False)
- else:
- self.widget_initial_extent.setMapCanvas(iface.mapCanvas())
+ self.widget_initial_extent.setMapCanvas(iface.mapCanvas(), False)
self.widget_initial_extent.setOutputCrs(self.project.crs())
self.widget_initial_extent.setOriginalExtent(iface.mapCanvas().extent(), self.project.crs())
self.project.crsChanged.connect(self.project_crs_changed)
@@ -544,20 +541,10 @@ def has_auto_fix(self) -> bool:
def enabled_ssl_button(self, status: bool):
""" Enable or not the button. """
- if Qgis.QGIS_VERSION_INT <= 32200:
- self.button_convert_ssl.setToolTip(tr("QGIS 3.22 minimum is required"))
- self.button_convert_ssl.setEnabled(False)
- return
-
self.button_convert_ssl.setEnabled(status)
def enabled_estimated_md_button(self, status: bool):
""" Enable or not the button. """
- if Qgis.QGIS_VERSION_INT <= 32200:
- self.button_use_estimated_md.setToolTip(tr("QGIS 3.22 minimum is required"))
- self.button_use_estimated_md.setEnabled(False)
- return
-
self.button_use_estimated_md.setEnabled(status)
def enabled_trust_project(self, status: bool):
diff --git a/lizmap/dialogs/server_wizard.py b/lizmap/dialogs/server_wizard.py
index be72c1d9..05839658 100644
--- a/lizmap/dialogs/server_wizard.py
+++ b/lizmap/dialogs/server_wizard.py
@@ -49,13 +49,10 @@
from lizmap.definitions.qgis_settings import Settings
from lizmap.logger import log_function
from lizmap.saas import is_lizmap_cloud, webdav_properties
+from lizmap.server_dav import WebDav
from lizmap.toolbelt.i18n import tr
-from lizmap.toolbelt.version import qgis_version, version
-
-if qgis_version() >= 32200:
- from lizmap.server_dav import WebDav
-
from lizmap.toolbelt.plugin import lizmap_user_folder, user_settings
+from lizmap.toolbelt.version import version
LOGGER = logging.getLogger('Lizmap')
THUMBS = " 👍"
@@ -945,11 +942,7 @@ def save_auth_id(self) -> bool:
LOGGER.debug("Edit current information authentication ID : {}".format(self.auth_id))
# Edit
config.setId(self.auth_id)
- if qgis_version() < 32000:
- auth_manager.removeAuthenticationConfig(self.auth_id)
- result = auth_manager.storeAuthenticationConfig(config)
- else:
- result = auth_manager.storeAuthenticationConfig(config, True)
+ result = auth_manager.storeAuthenticationConfig(config, True)
# The JSON will be saved later, in the table
else:
# Creation
@@ -1120,15 +1113,13 @@ def request_check_url(self, url: str, login: str, password: str) -> Tuple[bool,
if any(item in version() for item in UNSTABLE_VERSION_PREFIX):
# Debug for devs
self.has_repository = False
- if qgis_version() < 32200:
- # Missing PyQGIS class for managing webdav
+
+ dav_metadata = webdav_properties(content)
+ if not dav_metadata:
self.dav_url = None
else:
- dav_metadata = webdav_properties(content)
- if not dav_metadata:
- self.dav_url = None
- else:
- self.dav_url = self.trailing_slash(dav_metadata.get('url')) + dav_metadata.get('projects_path')
+ self.dav_url = self.trailing_slash(dav_metadata.get('url')) + dav_metadata.get('projects_path')
+
return True, '', True
def _uri(self) -> QgsDataSourceUri:
diff --git a/lizmap/metadata.txt b/lizmap/metadata.txt
index 6666d162..d9a05a46 100755
--- a/lizmap/metadata.txt
+++ b/lizmap/metadata.txt
@@ -1,6 +1,6 @@
[general]
name=Lizmap
-qgisMinimumVersion=3.16
+qgisMinimumVersion=3.22
qgisMaximumVersion=3.99
author=3Liz
email=info@3liz.com
diff --git a/lizmap/plugin.py b/lizmap/plugin.py
index 6851c970..8f1ac977 100755
--- a/lizmap/plugin.py
+++ b/lizmap/plugin.py
@@ -25,6 +25,7 @@
QgsEditFormConfig,
QgsExpression,
QgsFileDownloader,
+ QgsIconUtils,
QgsLayerTree,
QgsLayerTreeGroup,
QgsMapLayer,
@@ -38,17 +39,9 @@
QgsWkbTypes,
)
from qgis.gui import QgsFileWidget
-from qgis.PyQt.QtCore import QEventLoop
-from qgis.PyQt.QtWidgets import QApplication, QFileDialog
-
-from lizmap.dialogs.news import NewConfigDialog
-from lizmap.dialogs.server_wizard import CreateFolderWizard
-
-if Qgis.QGIS_VERSION_INT >= 32200:
- from qgis.core import QgsIconUtils
-
from qgis.PyQt.QtCore import (
QCoreApplication,
+ QEventLoop,
QStorageInfo,
Qt,
QTranslator,
@@ -66,7 +59,9 @@
)
from qgis.PyQt.QtWidgets import (
QAction,
+ QApplication,
QDialogButtonBox,
+ QFileDialog,
QLineEdit,
QMessageBox,
QPushButton,
@@ -127,6 +122,8 @@
from lizmap.dialogs.html_maptip import HtmlMapTipDialog
from lizmap.dialogs.lizmap_popup import LizmapPopupDialog
from lizmap.dialogs.main import LizmapDialog
+from lizmap.dialogs.news import NewConfigDialog
+from lizmap.dialogs.server_wizard import CreateFolderWizard
from lizmap.dialogs.wizard_group import WizardGroupDialog
from lizmap.drag_drop_dataviz_manager import DragDropDatavizManager
from lizmap.forms.atlas_edition import AtlasEditionDialog
@@ -185,6 +182,7 @@
from qgis.core import QgsProjectServerValidator
from lizmap.qt_style_sheets import NEW_FEATURE_COLOR, NEW_FEATURE_CSS
+from lizmap.server_dav import WebDav
from lizmap.server_lwc import MAX_DAYS, ServerManager
from lizmap.toolbelt.convert import to_bool
from lizmap.toolbelt.custom_logging import (
@@ -212,9 +210,6 @@
from lizmap.tooltip import Tooltip
from lizmap.version_checker import VersionChecker
-if qgis_version() >= 32200:
- from lizmap.server_dav import WebDav
-
LOGGER = logging.getLogger(plugin_name())
VERSION_URL = 'https://raw.githubusercontent.com/3liz/lizmap-web-client/versions/versions.json'
# To try a local file
@@ -301,12 +296,9 @@ def __init__(self, iface, lwc_version: LwcVersions = None):
self.is_dev_version = any(item in self.version for item in UNSTABLE_VERSION_PREFIX)
self.dlg = LizmapDialog(is_dev_version=self.is_dev_version, lwc_version=self._version)
- if Qgis.QGIS_VERSION_INT >= 32200:
- self.webdav = WebDav()
- # Give the dialog only the first time
- self.webdav.setup_webdav_dialog(self.dlg)
- else:
- self.webdav = None
+ self.webdav = WebDav()
+ # Give the dialog only the first time
+ self.webdav.setup_webdav_dialog(self.dlg)
# self.check_webdav()
self.dock_html_preview = None
@@ -1501,27 +1493,26 @@ def initGui(self):
"This value will be replaced on the server side when evaluating the expression thanks to "
"the QGIS server Lizmap plugin.")
# Register variable helps
- if qgis_version() >= 32200:
- QgsExpression.addVariableHelpText(
- "lizmap_user",
- "{}
{}
{}".format(
- tr("The current Lizmap login as a string."),
- tr("It might be an empty string if the user is not connected."),
- server_side,
- )
+ QgsExpression.addVariableHelpText(
+ "lizmap_user",
+ "{}
{}
{}".format(
+ tr("The current Lizmap login as a string."),
+ tr("It might be an empty string if the user is not connected."),
+ server_side,
)
- QgsExpression.addVariableHelpText(
- "lizmap_user_groups",
- "{}
{}
{}
{}".format(
- tr("The current groups of the logged user as an array."),
- tr("It might be an empty array if the user is not connected."),
- tr(
- "You might need to use functions in the Array expression category, such as "
- "
array_to_stringto convert it to a string."), - server_side, - ) + ) + QgsExpression.addVariableHelpText( + "lizmap_user_groups", + "{}
array_to_stringto convert it to a string."), + server_side, ) - QgsExpression.addVariableHelpText("lizmap_repository", tr("The current repository ID on the server.")) + ) + QgsExpression.addVariableHelpText("lizmap_repository", tr("The current repository ID on the server.")) # Let's fix the dialog to the first panel self.dlg.mOptionsListWidget.setCurrentRow(Panels.Information) @@ -3401,7 +3392,7 @@ def check_project( # Icon for k, v in filters.items(): - if k == "_wkb_type" and Qgis.QGIS_VERSION_INT >= 32000: + if k == "_wkb_type": icon = QgsIconUtils.iconForWkbType(v) break else: diff --git a/lizmap/server_lwc.py b/lizmap/server_lwc.py index a7d475ee..90c5a105 100755 --- a/lizmap/server_lwc.py +++ b/lizmap/server_lwc.py @@ -1279,12 +1279,7 @@ def migrate_password_manager(self, servers: list): config.setConfig('username', user) config.setConfig('password', password) config.setConfig('realm', QUrl(url).host()) - - if qgis_version() < 32000: - auth_manager.removeAuthenticationConfig(auth_id) - result = auth_manager.storeAuthenticationConfig(config) - else: - result = auth_manager.storeAuthenticationConfig(config, True) + result = auth_manager.storeAuthenticationConfig(config, True) if not result: LOGGER.critical("Error while migrating the server") diff --git a/lizmap/test/test_dialog_edition.py b/lizmap/test/test_dialog_edition.py index 8e281c99..05271aaa 100755 --- a/lizmap/test/test_dialog_edition.py +++ b/lizmap/test/test_dialog_edition.py @@ -16,7 +16,6 @@ from lizmap.forms.time_manager_edition import TimeManagerEditionDialog from lizmap.forms.tooltip_edition import ToolTipEditionDialog from lizmap.toolbelt.resources import plugin_test_data_path -from lizmap.toolbelt.version import qgis_version __copyright__ = 'Copyright 2023, 3Liz' __license__ = 'GPL version 3' @@ -61,11 +60,7 @@ def test_load_save_collection_dataviz(self): """Test we can load collection.""" dialog = DatavizEditionDialog() self.assertFalse(dialog.error.isVisible()) - if qgis_version() < 32200: - self.assertEqual('', dialog.x_field.currentField()) - self.assertEqual(dialog.validate(), 'The field "x field" is mandatory.') - else: - self.assertEqual('id', dialog.x_field.currentField()) + self.assertEqual('id', dialog.x_field.currentField()) data = [ { @@ -92,15 +87,7 @@ def test_atlas_dialog(self): dialog = AtlasEditionDialog() self.assertFalse(dialog.error.isVisible()) - if qgis_version() >= 32200: - self.assertEqual(dialog.primary_key.currentField(), 'id') - else: - self.assertEqual(dialog.validate(), 'The field "primary key" is mandatory.') - dialog.primary_key.setCurrentIndex(1) - self.assertEqual(dialog.validate(), 'The field "feature label" is mandatory.') - dialog.feature_label.setCurrentIndex(1) - self.assertEqual(dialog.validate(), 'The field "sort field" is mandatory.') - dialog.sort_field.setCurrentIndex(1) + self.assertEqual(dialog.primary_key.currentField(), 'id') self.assertEqual( 'The layers you have chosen for this tool must be checked in the "WFS Capabilities"\n option of the QGIS ' @@ -126,14 +113,11 @@ def test_atlas_dialog(self): del dialog dialog = AtlasEditionDialog() - if qgis_version() < 32200: - self.assertEqual(dialog.validate(), 'The field "primary key" is mandatory.') - else: - self.assertEqual( - dialog.validate(), - 'The layers you have chosen for this tool must be checked in the "WFS Capabilities"\n option of the ' - 'QGIS Server tab in the "Project Properties" dialog.' - ) + self.assertEqual( + dialog.validate(), + 'The layers you have chosen for this tool must be checked in the "WFS Capabilities"\n option of the ' + 'QGIS Server tab in the "Project Properties" dialog.' + ) dialog.load_form(data) diff --git a/lizmap/test/test_trace_dialog.py b/lizmap/test/test_trace_dialog.py index 0322c4ef..f2193227 100755 --- a/lizmap/test/test_trace_dialog.py +++ b/lizmap/test/test_trace_dialog.py @@ -7,7 +7,6 @@ from lizmap.definitions.dataviz import GraphType from lizmap.forms.trace_dataviz_edition import TraceDatavizEditionDialog from lizmap.toolbelt.resources import plugin_test_data_path -from lizmap.toolbelt.version import qgis_version __copyright__ = 'Copyright 2020, 3Liz' __license__ = 'GPL version 3' @@ -44,32 +43,19 @@ def test_unique(self): """Test Y is unique when we add a new row.""" dialog = TraceDatavizEditionDialog(None, self.layer, GraphType.Histogram, []) self.assertFalse(dialog.error.isVisible()) - if qgis_version() < 32200: - self.assertEqual('', dialog.y_field.currentField()) - self.assertEqual('Y field is required.', dialog.validate()) - dialog.y_field.setCurrentIndex(0) - else: - self.assertEqual('id', dialog.y_field.currentField()) + self.assertEqual('id', dialog.y_field.currentField()) self.assertIsNone(dialog.validate()) # Same but with a unique value not existing dialog = TraceDatavizEditionDialog(None, self.layer, GraphType.Histogram, ['hello']) self.assertFalse(dialog.error.isVisible()) - if qgis_version() < 32200: - self.assertEqual('Y field is required.', dialog.validate()) - dialog.y_field.setCurrentIndex(0) - else: - self.assertEqual('id', dialog.y_field.currentField()) + self.assertEqual('id', dialog.y_field.currentField()) self.assertIsNone(dialog.validate()) # Same but with a unique value dialog = TraceDatavizEditionDialog(None, self.layer, GraphType.Histogram, ['id']) self.assertFalse(dialog.error.isVisible()) - if qgis_version() < 32200: - self.assertEqual('Y field is required.', dialog.validate()) - dialog.y_field.setCurrentIndex(0) - else: - self.assertEqual('id', dialog.y_field.currentField()) + self.assertEqual('id', dialog.y_field.currentField()) self.assertEqual('This Y field is already existing.', dialog.validate()) def test_trace_dialog(self): @@ -77,18 +63,11 @@ def test_trace_dialog(self): dialog = TraceDatavizEditionDialog(None, self.layer, GraphType.Histogram, []) self.assertFalse(dialog.error.isVisible()) - if qgis_version() < 32200: - self.assertEqual('', dialog.y_field.currentField()) - self.assertEqual('Y field is required.', dialog.validate()) - self.assertEqual('#086fa1', dialog.color.color().name()) - self.assertEqual('', dialog.color_field.currentField()) - self.assertTrue(dialog.color.isEnabled()) - else: - # TODO better to check these ones - self.assertEqual('id', dialog.y_field.currentField()) - self.assertEqual('#000000', dialog.color.color().name()) - self.assertEqual('id', dialog.color_field.currentField()) - self.assertFalse(dialog.color.isEnabled()) + # TODO better to check these ones + self.assertEqual('id', dialog.y_field.currentField()) + self.assertEqual('#000000', dialog.color.color().name()) + self.assertEqual('id', dialog.color_field.currentField()) + self.assertFalse(dialog.color.isEnabled()) self.assertTrue(dialog.color_field.allowEmptyFieldName()) diff --git a/lizmap/test/test_webdav.py b/lizmap/test/test_webdav.py index 66d77876..c491e41a 100644 --- a/lizmap/test/test_webdav.py +++ b/lizmap/test/test_webdav.py @@ -8,13 +8,9 @@ from qgis.PyQt.QtWidgets import QWizard from lizmap.dialogs.server_wizard import THUMBS, CreateFolderWizard -from lizmap.toolbelt.strings import random_string -from lizmap.toolbelt.version import qgis_version - -if qgis_version() >= 32200: - from lizmap.server_dav import WebDav, PropFindFileResponse, PropFindDirResponse - +from lizmap.server_dav import PropFindDirResponse, PropFindFileResponse, WebDav from lizmap.toolbelt.resources import plugin_test_data_path +from lizmap.toolbelt.strings import random_string try: from lizmap.test.credentials import ( @@ -47,7 +43,7 @@ def skip_test(): """ Check conditions for running tests. """ - return not all((CREDENTIALS, qgis_version() >= 32200, LIZMAP_HOST_DAV, LIZMAP_USER, LIZMAP_PASSWORD)) + return not all((CREDENTIALS, LIZMAP_HOST_DAV, LIZMAP_USER, LIZMAP_PASSWORD)) # # Important note, we are not using our own webdav library to create/remove fixtures. diff --git a/lizmap/toolbelt/version.py b/lizmap/toolbelt/version.py index 64170762..2e8d4c7c 100644 --- a/lizmap/toolbelt/version.py +++ b/lizmap/toolbelt/version.py @@ -13,10 +13,7 @@ def qgis_version(): """ Return the QGIS version as integers. """ - # The API has changed in QGIS 3.12 - # Use the function layer - # noinspection PyUnresolvedReferences - return Qgis.QGIS_VERSION_INT + return Qgis.versionInt() def version(remove_v_prefix=True) -> str: diff --git a/lizmap/widgets/check_project.py b/lizmap/widgets/check_project.py index 8c79d73f..307b551e 100644 --- a/lizmap/widgets/check_project.py +++ b/lizmap/widgets/check_project.py @@ -21,7 +21,6 @@ from lizmap.definitions.online_help import pg_service_help from lizmap.definitions.qgis_settings import Settings from lizmap.toolbelt.i18n import tr -from lizmap.toolbelt.version import qgis_version # 10 000 * 10 000 RASTER_COUNT_CELL = 100000000 @@ -245,9 +244,8 @@ class Checks: """ List of checks defined. """ def __init__(self): - # Check QGIS_VERSION_INT - qgis_32200 = tr( - 'With QGIS ≥ 3.22, you can use the auto-fix button in the dedicated panel of the plugin to fix currently ' + qgis_auto_fix_button = tr( + 'You can use the auto-fix button in the dedicated panel of the plugin to fix currently ' 'loaded layers' ) other_auth = tr('Either switch to another authentication mechanism') @@ -430,11 +428,11 @@ def __init__(self): '