From 0da75cad9d1d3f23f1bbd4e79a70168cd11e5e82 Mon Sep 17 00:00:00 2001 From: signedav Date: Mon, 3 Nov 2025 12:48:29 +0100 Subject: [PATCH 1/4] nameLang parameter to create schema in translated language --- modelbaker/iliwrapper/ili2dbconfig.py | 6 + tests/test_translations.py | 195 +++++++++++++++++++++++++- 2 files changed, 199 insertions(+), 2 deletions(-) diff --git a/modelbaker/iliwrapper/ili2dbconfig.py b/modelbaker/iliwrapper/ili2dbconfig.py index 69cc99d..2699589 100644 --- a/modelbaker/iliwrapper/ili2dbconfig.py +++ b/modelbaker/iliwrapper/ili2dbconfig.py @@ -252,6 +252,7 @@ def __init__(self, other: Ili2DbCommandConfiguration = None): self.stroke_arcs = True self.pre_script = "" self.post_script = "" + self.name_lang = "" def to_ili2db_args(self, extra_args=[], with_action=True): """ @@ -339,6 +340,11 @@ def to_ili2db_args(self, extra_args=[], with_action=True): if self.db_ili_version is None or self.db_ili_version > 3: self.append_args(args, ["--createNlsTab"]) + if self.name_lang: + self.append_args(args, ["--nameLang", self.name_lang]) + elif self.db_ili_version is None or self.db_ili_version > 3: + self.append_args(args, ["--nameLang", "NULL"]) + self.append_args( args, Ili2DbCommandConfiguration.to_ili2db_args(self), force_append=True ) diff --git a/tests/test_translations.py b/tests/test_translations.py index 432d26c..0febf71 100644 --- a/tests/test_translations.py +++ b/tests/test_translations.py @@ -269,7 +269,7 @@ def test_available_langs_gpkg(self): # ... as well as ignoring the translated models and alowing it again and the english one assert {'de','en'} == set(db_connector.get_available_languages(["PlansDAffectation_V1_2"])) - def test_translated_db_objects_pg(self): + def test_available_langs_pg(self): importer = iliimporter.Importer() importer.tool = DbIliMode.ili2pg importer.configuration = iliimporter_config(importer.tool) @@ -306,7 +306,198 @@ def test_translated_db_objects_pg(self): # ... as well as ignoring the translated models and alowing it again and the english one assert {'de','en'} == set(db_connector.get_available_languages(["PlansDAffectation_V1_2"])) - + + def test_namelang_gpkg(self): + # same as translated_db_objects but this time is the schema in French (namelang) and the preferred language German. + importer = iliimporter.Importer() + importer.tool = DbIliMode.ili2gpkg + importer.configuration = iliimporter_config(importer.tool) + importer.configuration.ilimodels = "PlansDAffectation_V1_2" + importer.configuration.dbfile = os.path.join( + self.basetestpath, "tmp_translated_gpkg.gpkg" + ) + importer.configuration.inheritance = "smart2" + importer.configuration.create_basket_col = True + importer.configuration.name_lang = 'fr' + importer.stdout.connect(self.print_info) + importer.stderr.connect(self.print_error) + assert importer.run() == iliimporter.Importer.SUCCESS + + config_manager = GpkgCommandConfigManager(importer.configuration) + uri = config_manager.get_uri() + + generator = Generator( + DbIliMode.ili2gpkg, + uri, + importer.configuration.inheritance, + consider_basket_handling=True, + preferred_language="de", + ) + + available_layers = generator.layers() + relations, _ = generator.relations(available_layers) + legend = generator.legend(available_layers) + + project = Project() + project.layers = available_layers + project.relations = relations + project.legend = legend + project.post_generate() + + qgis_project = QgsProject.instance() + project.create(None, qgis_project) + + count = 0 + fr_layer = None + for layer in available_layers: + if layer.name == "affectationprimaire_surfacedezones": + assert layer.alias == "Grundnutzung_Zonenflaeche" + de_layer = layer.layer + count += 1 + fields = de_layer.fields() + field_idx = fields.lookupField("publiedepuis") + assert field_idx != -1 + field = fields.field(field_idx) + assert field.name() == "publiedepuis" + assert field.alias() == "publiziertAb" + + edit_form_config = de_layer.editFormConfig() + tabs = edit_form_config.tabs() + tab_list = [tab.name() for tab in tabs] + expected_tab_list = [ + "General", + "Dokument", + "Objektbezogene_Festlegung", + "Ueberlagernde_Festlegung", + "Linienbezogene_Festlegung", + ] + assert len(tab_list) == len(expected_tab_list) + assert set(tab_list) == set(expected_tab_list) + + # check domain table and translated domains + if layer.name == "statutjuridique": + count += 1 + assert layer.alias == "RechtsStatus" + assert layer.layer.displayExpression() == "\n".join( + [ + "CASE", + "WHEN iliCode = 'AenderungOhneVorwirkung' THEN 'AenderungOhneVorwirkung'", + "WHEN iliCode = 'inKraft' THEN 'inKraft'", + "WHEN iliCode = 'AenderungMitVorwirkung' THEN 'AenderungMitVorwirkung'", + "END", + ] + ) + + # check if the layers have been considered + assert count == 2 + assert de_layer + + # Check translated relation + rels = qgis_project.relationManager().referencedRelations(de_layer) + assert len(rels) == 1 + assert ( + rels[0].id() + == "geometrie_document_geometrie_affectationprimaire_surfacedezones_affectationprimaire_surfacedezones_T_Id" + ) + assert ( + rels[0].name() + == "Geometrie_Dokument_(Geometrie)_Grundnutzung_Zonenflaeche_(T_Id)" + ) + + def test_namelang_pg(self): + # same as translated_db_objects but this time is the schema in French (namelang) and the preferred language German. + importer = iliimporter.Importer() + importer.tool = DbIliMode.ili2pg + importer.configuration = iliimporter_config(importer.tool) + importer.configuration.ilimodels = "PlansDAffectation_V1_2" + importer.configuration.dbschema = "tid_{:%Y%m%d%H%M%S%f}".format( + datetime.datetime.now() + ) + importer.configuration.inheritance = "smart2" + importer.configuration.create_basket_col = True + importer.configuration.name_lang = 'fr' + importer.stdout.connect(self.print_info) + importer.stderr.connect(self.print_error) + assert importer.run() == iliimporter.Importer.SUCCESS + + generator = Generator( + DbIliMode.ili2pg, + get_pg_connection_string(), + importer.configuration.inheritance, + importer.configuration.dbschema, + consider_basket_handling=True, + preferred_language="de", + ) + available_layers = generator.layers() + relations, _ = generator.relations(available_layers) + legend = generator.legend(available_layers) + + project = Project() + project.layers = available_layers + project.relations = relations + project.legend = legend + project.post_generate() + + qgis_project = QgsProject.instance() + project.create(None, qgis_project) + + count = 0 + fr_layer = None + for layer in available_layers: + if layer.name == "affectationprimaire_surfacedezones": + assert layer.alias == "Grundnutzung_Zonenflaeche" + de_layer = layer.layer + count += 1 + fields = de_layer.fields() + field_idx = fields.lookupField("publiedepuis") + assert field_idx != -1 + field = fields.field(field_idx) + assert field.name() == "publiedepuis" + assert field.alias() == "publiziertAb" + + edit_form_config = de_layer.editFormConfig() + tabs = edit_form_config.tabs() + tab_list = [tab.name() for tab in tabs] + expected_tab_list = [ + "General", + "Dokument", + "Objektbezogene_Festlegung", + "Ueberlagernde_Festlegung", + "Linienbezogene_Festlegung", + ] + assert len(tab_list) == len(expected_tab_list) + assert set(tab_list) == set(expected_tab_list) + + # check domain table and translated domains + if layer.name == "statutjuridique": + count += 1 + assert layer.alias == "RechtsStatus" + assert layer.layer.displayExpression() == "\n".join( + [ + "CASE", + "WHEN iliCode = 'AenderungMitVorwirkung' THEN 'AenderungMitVorwirkung'", + "WHEN iliCode = 'AenderungOhneVorwirkung' THEN 'AenderungOhneVorwirkung'", + "WHEN iliCode = 'inKraft' THEN 'inKraft'", + "END", + ] + ) + + # check if the layers have been considered + assert count == 2 + assert de_layer + + # Check translated relation + rels = qgis_project.relationManager().referencedRelations(de_layer) + assert len(rels) == 1 + assert ( + rels[0].id() + == "geometrie_document_geomtr_ffcttnrmr_srfcdznes_fkey" + ) + assert ( + rels[0].name() + == "Geometrie_Dokument_(Geometrie)_Grundnutzung_Zonenflaeche_(t_id)" + ) + def print_info(self, text): logging.info(text) From bd49ff4f8c479dc4afe59ceb1b5ae5f8dd199f94 Mon Sep 17 00:00:00 2001 From: signedav Date: Mon, 3 Nov 2025 14:07:45 +0100 Subject: [PATCH 2/4] avoid gpkg duplicates and better test method naming --- tests/test_translations.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/tests/test_translations.py b/tests/test_translations.py index 0febf71..d5e69be 100644 --- a/tests/test_translations.py +++ b/tests/test_translations.py @@ -52,7 +52,9 @@ def test_translated_db_objects_gpkg(self): importer.configuration = iliimporter_config(importer.tool) importer.configuration.ilimodels = "PlansDAffectation_V1_2" importer.configuration.dbfile = os.path.join( - self.basetestpath, "tmp_translated_gpkg.gpkg" + self.basetestpath, "tmp_translated_{:%Y%m%d%H%M%S%f}.gpkg".format( + datetime.datetime.now() + ), ) importer.configuration.inheritance = "smart2" importer.configuration.create_basket_col = True @@ -231,13 +233,15 @@ def test_translated_db_objects_pg(self): == "Geometrie_Document_(Geometrie)_AffectationPrimaire_SurfaceDeZones_(t_id)" ) - def test_available_langs_gpkg(self): + def test_translated_available_langs_gpkg(self): importer = iliimporter.Importer() importer.tool = DbIliMode.ili2gpkg importer.configuration = iliimporter_config(importer.tool) importer.configuration.ilimodels = "PlansDAffectation_V1_2" importer.configuration.dbfile = os.path.join( - self.basetestpath, "tmp_translated_gpkg.gpkg" + self.basetestpath, "tmp_translated_{:%Y%m%d%H%M%S%f}.gpkg".format( + datetime.datetime.now() + ), ) importer.configuration.inheritance = "smart2" importer.configuration.create_basket_col = True @@ -269,7 +273,7 @@ def test_available_langs_gpkg(self): # ... as well as ignoring the translated models and alowing it again and the english one assert {'de','en'} == set(db_connector.get_available_languages(["PlansDAffectation_V1_2"])) - def test_available_langs_pg(self): + def test_translated_available_langs_pg(self): importer = iliimporter.Importer() importer.tool = DbIliMode.ili2pg importer.configuration = iliimporter_config(importer.tool) @@ -307,14 +311,16 @@ def test_available_langs_pg(self): # ... as well as ignoring the translated models and alowing it again and the english one assert {'de','en'} == set(db_connector.get_available_languages(["PlansDAffectation_V1_2"])) - def test_namelang_gpkg(self): + def test_translated_namelang_gpkg(self): # same as translated_db_objects but this time is the schema in French (namelang) and the preferred language German. importer = iliimporter.Importer() importer.tool = DbIliMode.ili2gpkg importer.configuration = iliimporter_config(importer.tool) importer.configuration.ilimodels = "PlansDAffectation_V1_2" importer.configuration.dbfile = os.path.join( - self.basetestpath, "tmp_translated_gpkg.gpkg" + self.basetestpath, "tmp_translated_{:%Y%m%d%H%M%S%f}.gpkg".format( + datetime.datetime.now() + ) ) importer.configuration.inheritance = "smart2" importer.configuration.create_basket_col = True @@ -404,7 +410,7 @@ def test_namelang_gpkg(self): == "Geometrie_Dokument_(Geometrie)_Grundnutzung_Zonenflaeche_(T_Id)" ) - def test_namelang_pg(self): + def test_translated_namelang_pg(self): # same as translated_db_objects but this time is the schema in French (namelang) and the preferred language German. importer = iliimporter.Importer() importer.tool = DbIliMode.ili2pg From 5afbc829f627b2f9a4b7087b1d3591a22a8912f8 Mon Sep 17 00:00:00 2001 From: signedav Date: Fri, 7 Nov 2025 08:56:39 +0100 Subject: [PATCH 3/4] gpkgMultiGeomPerTable should not consider metaconfig because its a setting-parameter some comments are added... --- modelbaker/iliwrapper/ili2dbconfig.py | 41 ++++++++++++++++++--------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/modelbaker/iliwrapper/ili2dbconfig.py b/modelbaker/iliwrapper/ili2dbconfig.py index 2699589..3e68632 100644 --- a/modelbaker/iliwrapper/ili2dbconfig.py +++ b/modelbaker/iliwrapper/ili2dbconfig.py @@ -146,19 +146,28 @@ def __init__(self, other=None): self.__dict__ = other.__dict__.copy() def append_args(self, args, values, consider_metaconfig=False, force_append=False): - - if not force_append and self.metaconfig_id and values: - if self.metaconfig_params_only: - return - if ( - consider_metaconfig - and self.metaconfig - and "ch.ehi.ili2db" in self.metaconfig.sections() - ): - metaconfig_ili2db_params = self.metaconfig["ch.ehi.ili2db"] - if values[0][2:] in metaconfig_ili2db_params.keys(): - # if the value is set in the metaconfig, then we do consider it instead + """ + Usually, there's no metaconfig, so we just add the value to the command's arguments. + But if there is a metaconfig and the parameter isn't forced (i.e., it's not a technical parameter), we check: + - Is metaconfig_params_only enabled? + - If yes, we don't add the argument—even if the parameter isn't in the metaconfig (meaning the parameter remains disabled). + - If no, we check whether we want to consider the metaconfig for this specific parameter. + - If yes, we don't add the argument if it's already in the metaconfig. + - If no, we add the argument. + """ + if self.metaconfig_id: + if not force_append: + if self.metaconfig_params_only: return + if ( + consider_metaconfig + and self.metaconfig + and "ch.ehi.ili2db" in self.metaconfig.sections() + ): + metaconfig_ili2db_params = self.metaconfig["ch.ehi.ili2db"] + if values[0][2:] in metaconfig_ili2db_params.keys(): + # if the value is set in the metaconfig, then we do consider it instead + return args += values def to_ili2db_args(self): @@ -257,7 +266,11 @@ def __init__(self, other: Ili2DbCommandConfiguration = None): def to_ili2db_args(self, extra_args=[], with_action=True): """ Create an ili2db argument array, with the password masked with ****** and optionally with the ``action`` - argument (--schemaimport) removed + argument (--schemaimport) removed. + + On all default parameter we consider the metaconfiguration if available. + On those controlled by configuration (like create_basket_col) we don't consider the metaconfiguration (and always set or unset them - even when null). + On technical parameters, we always force-add to the command — even if the metaconfig_params_only setting is enabled. """ args = list() @@ -310,7 +323,7 @@ def to_ili2db_args(self, extra_args=[], with_action=True): if self.tool and (self.tool & DbIliMode.gpkg): if self.create_gpkg_multigeom: - self.append_args(args, ["--gpkgMultiGeomPerTable"], True) + self.append_args(args, ["--gpkgMultiGeomPerTable"]) elif self.db_ili_version is None or self.db_ili_version > 3: self.append_args(args, ["--gpkgMultiGeomPerTable=False"]) From 10801be3f89e21c9b23cf670a3527568edd1887a Mon Sep 17 00:00:00 2001 From: signedav Date: Fri, 7 Nov 2025 08:58:14 +0100 Subject: [PATCH 4/4] additional comment --- modelbaker/iliwrapper/ili2dbconfig.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modelbaker/iliwrapper/ili2dbconfig.py b/modelbaker/iliwrapper/ili2dbconfig.py index 3e68632..8ad33ca 100644 --- a/modelbaker/iliwrapper/ili2dbconfig.py +++ b/modelbaker/iliwrapper/ili2dbconfig.py @@ -270,7 +270,7 @@ def to_ili2db_args(self, extra_args=[], with_action=True): On all default parameter we consider the metaconfiguration if available. On those controlled by configuration (like create_basket_col) we don't consider the metaconfiguration (and always set or unset them - even when null). - On technical parameters, we always force-add to the command — even if the metaconfig_params_only setting is enabled. + On technical parameters, we always force-add to the command — even if the metaconfig_params_only setting is enabled. Special case here are the SQL scripts. They are considered as technical and forced. """ args = list()