From 6354e446fad56b6b6a61c9a66fb5b626d9cbb203 Mon Sep 17 00:00:00 2001 From: Olivier Dalang Date: Thu, 9 Mar 2023 10:07:36 +0100 Subject: [PATCH] fix #53: add a check for the datamodel version --- qgepqwat2ili/__init__.py | 14 +++++++++++++- qgepqwat2ili/gui/__init__.py | 15 ++++++++++++++- qgepqwat2ili/qgep/version.py | 2 ++ qgepqwat2ili/qwat/version.py | 2 ++ qgepqwat2ili/utils/various.py | 24 ++++++++++++++++++++++++ 5 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 qgepqwat2ili/qgep/version.py create mode 100644 qgepqwat2ili/qwat/version.py diff --git a/qgepqwat2ili/__init__.py b/qgepqwat2ili/__init__.py index fd48866c..5ee93689 100644 --- a/qgepqwat2ili/__init__.py +++ b/qgepqwat2ili/__init__.py @@ -8,12 +8,14 @@ from .qgep.mapping import get_qgep_mapping from .qgep.model_abwasser import Base as BaseAbwasser from .qgep.model_qgep import Base as BaseQgep +from .qgep.version import QGEP_PUM_TABLE, QGEP_SUPPORTED_VERSION from .qwat.export import qwat_export from .qwat.import_ import qwat_import from .qwat.mapping import get_qwat_mapping from .qwat.model_qwat import Base as BaseQwat from .qwat.model_wasser import Base as BaseWasser -from .utils.various import make_log_path +from .qwat.version import QWAT_PUM_TABLE, QWAT_SUPPORTED_VERSION +from .utils.various import check_version, make_log_path def main(args): @@ -21,6 +23,7 @@ def main(args): parser = argparse.ArgumentParser( description="ili2QWAT / ili2QGEP entrypoint", formatter_class=argparse.ArgumentDefaultsHelpFormatter ) + parser.add_argument("--skip_version_check", action="store_true", help="do not check the datamodel version") subparsers = parser.add_subparsers(title="subcommands", dest="parser") # subparsers.required = True @@ -130,6 +133,10 @@ def main(args): SCHEMA = config.ABWASSER_SCHEMA ILI_MODEL = config.ABWASSER_ILI_MODEL ILI_MODEL_NAME = config.ABWASSER_ILI_MODEL_NAME + + if not args.skip_version_check: + check_version(QGEP_PUM_TABLE, QGEP_SUPPORTED_VERSION) + if args.direction == "export": utils.ili2db.create_ili_schema( SCHEMA, ILI_MODEL, make_log_path(log_path, "ilicreate"), recreate_schema=args.recreate_schema @@ -164,6 +171,11 @@ def main(args): SCHEMA = config.WASSER_SCHEMA ILI_MODEL = config.WASSER_ILI_MODEL ILI_MODEL_NAME = config.WASSER_ILI_MODEL_NAME + + if not args.skip_version_check: + # note: there are two tables, info and upgrades, not sure which one is used + check_version(QWAT_PUM_TABLE, QWAT_SUPPORTED_VERSION) + if args.direction == "export": utils.ili2db.create_ili_schema( SCHEMA, ILI_MODEL, make_log_path(log_path, "ilicreate"), recreate_schema=args.recreate_schema diff --git a/qgepqwat2ili/gui/__init__.py b/qgepqwat2ili/gui/__init__.py index d7d48818..50121746 100644 --- a/qgepqwat2ili/gui/__init__.py +++ b/qgepqwat2ili/gui/__init__.py @@ -15,13 +15,20 @@ from .. import config from ..qgep.export import qgep_export from ..qgep.import_ import qgep_import +from ..qgep.version import QGEP_PUM_TABLE, QGEP_SUPPORTED_VERSION from ..utils.ili2db import ( create_ili_schema, export_xtf_data, import_xtf_data, validate_xtf_data, ) -from ..utils.various import CmdException, LoggingHandlerContext, logger, make_log_path +from ..utils.various import ( + CmdException, + LoggingHandlerContext, + check_version, + logger, + make_log_path, +) from .gui_export import GuiExport from .gui_import import GuiImport @@ -55,6 +62,9 @@ def action_import(plugin): if not configure_from_modelbaker(plugin.iface): return + # check version + check_version(QGEP_PUM_TABLE, QGEP_SUPPORTED_VERSION) + default_folder = QgsSettings().value("qgep_pluging/last_interlis_path", QgsProject.instance().absolutePath()) file_name, _ = QFileDialog.getOpenFileName( None, plugin.tr("Import file"), default_folder, plugin.tr("Interlis transfer files (*.xtf)") @@ -159,6 +169,9 @@ def action_export(plugin): if not configure_from_modelbaker(plugin.iface): return + # check version + check_version(QGEP_PUM_TABLE, QGEP_SUPPORTED_VERSION) + export_dialog = GuiExport(plugin.iface.mainWindow()) def action_do_export(): diff --git a/qgepqwat2ili/qgep/version.py b/qgepqwat2ili/qgep/version.py new file mode 100644 index 00000000..c671831d --- /dev/null +++ b/qgepqwat2ili/qgep/version.py @@ -0,0 +1,2 @@ +QGEP_PUM_TABLE = "qgep_sys.pum_info" +QGEP_SUPPORTED_VERSION = ">=1.5.7" # see https://peps.python.org/pep-0440/#version-specifiers diff --git a/qgepqwat2ili/qwat/version.py b/qgepqwat2ili/qwat/version.py new file mode 100644 index 00000000..d39bfd76 --- /dev/null +++ b/qgepqwat2ili/qwat/version.py @@ -0,0 +1,2 @@ +QWAT_PUM_TABLE = "qwat_sys.info" # note: in the demo data, there's also an "upgrades" table ?! +QWAT_SUPPORTED_VERSION = ">=1.3.6" # see https://peps.python.org/pep-0440/#version-specifiers diff --git a/qgepqwat2ili/utils/various.py b/qgepqwat2ili/utils/various.py index b3e4b985..9f71dd96 100644 --- a/qgepqwat2ili/utils/various.py +++ b/qgepqwat2ili/utils/various.py @@ -8,6 +8,10 @@ import time from typing import List +import psycopg2 +from packaging import version +from packaging.specifiers import SpecifierSet + from .. import config @@ -269,6 +273,26 @@ def make_log_path(next_to_path, step_name): return os.path.join(temp_path, f"{now}.{step_name}.log") +def check_version(qualified_pum_info_table, version_specifier): + # get the current version + connection = psycopg2.connect(get_pgconf_as_psycopg2_dsn()) + connection.set_session(autocommit=True) + cursor = connection.cursor() + cursor.execute(f'SELECT "version" FROM {qualified_pum_info_table};') + # we get the max version by iterating in python, since no easy/reliable way to get it in SQL + current_version = max([version.parse("0"), *[version.parse(v_str) for (v_str,) in cursor.fetchall()]]) + + # get the specified version + # see https://peps.python.org/pep-0440/#version-specifiers + supported_version_spec = SpecifierSet(version_specifier) + + if not supported_version_spec.contains(current_version): + raise RuntimeError( + f"Version mismatch ! Your datamodel is in version {current_version} which is not supported (supported versions: {version_specifier})." + ) + logger.info(f"Running a supported datamodel version: {current_version}") + + class LoggingHandlerContext: """Temporarily sets a log handler, then removes it"""