From 032bc905f2e959902a33ae3f25d1784e42c3ec08 Mon Sep 17 00:00:00 2001 From: voisardf Date: Mon, 27 Nov 2023 12:17:03 +0100 Subject: [PATCH 01/60] initial file as copy of standard test file --- .../sources/test_hook_methods.py | 234 ++++++++++++++++++ 1 file changed, 234 insertions(+) create mode 100644 tests/contrib.data_sources.interlis_2_3/sources/test_hook_methods.py diff --git a/tests/contrib.data_sources.interlis_2_3/sources/test_hook_methods.py b/tests/contrib.data_sources.interlis_2_3/sources/test_hook_methods.py new file mode 100644 index 0000000000..063457c8a8 --- /dev/null +++ b/tests/contrib.data_sources.interlis_2_3/sources/test_hook_methods.py @@ -0,0 +1,234 @@ +import binascii + +import pytest +from unittest.mock import patch +from sqlalchemy import Integer +from sqlalchemy.orm import declarative_base +from pyramid.httpexceptions import HTTPNotFound, HTTPServerError +from pyramid_oereb.contrib.data_sources.interlis_2_3.sources.hook_methods import get_symbol +from pyramid_oereb.contrib.data_sources.interlis_2_3.sources.models import get_view_service, get_legend_entry +from pyramid_oereb.core import b64 + + +@pytest.fixture +def theme_config(): + yield { + "srid": 2056, + "code": "ch.BaulinienNationalstrassen", + "geometry_type": "LINESTRING", + "view_service": { + "layer_index": 1, + "layer_opacity": 0.25, + }, + "law_status_lookup": [{ + "data_code": "inKraft", + "transfer_code": "inKraft", + "extract_code": "inForce" + }], + "standard": True, + "federal": True, + "source": { + "class": "pyramid_oereb.contrib.data_sources.interlis_2_3.sources.plr.DatabaseSource", + "params": { + "db_connection": "postgresql://postgres:postgres@123.123.123.123:5432/oereb_test_db", + "model_factory": "pyramid_oereb.contrib.data_sources.interlis_2_3.models.theme.model_factory_string_pk", # noqa: E501 + "schema_name": "land_use_plans" + } + }, + "hooks": { + "get_symbol": "pyramid_oereb.contrib.data_sources.interlis_2_3.hook_methods.get_symbol", + "get_symbol_ref": "pyramid_oereb.contrib.data_sources.interlis_2_3.hook_methods.get_symbol_ref" + }, + "thresholds": { + "length": { + "limit": 1.0, + "unit": 'm', + "precision": 2 + }, + "area": { + "limit": 1.0, + "unit": 'm²', + "precision": 2 + }, + "percentage": { + "precision": 1 + } + }, + "document_types_lookup": [{ + "data_code": "Rechtsvorschrift", + "transfer_code": "Rechtsvorschrift", + "extract_code": "LegalProvision" + }, { + "data_code": "GesetzlicheGrundlage", + "transfer_code": "GesetzlicheGrundlage", + "extract_code": "Law" + }, { + "data_code": "Hinweis", + "transfer_code": "Hinweis", + "extract_code": "Hint" + }] + } + + +@pytest.fixture +def legend_entry(): + Base = declarative_base() + ViewService = get_view_service(Base, 'test', Integer) + LegendEntry = get_legend_entry(Base, 'test', Integer, ViewService) + yield LegendEntry + + +@pytest.fixture +def one_result_binary_session(legend_entry, png_binary, session, query): + + class Query(query): + + def one(self): + return legend_entry(**{ + 'id': 1, + 'symbol': png_binary, + 'legend_text': {'de': 'testlegende'}, + 'type_code': 'testCode', + 'type_code_list': 'testCode,testCode2,testCode3', + 'theme': 'ch.TestThema', + 'sub_theme': 'ch.SubTestThema', + 'view_service_id': 1 + }) + + class Session(session): + + def query(self, term): + return Query() + + yield Session + + +@pytest.fixture +def no_result_session(legend_entry, png_binary, session, query): + + class Session(session): + + def query(self, term): + return query() + + yield Session + + +@pytest.fixture +def one_result_no_symbol_session(legend_entry, session, query): + + class Query(query): + + def one(self): + return legend_entry(**{ + 'id': 1, + 'legend_text': {'de': 'testlegende'}, + 'type_code': 'testCode', + 'type_code_list': 'testCode,testCode2,testCode3', + 'theme': 'ch.TestThema', + 'sub_theme': 'ch.SubTestThema', + 'view_service_id': 1 + }) + + class Session(session): + + def query(self, term): + return Query() + + yield Session + + +@pytest.fixture +def one_result_wrong_content_session(legend_entry, session, query): + + class Query(query): + + def one(self): + return legend_entry(**{ + 'id': 1, + 'symbol': 1, + 'legend_text': {'de': 'testlegende'}, + 'type_code': 'testCode', + 'type_code_list': 'testCode,testCode2,testCode3', + 'theme': 'ch.TestThema', + 'sub_theme': 'ch.SubTestThema', + 'view_service_id': 1 + }) + + class Session(session): + + def query(self, term): + return Query() + + yield Session + + +@pytest.fixture +def one_result_b64_session(legend_entry, png_binary, session, query): + + class Query(query): + def one(self): + return legend_entry(**{ + 'id': 1, + 'symbol': b64.encode(png_binary), + 'legend_text': {'de': 'testlegende'}, + 'type_code': 'testCode', + 'type_code_list': 'testCode,testCode2,testCode3', + 'theme': 'ch.TestThema', + 'sub_theme': 'ch.SubTestThema', + 'view_service_id': 1 + }) + + class Session(session): + def query(self, term): + return Query() + + yield Session + + +def test_get_symbol_binary_content(theme_config, one_result_binary_session, png_binary): + with patch( + 'pyramid_oereb.core.adapter.DatabaseAdapter.get_session', + return_value=one_result_binary_session()): + body, content_type = get_symbol({'identifier': "1"}, theme_config) + assert content_type == 'image/png' + assert body == b64.decode(binascii.b2a_base64(png_binary).decode('ascii')) + + +def test_get_symbol_no_symbol_content(theme_config, one_result_no_symbol_session): + with patch( + 'pyramid_oereb.core.adapter.DatabaseAdapter.get_session', + return_value=one_result_no_symbol_session()): + with pytest.raises(HTTPServerError): + get_symbol({'identifier': "1"}, theme_config) + + +def test_get_symbol_wrong_param(theme_config, one_result_no_symbol_session): + with patch( + 'pyramid_oereb.core.adapter.DatabaseAdapter.get_session', + return_value=one_result_no_symbol_session()): + with pytest.raises(HTTPServerError): + get_symbol({'identif': "1"}, theme_config) + + +def test_get_symbol_no_legend_entry(theme_config, no_result_session): + with patch( + 'pyramid_oereb.core.adapter.DatabaseAdapter.get_session', + return_value=no_result_session()): + with pytest.raises(HTTPNotFound): + get_symbol({'identifier': "2"}, theme_config) + + +def test_get_symbol_wrong_content(theme_config, one_result_wrong_content_session): + with patch('pyramid_oereb.core.adapter.DatabaseAdapter.get_session', + return_value=one_result_wrong_content_session()): + with pytest.raises(HTTPServerError): + get_symbol({'identifier': "1"}, theme_config) + + +def test_get_symbol_b64_content(theme_config, one_result_b64_session, png_binary): + with patch('pyramid_oereb.core.adapter.DatabaseAdapter.get_session', + return_value=one_result_b64_session()): + body, content_type = get_symbol({'identifier': "1"}, theme_config) + assert content_type == 'image/png' + assert body == b64.decode(binascii.b2a_base64(png_binary).decode('ascii')) From f8dd968e0227385480550095843f69941f6f4603 Mon Sep 17 00:00:00 2001 From: voisardf Date: Mon, 27 Nov 2023 16:32:45 +0100 Subject: [PATCH 02/60] some more adaptions --- .../sources/test_hook_methods.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/contrib.data_sources.interlis_2_3/sources/test_hook_methods.py b/tests/contrib.data_sources.interlis_2_3/sources/test_hook_methods.py index 063457c8a8..553df527f5 100644 --- a/tests/contrib.data_sources.interlis_2_3/sources/test_hook_methods.py +++ b/tests/contrib.data_sources.interlis_2_3/sources/test_hook_methods.py @@ -5,8 +5,8 @@ from sqlalchemy import Integer from sqlalchemy.orm import declarative_base from pyramid.httpexceptions import HTTPNotFound, HTTPServerError -from pyramid_oereb.contrib.data_sources.interlis_2_3.sources.hook_methods import get_symbol -from pyramid_oereb.contrib.data_sources.interlis_2_3.sources.models import get_view_service, get_legend_entry +from pyramid_oereb.contrib.data_sources.interlis_2_3.hook_methods import get_symbol +from pyramid_oereb.contrib.data_sources.standard.models import get_view_service, get_legend_entry from pyramid_oereb.core import b64 @@ -14,8 +14,8 @@ def theme_config(): yield { "srid": 2056, - "code": "ch.BaulinienNationalstrassen", - "geometry_type": "LINESTRING", + "code": "ch.BelasteteStandorteZivileFlugplaetze", + "geometry_type": "GEOMETRYCOLLECTION", "view_service": { "layer_index": 1, "layer_opacity": 0.25, @@ -31,13 +31,13 @@ def theme_config(): "class": "pyramid_oereb.contrib.data_sources.interlis_2_3.sources.plr.DatabaseSource", "params": { "db_connection": "postgresql://postgres:postgres@123.123.123.123:5432/oereb_test_db", - "model_factory": "pyramid_oereb.contrib.data_sources.interlis_2_3.models.theme.model_factory_string_pk", # noqa: E501 - "schema_name": "land_use_plans" + "model_factory": "pyramid_oereb.contrib.data_sources.interlis_2_3.models.theme.model_factory_integer_pk", # noqa: E501 + "schema_name": "contaminated_civil_aviation_sites" } }, "hooks": { "get_symbol": "pyramid_oereb.contrib.data_sources.interlis_2_3.hook_methods.get_symbol", - "get_symbol_ref": "pyramid_oereb.contrib.data_sources.interlis_2_3.hook_methods.get_symbol_ref" + "get_symbol_ref": "pyramid_oereb.core.hook_methods.get_symbol_ref" }, "thresholds": { "length": { From 0587958125cf6d85479d76890e4e9414987aa6c5 Mon Sep 17 00:00:00 2001 From: voisardf Date: Mon, 27 Nov 2023 17:20:40 +0100 Subject: [PATCH 03/60] first part of test improvments --- .../sources/test_hook_methods.py | 47 ------------------- 1 file changed, 47 deletions(-) diff --git a/tests/contrib.data_sources.interlis_2_3/sources/test_hook_methods.py b/tests/contrib.data_sources.interlis_2_3/sources/test_hook_methods.py index 553df527f5..a68e874310 100644 --- a/tests/contrib.data_sources.interlis_2_3/sources/test_hook_methods.py +++ b/tests/contrib.data_sources.interlis_2_3/sources/test_hook_methods.py @@ -185,50 +185,3 @@ def query(self, term): yield Session - -def test_get_symbol_binary_content(theme_config, one_result_binary_session, png_binary): - with patch( - 'pyramid_oereb.core.adapter.DatabaseAdapter.get_session', - return_value=one_result_binary_session()): - body, content_type = get_symbol({'identifier': "1"}, theme_config) - assert content_type == 'image/png' - assert body == b64.decode(binascii.b2a_base64(png_binary).decode('ascii')) - - -def test_get_symbol_no_symbol_content(theme_config, one_result_no_symbol_session): - with patch( - 'pyramid_oereb.core.adapter.DatabaseAdapter.get_session', - return_value=one_result_no_symbol_session()): - with pytest.raises(HTTPServerError): - get_symbol({'identifier': "1"}, theme_config) - - -def test_get_symbol_wrong_param(theme_config, one_result_no_symbol_session): - with patch( - 'pyramid_oereb.core.adapter.DatabaseAdapter.get_session', - return_value=one_result_no_symbol_session()): - with pytest.raises(HTTPServerError): - get_symbol({'identif': "1"}, theme_config) - - -def test_get_symbol_no_legend_entry(theme_config, no_result_session): - with patch( - 'pyramid_oereb.core.adapter.DatabaseAdapter.get_session', - return_value=no_result_session()): - with pytest.raises(HTTPNotFound): - get_symbol({'identifier': "2"}, theme_config) - - -def test_get_symbol_wrong_content(theme_config, one_result_wrong_content_session): - with patch('pyramid_oereb.core.adapter.DatabaseAdapter.get_session', - return_value=one_result_wrong_content_session()): - with pytest.raises(HTTPServerError): - get_symbol({'identifier': "1"}, theme_config) - - -def test_get_symbol_b64_content(theme_config, one_result_b64_session, png_binary): - with patch('pyramid_oereb.core.adapter.DatabaseAdapter.get_session', - return_value=one_result_b64_session()): - body, content_type = get_symbol({'identifier': "1"}, theme_config) - assert content_type == 'image/png' - assert body == b64.decode(binascii.b2a_base64(png_binary).decode('ascii')) From 7ab25b0d75b69fea90c74f25346c62f65eca0e45 Mon Sep 17 00:00:00 2001 From: voisardf Date: Tue, 28 Nov 2023 09:49:16 +0100 Subject: [PATCH 04/60] applied hook method tests to interlis 2.3 --- .../conftest.py | 91 +++++++++++++++++++ .../sources/test_hook_methods.py | 51 ++++++++++- 2 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 tests/contrib.data_sources.interlis_2_3/conftest.py diff --git a/tests/contrib.data_sources.interlis_2_3/conftest.py b/tests/contrib.data_sources.interlis_2_3/conftest.py new file mode 100644 index 0000000000..96976a786c --- /dev/null +++ b/tests/contrib.data_sources.interlis_2_3/conftest.py @@ -0,0 +1,91 @@ +import pytest +import io + +from unittest.mock import patch +from PIL import Image + +from pyramid_oereb.core.records.law_status import LawStatusRecord + + +@pytest.fixture +def session(): + + class Session: + + def query(self, model): + return + + def close(self): + return + + yield Session + + +@pytest.fixture +def query(): + + class Query: + + def filter(self, term): + return self + + def one(self): + return + + yield Query + + +@pytest.fixture(autouse=True) +def srid(): + def srid(): + return 2056 + with patch('pyramid_oereb.core.config.Config.get_srid', srid): + yield + + +@pytest.fixture +def png_image(): + yield Image.new("RGB", (72, 36), (128, 128, 128)) + + +@pytest.fixture +def png_binary(png_image): + output = io.BytesIO() + png_image.save(output, format='PNG') + yield output.getvalue() + + +@pytest.fixture +def law_status_records(): + yield [ + LawStatusRecord( + "inKraft", + { + "de": "Rechtskräftig", + "fr": "En vigueur", + "it": "In vigore", + "rm": "En vigur", + "en": "In force" + } + ), + LawStatusRecord( + "AenderungMitVorwirkung", + { + "de": "Änderung mit Vorwirkung", + "fr": "Modification avec effet anticipé", + "it": "Modifica con effetto anticipato", + "rm": "Midada cun effect anticipà", + "en": "Modification with pre-effect" + } + ), + LawStatusRecord( + "AenderungOhneVorwirkung", + { + "de": "Änderung ohne Vorwirkung", + "fr": "Modification sans effet anticipé", + "it": "Modifica senza effetto anticipato", + "rm": "Midada senza effect anticipà", + "en": "Modification without pre-effect" + } + ) + ] diff --git a/tests/contrib.data_sources.interlis_2_3/sources/test_hook_methods.py b/tests/contrib.data_sources.interlis_2_3/sources/test_hook_methods.py index a68e874310..d30a33e712 100644 --- a/tests/contrib.data_sources.interlis_2_3/sources/test_hook_methods.py +++ b/tests/contrib.data_sources.interlis_2_3/sources/test_hook_methods.py @@ -25,13 +25,13 @@ def theme_config(): "transfer_code": "inKraft", "extract_code": "inForce" }], - "standard": True, + "standard": False, "federal": True, "source": { "class": "pyramid_oereb.contrib.data_sources.interlis_2_3.sources.plr.DatabaseSource", "params": { "db_connection": "postgresql://postgres:postgres@123.123.123.123:5432/oereb_test_db", - "model_factory": "pyramid_oereb.contrib.data_sources.interlis_2_3.models.theme.model_factory_integer_pk", # noqa: E501 + "model_factory": "pyramid_oereb.contrib.data_sources.interlis_2_3.models.theme.model_factory_string_pk", # noqa: E501 "schema_name": "contaminated_civil_aviation_sites" } }, @@ -185,3 +185,50 @@ def query(self, term): yield Session + +def test_get_symbol_binary_content(theme_config, one_result_binary_session, png_binary): + with patch( + 'pyramid_oereb.core.adapter.DatabaseAdapter.get_session', + return_value=one_result_binary_session()): + body, content_type = get_symbol({'identifier': "1"}, theme_config) + assert content_type == 'image/png' + assert body == b64.decode(binascii.b2a_base64(png_binary).decode('ascii')) + + +def test_get_symbol_no_symbol_content(theme_config, one_result_no_symbol_session): + with patch( + 'pyramid_oereb.core.adapter.DatabaseAdapter.get_session', + return_value=one_result_no_symbol_session()): + with pytest.raises(HTTPServerError): + get_symbol({'identifier': "1"}, theme_config) + + +def test_get_symbol_wrong_param(theme_config, one_result_no_symbol_session): + with patch( + 'pyramid_oereb.core.adapter.DatabaseAdapter.get_session', + return_value=one_result_no_symbol_session()): + with pytest.raises(HTTPServerError): + get_symbol({'identif': "1"}, theme_config) + + +def test_get_symbol_no_legend_entry(theme_config, no_result_session): + with patch( + 'pyramid_oereb.core.adapter.DatabaseAdapter.get_session', + return_value=no_result_session()): + with pytest.raises(HTTPNotFound): + get_symbol({'identifier': "2"}, theme_config) + + +def test_get_symbol_wrong_content(theme_config, one_result_wrong_content_session): + with patch('pyramid_oereb.core.adapter.DatabaseAdapter.get_session', + return_value=one_result_wrong_content_session()): + with pytest.raises(HTTPServerError): + get_symbol({'identifier': "1"}, theme_config) + + +def test_get_symbol_b64_content(theme_config, one_result_b64_session, png_binary): + with patch('pyramid_oereb.core.adapter.DatabaseAdapter.get_session', + return_value=one_result_b64_session()): + body, content_type = get_symbol({'identifier': "1"}, theme_config) + assert content_type == 'image/png' + assert body == b64.decode(binascii.b2a_base64(png_binary).decode('ascii')) From 12a79e3c7ee4799468693e3c8ca4e3a0213fb6b7 Mon Sep 17 00:00:00 2001 From: voisardf Date: Tue, 28 Nov 2023 09:50:50 +0100 Subject: [PATCH 05/60] just adding a new line --- pyramid_oereb/contrib/data_sources/interlis_2_3/hook_methods.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pyramid_oereb/contrib/data_sources/interlis_2_3/hook_methods.py b/pyramid_oereb/contrib/data_sources/interlis_2_3/hook_methods.py index 7f016b9f55..ae00454c4e 100644 --- a/pyramid_oereb/contrib/data_sources/interlis_2_3/hook_methods.py +++ b/pyramid_oereb/contrib/data_sources/interlis_2_3/hook_methods.py @@ -24,6 +24,7 @@ def get_symbol(params, theme_config): Returns: bytearray, str: The image content and the mimetype of image. + Raises: HTTPNotFound HTTPServerError From 2a567574248af14130df2cfe08a17d9788ff1fb4 Mon Sep 17 00:00:00 2001 From: voisardf Date: Tue, 28 Nov 2023 10:52:52 +0100 Subject: [PATCH 06/60] removed unused fixtures --- .../conftest.py | 38 ------------------- 1 file changed, 38 deletions(-) diff --git a/tests/contrib.data_sources.interlis_2_3/conftest.py b/tests/contrib.data_sources.interlis_2_3/conftest.py index 96976a786c..b10b5c474b 100644 --- a/tests/contrib.data_sources.interlis_2_3/conftest.py +++ b/tests/contrib.data_sources.interlis_2_3/conftest.py @@ -4,8 +4,6 @@ from unittest.mock import patch from PIL import Image -from pyramid_oereb.core.records.law_status import LawStatusRecord - @pytest.fixture def session(): @@ -53,39 +51,3 @@ def png_binary(png_image): output = io.BytesIO() png_image.save(output, format='PNG') yield output.getvalue() - - -@pytest.fixture -def law_status_records(): - yield [ - LawStatusRecord( - "inKraft", - { - "de": "Rechtskräftig", - "fr": "En vigueur", - "it": "In vigore", - "rm": "En vigur", - "en": "In force" - } - ), - LawStatusRecord( - "AenderungMitVorwirkung", - { - "de": "Änderung mit Vorwirkung", - "fr": "Modification avec effet anticipé", - "it": "Modifica con effetto anticipato", - "rm": "Midada cun effect anticipà", - "en": "Modification with pre-effect" - } - ), - LawStatusRecord( - "AenderungOhneVorwirkung", - { - "de": "Änderung ohne Vorwirkung", - "fr": "Modification sans effet anticipé", - "it": "Modifica senza effetto anticipato", - "rm": "Midada senza effect anticipà", - "en": "Modification without pre-effect" - } - ) - ] From 1edb09c2aef55dcc385324b27e3881f0f83ec7c9 Mon Sep 17 00:00:00 2001 From: Anne Maier Date: Wed, 29 Nov 2023 12:11:57 +0100 Subject: [PATCH 07/60] add mockup function for get_models --- .../sources/test_hook_methods.py | 75 ++++++++++++++----- 1 file changed, 55 insertions(+), 20 deletions(-) diff --git a/tests/contrib.data_sources.interlis_2_3/sources/test_hook_methods.py b/tests/contrib.data_sources.interlis_2_3/sources/test_hook_methods.py index d30a33e712..07466ac4be 100644 --- a/tests/contrib.data_sources.interlis_2_3/sources/test_hook_methods.py +++ b/tests/contrib.data_sources.interlis_2_3/sources/test_hook_methods.py @@ -1,4 +1,6 @@ import binascii +from pyramid_oereb.contrib.data_sources.interlis_2_3.models.theme import Models +from pyramid_oereb.contrib.data_sources.interlis_2_3.sources.plr import StandardThemeConfigParser import pytest from unittest.mock import patch @@ -186,49 +188,82 @@ def query(self, term): yield Session -def test_get_symbol_binary_content(theme_config, one_result_binary_session, png_binary): +@pytest.fixture +def mock_get_models(): + + class LegendEntry(): + t_id = 1 + + office = '' + document = '' + view_service = '' + legend_entry = LegendEntry() + public_law_restriction = [] + geometry = '' + public_law_restriction_document = '' + localised_blob = '' + localised_uri = '' + multilingual_blob = {} + multilingual_uri = {} + base = '' + db_connection = '' + schema_name = '' + return Models(office, document, view_service, + legend_entry, public_law_restriction, geometry, + public_law_restriction_document, + localised_blob, localised_uri, multilingual_blob, multilingual_uri, + base, db_connection, schema_name) + + +def test_get_symbol_binary_content(theme_config, one_result_binary_session, png_binary, mock_get_models): with patch( 'pyramid_oereb.core.adapter.DatabaseAdapter.get_session', return_value=one_result_binary_session()): - body, content_type = get_symbol({'identifier': "1"}, theme_config) - assert content_type == 'image/png' - assert body == b64.decode(binascii.b2a_base64(png_binary).decode('ascii')) + with patch.object(StandardThemeConfigParser, 'get_models', return_value=mock_get_models): + body, content_type = get_symbol({'identifier': "1"}, theme_config) + assert content_type == 'image/png' + assert body == b64.decode(binascii.b2a_base64(png_binary).decode('ascii')) -def test_get_symbol_no_symbol_content(theme_config, one_result_no_symbol_session): +def test_get_symbol_no_symbol_content(theme_config, one_result_no_symbol_session, mock_get_models): with patch( 'pyramid_oereb.core.adapter.DatabaseAdapter.get_session', return_value=one_result_no_symbol_session()): - with pytest.raises(HTTPServerError): - get_symbol({'identifier': "1"}, theme_config) + with patch.object(StandardThemeConfigParser, 'get_models', return_value=mock_get_models): + with pytest.raises(HTTPServerError): + get_symbol({'identifier': "1"}, theme_config) -def test_get_symbol_wrong_param(theme_config, one_result_no_symbol_session): +def test_get_symbol_wrong_param(theme_config, one_result_no_symbol_session, mock_get_models): with patch( 'pyramid_oereb.core.adapter.DatabaseAdapter.get_session', return_value=one_result_no_symbol_session()): - with pytest.raises(HTTPServerError): - get_symbol({'identif': "1"}, theme_config) + with patch.object(StandardThemeConfigParser, 'get_models', return_value=mock_get_models): + with pytest.raises(HTTPServerError): + get_symbol({'identif': "1"}, theme_config) -def test_get_symbol_no_legend_entry(theme_config, no_result_session): +def test_get_symbol_no_legend_entry(theme_config, no_result_session, mock_get_models): with patch( 'pyramid_oereb.core.adapter.DatabaseAdapter.get_session', return_value=no_result_session()): - with pytest.raises(HTTPNotFound): - get_symbol({'identifier': "2"}, theme_config) + with patch.object(StandardThemeConfigParser, 'get_models', return_value=mock_get_models): + with pytest.raises(HTTPNotFound): + get_symbol({'identifier': "2"}, theme_config) -def test_get_symbol_wrong_content(theme_config, one_result_wrong_content_session): +def test_get_symbol_wrong_content(theme_config, one_result_wrong_content_session, mock_get_models): with patch('pyramid_oereb.core.adapter.DatabaseAdapter.get_session', return_value=one_result_wrong_content_session()): - with pytest.raises(HTTPServerError): - get_symbol({'identifier': "1"}, theme_config) + with patch.object(StandardThemeConfigParser, 'get_models', return_value=mock_get_models): + with pytest.raises(HTTPServerError): + get_symbol({'identifier': "1"}, theme_config) -def test_get_symbol_b64_content(theme_config, one_result_b64_session, png_binary): +def test_get_symbol_b64_content(theme_config, one_result_b64_session, png_binary, mock_get_models): with patch('pyramid_oereb.core.adapter.DatabaseAdapter.get_session', return_value=one_result_b64_session()): - body, content_type = get_symbol({'identifier': "1"}, theme_config) - assert content_type == 'image/png' - assert body == b64.decode(binascii.b2a_base64(png_binary).decode('ascii')) + with patch.object(StandardThemeConfigParser, 'get_models', return_value=mock_get_models): + body, content_type = get_symbol({'identifier': "1"}, theme_config) + assert content_type == 'image/png' + assert body == b64.decode(binascii.b2a_base64(png_binary).decode('ascii')) From a2caf467bbf3036985dfc4fc4131ba442e6f5e60 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Thu, 30 Nov 2023 12:01:19 +0100 Subject: [PATCH 08/60] remove xml2pdf from pyramid_oereb --- Makefile | 4 +- dev/config/create_yaml.py | 11 -- dev/config/pyramid_oereb.yml.mako | 18 +-- doc/source/conf.py | 3 +- doc/source/contrib/print_proxy/index.rst.mako | 4 +- .../contrib/print_proxy/xml2pdf.rst.mako | 64 --------- doc/source/index.rst | 3 +- .../contrib/print_proxy/xml_2_pdf/README.md | 5 - .../contrib/print_proxy/xml_2_pdf/__init__.py | 0 .../print_proxy/xml_2_pdf/xml_2_pdf.py | 135 ------------------ tests/contrib.print_proxy.xml_2_pdf/.gitkeep | 0 11 files changed, 5 insertions(+), 242 deletions(-) delete mode 100644 doc/source/contrib/print_proxy/xml2pdf.rst.mako delete mode 100644 pyramid_oereb/contrib/print_proxy/xml_2_pdf/README.md delete mode 100644 pyramid_oereb/contrib/print_proxy/xml_2_pdf/__init__.py delete mode 100644 pyramid_oereb/contrib/print_proxy/xml_2_pdf/xml_2_pdf.py delete mode 100644 tests/contrib.print_proxy.xml_2_pdf/.gitkeep diff --git a/Makefile b/Makefile index 8ce74694b0..bd266d18cf 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,6 @@ DEV_CREATE_OEREBLEX_TABLES_SCRIPT = $(VENV_BIN)/create_oereblex_tables MODEL_PK_TYPE_IS_STRING ?= true -PRINT_BACKEND = MapFishPrint # Set to XML2PDF if preferred PRINT_URL ?= http://oereb-print:8080/print/oereb # ******************** @@ -207,7 +206,7 @@ BUILD_DEPS += ${VENV_ROOT}/requirements-timestamp # *********************** $(DEV_CONFIGURATION_YML): ${VENV_ROOT}/requirements-timestamp $(DEV_CREATE_STANDARD_YML_SCRIPT) - $(DEV_CREATE_STANDARD_YML_SCRIPT) --name $@ --database $(SQLALCHEMY_URL) --print_backend $(PRINT_BACKEND) --print_url $(PRINT_URL) + $(DEV_CREATE_STANDARD_YML_SCRIPT) --name $@ --database $(SQLALCHEMY_URL) --print_url $(PRINT_URL) # ********************* # END DEV-YAML creation @@ -308,7 +307,6 @@ test-core: ${VENV_ROOT}/requirements-timestamp .PHONY: test-contrib-print_proxy-mapfish_print test-contrib-print_proxy-mapfish_print: ${VENV_ROOT}/requirements-timestamp $(VENV_BIN)/py.test -vv $(PYTEST_OPTS) --cov-config .coveragerc.contrib-print_proxy-mapfish_print --cov $(PACKAGE) --cov-report xml:coverage.contrib-print_proxy-mapfish_print.xml tests/contrib.print_proxy.mapfish_print - # $(VENV_BIN)/py.test -vv $(PYTEST_OPTS) --cov-config .coveragerc --cov $(PACKAGE) --cov-report term-missing:skip-covered tests/contrib.print_proxy.xml_2_pdf .PHONY: test-contrib-data_sources-standard test-contrib-data_sources-standard: ${VENV_ROOT}/requirements-timestamp diff --git a/dev/config/create_yaml.py b/dev/config/create_yaml.py index 880ee54e1d..d53911c5f7 100644 --- a/dev/config/create_yaml.py +++ b/dev/config/create_yaml.py @@ -8,7 +8,6 @@ def _create_yaml_config_( name='pyramid_oereb.yml', database='postgresql://postgres:password@localhost/pyramid_oereb', - print_backend='MapFishPrint', print_url='http://oereb-print:8080/print/oereb'): """ Creates the specified YAML file using a template. This YAML file contains the standard @@ -28,7 +27,6 @@ def _create_yaml_config_( ) config = template.render( sqlalchemy_url=database, - print_backend=print_backend, print_url=print_url ) pyramid_oereb_yml = open(name, 'wb+') @@ -58,14 +56,6 @@ def create_yaml(): help='The database connection string (default is: ' 'postgresql://postgres:password@oereb-db:5432/pyramid_oereb).' ) - parser.add_option( - '-p', '--print_backend', - dest='print_backend', - metavar='PRINT_BACKEND', - type='string', - default='MapFishPrint', - help='The print backend (for PDF generation) to use (default is: MapFishPrint)' - ) parser.add_option( '-u', '--print_url', dest='print_url', @@ -78,6 +68,5 @@ def create_yaml(): _create_yaml_config_( name=options.name, database=options.database, - print_backend=options.print_backend, print_url=options.print_url ) diff --git a/dev/config/pyramid_oereb.yml.mako b/dev/config/pyramid_oereb.yml.mako index 8dd0a58270..30181a8cff 100644 --- a/dev/config/pyramid_oereb.yml.mako +++ b/dev/config/pyramid_oereb.yml.mako @@ -42,22 +42,7 @@ pyramid_oereb: # The pyramid renderer which is used as proxy pass through to the desired service for printable static # extract. Here you can define the path to the logic which prepares the output as payload for print # service and returns the result to the user. -% if print_backend == 'XML2PDF': - # Configuration for XML2PDF print service - renderer: pyramid_oereb.contrib.print_proxy.xml_2_pdf.xml_2_pdf.Renderer - # Define whether all geometry data must be included when sending the data to the print service - with_geometry: False - # Base URL with application of the print server - base_url: https://oereb-dev.gis-daten.ch/oereb/report/create - token: 24ba4328-a306-4832-905d-b979388d4cab - use_wms: "true" - validate: "false" - # The following parameters are currently not used by xml2pdf, but might be in the future (see issue #873) - buffer: 10 - basic_map_size: [493, 280] - pdf_dpi: 300 - pdf_map_size_millimeters: [174, 99] -% else: + # # Configuration for MapFish-Print print service renderer: pyramid_oereb.contrib.print_proxy.mapfish_print.mapfish_print.Renderer # Define whether all geometry data must be included when sending the data to the print service @@ -116,7 +101,6 @@ pyramid_oereb: print_canton_logo: true # Flag to print or not the municipality name print_municipality_name: true -% endif # The "app_schema" property contains only one sub property "name". This is directly related to the database # creation process, because this name is used as schema name in the target database. The app_schema holds diff --git a/doc/source/conf.py b/doc/source/conf.py index 2e169b0a48..525aa683f5 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -73,8 +73,7 @@ 'contrib/data_sources/swisstopo/index.rst', 'contrib/data_sources/index.rst', 'contrib/print_proxy/index.rst', - 'contrib/print_proxy/mapfish-print.rst', - 'contrib/print_proxy/xml2pdf.rst' + 'contrib/print_proxy/mapfish-print.rst' ] for target_path in target_paths: diff --git a/doc/source/contrib/print_proxy/index.rst.mako b/doc/source/contrib/print_proxy/index.rst.mako index 6832405611..7a6e954f12 100644 --- a/doc/source/contrib/print_proxy/index.rst.mako +++ b/doc/source/contrib/print_proxy/index.rst.mako @@ -8,13 +8,11 @@ Part of ``pyramid_oereb`` plugable system is also the production of PDF files of It is solved via a proxy approach. The extract is passed to a service which knows how to produce a PDF satisfying the federal specifications. -As of now ``pyramid_oereb`` offers the following print proxies: +As of now ``pyramid_oereb`` offers the following print proxy: * :ref:`contrib-print_proxy-mapfish-print` -* :ref:`contrib-print_proxy-xml2pdf` .. toctree:: :hidden: mapfish-print - xml2pdf diff --git a/doc/source/contrib/print_proxy/xml2pdf.rst.mako b/doc/source/contrib/print_proxy/xml2pdf.rst.mako deleted file mode 100644 index 05df0d6378..0000000000 --- a/doc/source/contrib/print_proxy/xml2pdf.rst.mako +++ /dev/null @@ -1,64 +0,0 @@ -.. _contrib-print_proxy-xml2pdf: - -XML2PDF -------- - -Configuration -............. - - -To properly configure the XML2PDF print service of GISDATEN AG, you need specific configuration in the section -``print`` of your ``yaml`` file. -Please see the `standard configuration file -`__ -as an example, or use the ``create_standard_yaml`` script to regenerate your configuration file with the desired options. - -<%! import glob, inspect, re, sys %> -<% -modules = [m for m in sys.modules.keys() if m.startswith('pyramid_oereb')] -files = glob.glob('../../pyramid_oereb/contrib/print_proxy/xml_2_pdf/*.py') -modules = [ - re.sub(r'\.__init__', '', f[6:-3].replace("/", ".")) for f in files -] - -modules.sort() -delete_modules = [] -for i, module in enumerate(modules): - try: - __import__(module) - except ImportError: - delete_modules.append(i) -delete_modules.reverse() -for i in delete_modules: - del modules[i] - -classes = {} -for module in modules: - classes[module] = [] - for name, obj in inspect.getmembers(sys.modules[module]): - if inspect.isclass(obj) and obj.__module__ == module: - classes[module].append(name) - -underline = ['^', '`', '\'', '.', '~', '*'] -%> - -%for module in modules: -.. _api-${module.replace('.', '-').lower()}: - -.. automodule:: ${module} - - -%for cls in classes[module]: -.. _api-${module.replace('.', '-').lower()}-${cls.lower()}: - -*${module.split('.')[-1].title().replace('_', ' ')} ${cls}* -${re.sub('.', underline[0], module.split('.')[-1] + ' ' + cls)} - -.. autoclass:: ${module}.${cls} - :members: - :inherited-members: - - .. automethod:: __init__ - -%endfor -%endfor diff --git a/doc/source/index.rst b/doc/source/index.rst index 3e7e588b04..671f2ffc43 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -56,8 +56,7 @@ of documentation. For the moment we provide an adapter to get the PDF static extract from mapfishprint and ======= -For the moment we provide an adapter to get the PDF static extract from mapfishprint and -`xml2pdf `__. +For the moment we provide an adapter to get the PDF static extract from mapfishprint. .. image:: ../images/overview.png :align: center diff --git a/pyramid_oereb/contrib/print_proxy/xml_2_pdf/README.md b/pyramid_oereb/contrib/print_proxy/xml_2_pdf/README.md deleted file mode 100644 index 605ced5654..0000000000 --- a/pyramid_oereb/contrib/print_proxy/xml_2_pdf/README.md +++ /dev/null @@ -1,5 +0,0 @@ -#xml_2_pdf# - -In order to produce a valid pdf extract for a given request, the data must be converted to fit the structure of xml2pdf. - -The request to xml2pdf print is prepared, headers and parameters are set, xml data is being prepared and sent to print webservice. \ No newline at end of file diff --git a/pyramid_oereb/contrib/print_proxy/xml_2_pdf/__init__.py b/pyramid_oereb/contrib/print_proxy/xml_2_pdf/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/pyramid_oereb/contrib/print_proxy/xml_2_pdf/xml_2_pdf.py b/pyramid_oereb/contrib/print_proxy/xml_2_pdf/xml_2_pdf.py deleted file mode 100644 index 4273b0c914..0000000000 --- a/pyramid_oereb/contrib/print_proxy/xml_2_pdf/xml_2_pdf.py +++ /dev/null @@ -1,135 +0,0 @@ -# -*- coding: utf-8 -*- -import requests -import logging - -from pyramid.exceptions import ConfigurationError -from pyramid_oereb import Config -from pyramid_oereb.core.renderer.extract.xml_ import Renderer as XmlRenderer - - -log = logging.getLogger(__name__) - - -class Renderer(XmlRenderer): - - def __call__(self, value, system): - """ - Implements a subclass of pyramid_oereb.core.renderer.extract.xml_.Renderer to create a print result - out of a xml. The xml extract is reformatted to fit the structure of xml2pdf. - - Args: - value (tuple): A tuple containing the generated extract record and the params - dictionary. - system (dict): The available system properties. - - Returns: - pyramid.response.Response: The pdf content as received from configured mapfish print instance url. - - Raises: - ConfigurationError - """ - print_config = Config.get('print', {}) - if not print_config: - raise ConfigurationError('No print config section in config file was found.') - print_service_url = print_config.get('base_url', '') - if not print_service_url: - raise ConfigurationError('No print service url ("base_url") was found in the config.') - print_service_token = print_config.get('token', '') - if not print_service_token: - raise ConfigurationError('No print service token ("token") was found in the config.') - verify_certificate = print_config.get('verify_certificate', True) - - self.headers = { - 'token': print_service_token - } - self.parameters = { - 'validate': print_config.get('validate', 'false'), - 'usewms': print_config.get('use_wms', 'false'), - } - - log.debug("Parameter webservice is {}".format(value[1])) - - self._request = self.get_request(system) - # If language present in request, use that. Otherwise, keep language from base class - if 'lang' in self._request.GET: - self._language = self._request.GET.get('lang') - - self.parameters['language'] = self._language - self.parameters['flavour'] = self._request.params.get('flavour', 'reduced') - - # Based on extract record and webservice parameter, render the extract data as JSON - extract_record = value[0] - extract_as_xml = self._render(extract_record, value[1]) - - response = self.get_response(system) - - if self._request.GET.get('getspec', 'no') != 'no': - response.headers['Content-Type'] = 'application/xml; charset=UTF-8' - return extract_as_xml - - prepared_extraxt_as_xml = self.prepare_xml(extract_as_xml) - print_result = self.request_pdf( - print_service_url, - prepared_extraxt_as_xml, - self.headers, - self.parameters, - verify_certificate - ) - - response.status_code = print_result.status_code - response.headers = print_result.headers - if 'Transfer-Encoding' in response.headers: - del response.headers['Transfer-Encoding'] - if 'Connection' in response.headers: - del response.headers['Connection'] - return print_result - - @staticmethod - def request_pdf(url, data_extract, headers, parameters, verify_certificate): - """ - Posts the print request to the configured print server to return the pdf extract. - - Args: - url (str): URl to the print webservice. - data_extract (xml): The rendered xml extract. - headers (dict): Request headers for print request. - parameters (dict): Additional print parameters, such as language or flavour. - verify_certificate (boolean): Define if certificate should be verified. - - Returns: - file: The pdf file as received from configured mapfish print instance url. - - Raises: - Exception: Request failed. - """ - try: - backend_answer = requests.post( - url, - verify=verify_certificate, - headers=headers, - files={'file': ('xml', data_extract, 'text/xml')}, - data=parameters, - proxies=Config.get('proxies') - ) - if backend_answer.status_code != requests.codes.ok: - log.warning("request_pdf failed for url {}".format(url)) - log.debug("data extract for failed request was {}".format(data_extract)) - return backend_answer - except Exception as e: - log.exception(e) - log.warning("request_pdf failed for url {}".format(url)) - log.debug("data extract for failed request was {}".format(data_extract)) - raise e - - @staticmethod - def prepare_xml(extract_as_xml): - """ - Hook method in order to manipulate xml that is sent to print webservice. - - Args: - extract_as_xml(xml): Variable containing the xml content for print werbservice. - - Returns: - str: Data of extract. - """ - return extract_as_xml diff --git a/tests/contrib.print_proxy.xml_2_pdf/.gitkeep b/tests/contrib.print_proxy.xml_2_pdf/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 From a9b309a4a9f42fd02364304824766f3925dbf95f Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Thu, 30 Nov 2023 13:06:36 +0100 Subject: [PATCH 09/60] fix --- doc/source/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/index.rst b/doc/source/index.rst index 671f2ffc43..73697ccad4 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -53,7 +53,7 @@ The server is able to use several specific external api endpoints to fetch data API). These need to be configured and prepared by the integrator of this package. Please read the dedicated part of documentation. -For the moment we provide an adapter to get the PDF static extract from mapfishprint and +For the moment we provide an adapter to get the PDF static extract from mapfishprint. ======= For the moment we provide an adapter to get the PDF static extract from mapfishprint. From ec9c8060b7bad89252837234e3872528b0d87d54 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Thu, 30 Nov 2023 13:10:00 +0100 Subject: [PATCH 10/60] remove repeated sentence --- doc/source/index.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/doc/source/index.rst b/doc/source/index.rst index 73697ccad4..727ceec90a 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -55,9 +55,6 @@ of documentation. For the moment we provide an adapter to get the PDF static extract from mapfishprint. -======= -For the moment we provide an adapter to get the PDF static extract from mapfishprint. - .. image:: ../images/overview.png :align: center From 4d8fb5cd8d808eb3084b26ccee7c7f32d75d14ea Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Thu, 30 Nov 2023 14:06:22 +0100 Subject: [PATCH 11/60] rm /doc/source/contrib/print_proxy/xml2pdf.rst --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 803fb3fec7..132598bcc9 100644 --- a/.gitignore +++ b/.gitignore @@ -29,7 +29,6 @@ __pycache__/ /doc/source/api.rst /doc/source/contrib/print_proxy/index.rst /doc/source/contrib/print_proxy/mapfish-print.rst -/doc/source/contrib/print_proxy/xml2pdf.rst /doc/source/contrib/data_sources/standard/models-main.rst /doc/source/contrib/data_sources/standard/models-theme.rst /doc/source/contrib/data_sources/standard/models.rst From c94109d2204abedccabc0f78b8bb326767b1a333 Mon Sep 17 00:00:00 2001 From: Anne Maier Date: Thu, 30 Nov 2023 14:27:06 +0100 Subject: [PATCH 12/60] test_get_config --- tests/core/test_config.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/core/test_config.py b/tests/core/test_config.py index 8c506d7db5..77decb9523 100644 --- a/tests/core/test_config.py +++ b/tests/core/test_config.py @@ -1085,3 +1085,13 @@ def mock_read_offices(): Config._config = None Config.init_offices() assert Config.offices is None + + +@pytest.mark.run(order=1) +def test_get_config(): + Config._config = None + assert Config.get_config() == None + Config._config = {} + assert Config.get_config() == {} + # set config back to None. + Config._config = None From 5d6cf28ca4149a5a36ac2ab8c214e68072b04e0e Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Thu, 30 Nov 2023 14:32:25 +0100 Subject: [PATCH 13/60] additional comment --- dev/config/pyramid_oereb.yml.mako | 1 + 1 file changed, 1 insertion(+) diff --git a/dev/config/pyramid_oereb.yml.mako b/dev/config/pyramid_oereb.yml.mako index 30181a8cff..812b8598ad 100644 --- a/dev/config/pyramid_oereb.yml.mako +++ b/dev/config/pyramid_oereb.yml.mako @@ -42,6 +42,7 @@ pyramid_oereb: # The pyramid renderer which is used as proxy pass through to the desired service for printable static # extract. Here you can define the path to the logic which prepares the output as payload for print # service and returns the result to the user. + # This version of pyramid oereb provides only the mapfish_print print proxy. # # Configuration for MapFish-Print print service renderer: pyramid_oereb.contrib.print_proxy.mapfish_print.mapfish_print.Renderer From e454455c166b165b20568d369c8836d82ab24f95 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Thu, 30 Nov 2023 14:38:16 +0100 Subject: [PATCH 14/60] remove xml2pdf --- CHANGES.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index bcbb38b30b..7a55193ba6 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,6 +1,10 @@ Changelog ========= +main +---- +- Remove print proxy "xml2pdf" (#1889) + 2.4.6 ----- - Fix error with large of contents and new pdf library (#1813) From c612943609f46503f4a347fd02f64a2eb6d588e7 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Thu, 30 Nov 2023 14:38:50 +0100 Subject: [PATCH 15/60] change main to master --- CHANGES.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 7a55193ba6..abbcbb69ed 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,8 +1,8 @@ Changelog ========= -main ----- +master +------ - Remove print proxy "xml2pdf" (#1889) 2.4.6 From 69a7182b4a2756a26d7ea77c883fdc9e957f99b5 Mon Sep 17 00:00:00 2001 From: vvmruder Date: Thu, 30 Nov 2023 20:16:08 +0100 Subject: [PATCH 16/60] =?UTF-8?q?Reorganize=20and=20topping=20up=20tests?= =?UTF-8?q?=20for=20Contrib=20=C3=96REBlex=20Source=20(#1865)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * initial commit * improve test coverage * untrack coverage report * att tests for cmd call * fix lint * fix suggested change --- .coveragerc.contrib-data_sources-oereblex | 3 + .gitignore | 1 + Makefile | 6 +- .../data_sources/oereblex/models/theme.py | 2 + .../contrib.data_sources.oereblex/conftest.py | 133 ++++ .../models/test_theme.py | 74 ++ .../sources/test_document.py} | 0 .../sources/test_plr_oereblex.py | 718 ++++++++++++++++++ .../test_create_tables.py | 31 + 9 files changed, 967 insertions(+), 1 deletion(-) create mode 100644 .coveragerc.contrib-data_sources-oereblex create mode 100644 tests/contrib.data_sources.oereblex/conftest.py create mode 100644 tests/contrib.data_sources.oereblex/models/test_theme.py rename tests/{core/sources/test_document_oereblex.py => contrib.data_sources.oereblex/sources/test_document.py} (100%) create mode 100644 tests/contrib.data_sources.oereblex/sources/test_plr_oereblex.py create mode 100644 tests/contrib.data_sources.oereblex/test_create_tables.py diff --git a/.coveragerc.contrib-data_sources-oereblex b/.coveragerc.contrib-data_sources-oereblex new file mode 100644 index 0000000000..7c229f1ebf --- /dev/null +++ b/.coveragerc.contrib-data_sources-oereblex @@ -0,0 +1,3 @@ +[run] +source = + pyramid_oereb/contrib/data_sources/oereblex/*.py diff --git a/.gitignore b/.gitignore index 803fb3fec7..300f9940c9 100644 --- a/.gitignore +++ b/.gitignore @@ -81,6 +81,7 @@ DataExtract.json /coverage.contrib-data_sources-standard.xml /coverage.contrib-data_sources-interlis.xml +/coverage.contrib-data_sources-oereblex.xml /coverage.contrib-print_proxy-mapfish_print.xml /coverage.contrib-data_sources-swisstopo.xml /coverage.core.xml diff --git a/Makefile b/Makefile index 8ce74694b0..231d555c2e 100644 --- a/Makefile +++ b/Makefile @@ -322,12 +322,16 @@ test-contrib-data_sources-interlis: ${VENV_ROOT}/requirements-timestamp test-contrib-data_sources-swisstopo: ${VENV_ROOT}/requirements-timestamp $(VENV_BIN)/py.test -vv $(PYTEST_OPTS) --cov-config .coveragerc.contrib-data_sources-swisstopo --cov $(PACKAGE)/contrib/data_sources/swisstopo --cov-report=term-missing:skip-covered --cov-report=xml:coverage.contrib-data_sources-swisstopo.xml tests/contrib.data_sources.swisstopo +.PHONY: test-contrib-data_sources-oereblex +test-contrib-data_sources-oereblex: ${VENV_ROOT}/requirements-timestamp + $(VENV_BIN)/py.test -vv $(PYTEST_OPTS) --cov-config .coveragerc.contrib-data_sources-oereblex --cov $(PACKAGE)/contrib/data_sources/oereblex --cov-report=term-missing:skip-covered --cov-report=xml:coverage.contrib-data_sources-oereblex.xml tests/contrib.data_sources.oereblex + .PHONY: test-contrib-stats test-contrib-stats: ${VENV_ROOT}/requirements-timestamp $(VENV_BIN)/py.test -vv $(PYTEST_OPTS) --cov-config .coveragerc.contrib-stats --cov $(PACKAGE)/contrib/stats --cov-report=xml:coverage.contrib-stats.xml tests/contrib.stats .PHONY: tests -tests: ${VENV_ROOT}/requirements-timestamp test-core test-contrib-print_proxy-mapfish_print test-contrib-data_sources-standard test-contrib-data_sources-interlis test-contrib-stats test-contrib-data_sources-swisstopo +tests: ${VENV_ROOT}/requirements-timestamp test-core test-contrib-print_proxy-mapfish_print test-contrib-data_sources-standard test-contrib-data_sources-interlis test-contrib-stats test-contrib-data_sources-swisstopo test-contrib-data_sources-oereblex .PHONY: docker-tests docker-tests: diff --git a/pyramid_oereb/contrib/data_sources/oereblex/models/theme.py b/pyramid_oereb/contrib/data_sources/oereblex/models/theme.py index f8884ecdb4..1eabe866f8 100644 --- a/pyramid_oereb/contrib/data_sources/oereblex/models/theme.py +++ b/pyramid_oereb/contrib/data_sources/oereblex/models/theme.py @@ -38,6 +38,8 @@ def model_factory(schema_name, pk_type, geometry_type, srid, db_connection): needs geometry_type (str): The geoalchemy geometry type defined as well known string. srid (int): The SRID defining the projection of the geometries stored in standard db schema. + Returns: + Models: The models from factory wrapped in an intermediate object. """ Base = declarative_base() diff --git a/tests/contrib.data_sources.oereblex/conftest.py b/tests/contrib.data_sources.oereblex/conftest.py new file mode 100644 index 0000000000..911c513f1b --- /dev/null +++ b/tests/contrib.data_sources.oereblex/conftest.py @@ -0,0 +1,133 @@ +import io +from unittest.mock import patch + +import pytest +from PIL import Image + +from pyramid_oereb.core.records.law_status import LawStatusRecord + + +@pytest.fixture +def db_connection(): + yield "postgresql://mock_user:pass@123.123.123.123:5432/oereb_mock_db" + + +@pytest.fixture() +def app_config(): + yield { + "srid": 2056, + "app_schema": { + "name": "test", + "models": "pyramid_oereb.contrib.data_sources.standard.models.main", + "db_connection": "postgresql://postgres:postgres@123.123.123.123:5432/pyramid_oereb_test" + }, + 'geometry_types': { + 'point': {'types': []}, + 'line': {'types': []}, + 'polygon': {'types': []}, + 'collection': {'types': ['GeometryCollection']} + }, + "oereblex": { + "host": "https://oereblex.sg.ch", + "version": "1.2.2", + "pass_version": True, + "validation": True, + "language": "de", + "canton": "SG", + "mapping": { + "municipality": "subtype", + "official_number": "number", + "abbreviation": "abbreviation" + }, + "related_decree_as_main": False, + "related_notice_as_main": False, + "use_prepubs": True, + "url_param_config": [ + {"code": "ch.StatischeWaldgrenzen", "url_param": "oereb_id=5"} + ] + } + + } + + +@pytest.fixture() +def session(): + class Session: + + def query(self, model): + return + + def close(self): + return + + yield Session + + +@pytest.fixture +def query(): + class Query: + + def filter(self, term): + return self + + def one(self): + return + + yield Query + + +@pytest.fixture(autouse=True) +def srid(): + def srid(): + return 2056 + + with patch('pyramid_oereb.core.config.Config.get_srid', srid): + yield + + +@pytest.fixture +def png_image(): + yield Image.new("RGB", (72, 36), (128, 128, 128)) + + +@pytest.fixture +def png_binary(png_image): + output = io.BytesIO() + png_image.save(output, format='PNG') + yield output.getvalue() + + +@pytest.fixture +def law_status_records(): + yield [ + LawStatusRecord( + "inKraft", + { + "de": "Rechtskräftig", + "fr": "En vigueur", + "it": "In vigore", + "rm": "En vigur", + "en": "In force" + } + ), + LawStatusRecord( + "AenderungMitVorwirkung", + { + "de": "Änderung mit Vorwirkung", + "fr": "Modification avec effet anticipé", + "it": "Modifica con effetto anticipato", + "rm": "Midada cun effect anticipà", + "en": "Modification with pre-effect" + } + ), + LawStatusRecord( + "AenderungOhneVorwirkung", + { + "de": "Änderung ohne Vorwirkung", + "fr": "Modification sans effet anticipé", + "it": "Modifica senza effetto anticipato", + "rm": "Midada senza effect anticipà", + "en": "Modification without pre-effect" + } + ) + ] diff --git a/tests/contrib.data_sources.oereblex/models/test_theme.py b/tests/contrib.data_sources.oereblex/models/test_theme.py new file mode 100644 index 0000000000..130f6d4a3f --- /dev/null +++ b/tests/contrib.data_sources.oereblex/models/test_theme.py @@ -0,0 +1,74 @@ + +from sqlalchemy import Integer, String + +from pyramid_oereb.contrib.data_sources.oereblex.models.theme import ( + Models, model_factory, model_factory_string_pk, model_factory_integer_pk +) + + +def test_models(): + models = Models( + 'office', + 'view_service', + 'legend_entry', + 'public_law_restriction', + 'geometry', + 'base', + 'db_connection', + 'schema_name' + ) + assert models.Office == 'office' + assert models.ViewService == 'view_service' + assert models.LegendEntry == 'legend_entry' + assert models.PublicLawRestriction == 'public_law_restriction' + assert models.Geometry == 'geometry' + assert models.Base == 'base' + assert models.db_connection == 'db_connection' + assert models.schema_name == 'schema_name' + + +def test_model_factory(db_connection): + srid = 2056 + geometry_type = 'POINT' + pk_type = Integer + schema_name = 'test' + + models = model_factory( + schema_name, + pk_type, + geometry_type, + srid, + db_connection + ) + assert isinstance(models, Models) + assert models.db_connection == db_connection + assert models.PublicLawRestriction.__table_args__['schema'] == schema_name + assert isinstance(models.PublicLawRestriction.id.type, pk_type) + assert models.Geometry.geom.type.geometry_type == geometry_type + assert models.Geometry.geom.type.srid == srid + + +def test_model_factory_string_pk(db_connection): + srid = 2056 + geometry_type = 'POINT' + schema_name = 'test' + models = model_factory_string_pk( + schema_name, + geometry_type, + srid, + db_connection + ) + assert isinstance(models.PublicLawRestriction.id.type, String) + + +def test_model_factory_integer_pk(db_connection): + srid = 2056 + geometry_type = 'POINT' + schema_name = 'test' + models = model_factory_integer_pk( + schema_name, + geometry_type, + srid, + db_connection + ) + assert isinstance(models.PublicLawRestriction.id.type, Integer) diff --git a/tests/core/sources/test_document_oereblex.py b/tests/contrib.data_sources.oereblex/sources/test_document.py similarity index 100% rename from tests/core/sources/test_document_oereblex.py rename to tests/contrib.data_sources.oereblex/sources/test_document.py diff --git a/tests/contrib.data_sources.oereblex/sources/test_plr_oereblex.py b/tests/contrib.data_sources.oereblex/sources/test_plr_oereblex.py new file mode 100644 index 0000000000..c84330e723 --- /dev/null +++ b/tests/contrib.data_sources.oereblex/sources/test_plr_oereblex.py @@ -0,0 +1,718 @@ +import datetime + +import pytest +from unittest.mock import patch + +from geoalchemy2 import WKTElement +from shapely.geometry import Polygon, Point, LineString +from shapely.wkt import loads +from sqlalchemy import String +from sqlalchemy.orm import declarative_base + +from pyramid_oereb.core.config import Config +from pyramid_oereb.core.records.documents import DocumentRecord +from pyramid_oereb.core.records.geometry import GeometryRecord +from pyramid_oereb.contrib.data_sources.oereblex.models.theme import model_factory + +from pyramid_oereb.core import b64 +from pyramid_oereb.core.records.document_types import DocumentTypeRecord +from pyramid_oereb.core.records.image import ImageRecord +from pyramid_oereb.core.records.office import OfficeRecord +from pyramid_oereb.core.records.theme import ThemeRecord +from pyramid_oereb.core.records.view_service import LegendEntryRecord, ViewServiceRecord +from pyramid_oereb.core.views.webservice import Parameter + + +@pytest.fixture +def date_today(): + yield datetime.date.today() + + +@pytest.fixture +def yesterday(date_today): + yield date_today - datetime.timedelta(days=1) + + +@pytest.fixture +def tomorrow(date_today): + yield date_today + datetime.timedelta(days=1) + + +@pytest.fixture +def real_estate_wkt(): + yield 'MULTIPOLYGON (' \ + '((40 40, 20 45, 45 30, 40 40)),' \ + '((20 35, 10 30, 10 10, 30 5, 45 20, 20 35),' \ + '(30 20, 20 15, 20 25, 30 20))'\ + ')' + + +@pytest.fixture +def real_estate_shapely_geom(real_estate_wkt): + yield loads(real_estate_wkt) + + +@pytest.fixture +def plr_source_params(db_connection): + yield { + "code": "ch.StatischeWaldgrenzen", + "geometry_type": "LINESTRING", + "thresholds": { + "length": { + "limit": 1.0 + }, + "area": + {"limit": 1.0} + }, + "language": "de", + "federal": False, + "view_service": { + "layer_index": 1, + "layer_opacity": 1.0 + }, + "source": { + "class": "pyramid_oereb.contrib.sources.plr_oereblex.DatabaseOEREBlexSource", + "params": { + "db_connection": db_connection, + "model_factory": "pyramid_oereb.contrib.data_sources.standard." + "models.theme.model_factory_string_pk", + "schema_name": "forest_perimeters" + } + }, + "hooks": { + "get_symbol": "pyramid_oereb.contrib.data_sources.standard.hook_methods.get_symbol", + "get_symbol_ref": "pyramid_oereb.core.hook_methods.get_symbol_ref" + }, + "law_status_lookup": [{ + "data_code": "inKraft", + "transfer_code": "inKraft", + "extract_code": "inForce" + }, { + "data_code": "AenderungMitVorwirkung", + "transfer_code": "AenderungMitVorwirkung", + "extract_code": "changeWithPreEffect" + }, { + "data_code": "AenderungOhneVorwirkung", + "transfer_code": "AenderungOhneVorwirkung", + "extract_code": "changeWithoutPreEffect" + }], + "document_types_lookup": [{ + "data_code": "Rechtsvorschrift", + "transfer_code": "Rechtsvorschrift", + "extract_code": "LegalProvision" + }, { + "data_code": "GesetzlicheGrundlage", + "transfer_code": "GesetzlicheGrundlage", + "extract_code": "Law" + }, { + "data_code": "Hinweis", + "transfer_code": "Hinweis", + "extract_code": "Hint" + }] + } + + +@pytest.fixture(autouse=True) +def config_themes(app_config): + themes = [ + ThemeRecord( + "ch.StatischeWaldgrenzen", + {"de": "Statische Waldgrenzen"}, + 20 + ) + ] + with patch( + 'pyramid_oereb.core.config.Config.themes', themes + ), patch( + 'pyramid_oereb.core.config.Config._config', app_config + ): + yield + + +@pytest.fixture(autouse=True) +def config_config(plr_source_params): + mock_config = { + 'default_language': 'de', + 'srid': 2056, + 'geometry_types': { + 'point': { + 'types': { + 'Point', + 'MultiPoint' + } + }, + 'line': { + 'types': { + 'LineString', + 'LinearRing', + 'MultiLineString' + } + }, + 'polygon': { + 'types': { + 'Polygon', + 'MultiPolygon' + } + }, + 'collection': { + 'types': { + 'GeometryCollection' + } + } + }, + "plrs": [plr_source_params] + } + with patch('pyramid_oereb.core.config.Config._config', mock_config): + yield + + +@pytest.fixture +def all_plr_result_session(session, query): + class Query(query): + + def all(self): + return [] + + def filter(self, clause): + self.received_clause = clause + return self + + class Session(session): + + def query(self, term): + return Query() + + yield Session + + +@pytest.fixture +def base(): + yield declarative_base() + + +@pytest.fixture +def models(db_connection): + yield model_factory( + 'test', + String, + 'LINESTRING', + 2056, + db_connection + ) + + +@pytest.fixture +def view_service_model_class(models): + yield models.ViewService + + +@pytest.fixture +def legend_entry_model_class(models): + yield models.LegendEntry + + +@pytest.fixture +def legend_entries_from_db(legend_entry_model_class, png_binary): + yield [legend_entry_model_class(**{ + 'id': '1', + 'legend_text': {'de': 'testlegende without sub theme'}, + 'type_code': 'testCode', + 'type_code_list': 'testCode,testCode2,testCode3', + 'theme': 'ch.StatischeWaldgrenzen', + 'sub_theme': None, + 'view_service_id': '1', + 'symbol': b64.encode(png_binary) + })] + + +@pytest.fixture +def view_service_from_db(view_service_model_class): + yield view_service_model_class(**{ + 'id': '1', + 'reference_wms': {'de': 'https://geowms.bl.ch/?' + 'SERVICE=WMS&' + 'version=1.1.1&' + 'REQUEST=GetMap&' + 'layers=grundkarte_farbig_group&' + 'bbox=2614821,1259276,2618821,1263276&' + 'width=600&' + 'height=600&' + 'srs=EPSG:2056&' + 'format=image/png'}, + 'layer_index': 1, + 'layer_opacity': 1.0 + }) + + +@pytest.fixture +def legend_entry_records(png_binary): + yield [ + LegendEntryRecord( + ImageRecord(png_binary), + {'de': 'plr_legend_entry text'}, + 'testCode3', + 'testCode,testCode2,testCode3', + Config.themes[0], + 1 + ) + ] + + +@pytest.fixture +def document_type_record(): + yield DocumentTypeRecord( + "Rechtsvorschrift", + { + "de": "Rechtsvorschrift", + "fr": "Disposition juridique", + "it": "Prescrizione legale", + "rm": "Prescripziun giuridica", + "en": "Legal provision" + } + ) + + +@pytest.fixture +def document_records(document_type_record, law_status_records, yesterday, office_records): + yield [ + DocumentRecord( + document_type=document_type_record, + index=2, + law_status=law_status_records[0], + title={'de': 'Test Rechtsvorschrift'}, + published_from=yesterday, + responsible_office=office_records[0], + text_at_web={'de': 'http://meine.rechtsvorschrift.ch'}, + official_number={'de': 'rv.test.1'}, + abbreviation={'de': 'Test'}, + article_numbers=['Art.1', 'Art.2', 'Art.3'] + ) + ] + + +@pytest.fixture +def office_records(): + yield [ + OfficeRecord( + {'de': 'Office1'}, + 'abcde', + {'de': 'https://office1.url'}, + 'entrance 1', + 'building 1', + 'Office1 street', + '1a', + 4444, + 'Office1 City' + ) + ] + + +@pytest.fixture +def view_service_record(): + yield ViewServiceRecord( + {'de': 'http://my.wms.com'}, + 1, + 1.0, + 'de', + 2056, + None, + None + ) + + +@pytest.fixture +def geometry_records(law_status_records): + yield [ + GeometryRecord( + law_status_records[0], + datetime.date.today(), + None, + Point(0.5, 0.5) + ), + GeometryRecord( + law_status_records[0], + datetime.date.today(), + None, + LineString([(0, 0), (0, 1)]) + ), + GeometryRecord( + law_status_records[0], + datetime.date.today(), + None, + Polygon([(0, 0), (1, 1), (1, 0)]) + ) + ] + + +@pytest.fixture +def patch_config_get_law_status_by_data_code(law_status_records): + def get_law_status_by_data_code(code, law_status): + return law_status_records[0] + + with patch('pyramid_oereb.core.config.Config.get_law_status_by_data_code', get_law_status_by_data_code): + yield + + +@pytest.fixture +def patch_get_document_type_by_data_code(document_type_record): + def get_document_type_by_data_code(code, document_type): + return document_type_record + + with patch( + 'pyramid_oereb.core.config.Config.get_document_type_by_data_code', + get_document_type_by_data_code): + yield + + +@pytest.fixture +def patch_unwrap_multi_geometry(): + def mock_unwrap_multi_geometry(obj, law_status, published_from, published_until, geometry, geo_metadata): + return [obj, law_status, published_from, published_until, geometry, geo_metadata] + + with patch( + 'pyramid_oereb.contrib.data_sources.standard.sources.plr.DatabaseSource.unwrap_multi_geometry_', + mock_unwrap_multi_geometry): + yield + + +@pytest.fixture +def patch_unwrap_geometry_collection(): + def unwrap_geometry_collection(obj, law_status, published_from, published_until, geometry, geo_metadata): + return [obj, law_status, published_from, published_until, geometry, geo_metadata] + + with patch( + 'pyramid_oereb.contrib.data_sources.standard.sources.plr.' + 'DatabaseSource.unwrap_geometry_collection_', + unwrap_geometry_collection): + yield + + +@pytest.fixture +def patch_create_geometry_records(): + def create_geometry_records(obj, law_status, published_from, published_until, geometry, geo_metadata): + return [obj, law_status, published_from, published_until, geometry, geo_metadata] + + with patch( + 'pyramid_oereb.contrib.data_sources.standard.sources.plr.DatabaseSource.create_geometry_records_', + create_geometry_records): + yield + + +@pytest.fixture +def patch_from_db_to_office_record(office_records): + def from_db_to_office_record(obj, office_from_db): + return office_records[0] + with patch( + 'pyramid_oereb.contrib.data_sources.standard.sources.plr.DatabaseSource.from_db_to_office_record', + from_db_to_office_record): + yield + + +@pytest.fixture +def patch_from_db_to_legend_entry_record(legend_entry_records): + def from_db_to_legend_entry_record(obj, legend_entry_from_db): + return legend_entry_records[0] + with patch( + 'pyramid_oereb.contrib.data_sources.standard.sources.plr.DatabaseSource' + '.from_db_to_legend_entry_record', + from_db_to_legend_entry_record): + yield + + +@pytest.fixture +def patch_from_db_to_legend_entry_records(legend_entry_records): + def from_db_to_legend_entry_records(obj, legend_entries_from_db, legend_entry_record): + return legend_entry_records + with patch( + 'pyramid_oereb.contrib.data_sources.standard.sources.plr.DatabaseSource.' + 'from_db_to_legend_entry_records', + from_db_to_legend_entry_records): + yield + + +@pytest.fixture +def patch_from_db_to_view_service_record(view_service_record): + def from_db_to_view_service_record(obj, public_law_restriction_from_db, legend_entry_records): + return view_service_record + with patch( + 'pyramid_oereb.contrib.data_sources.standard.sources.plr.DatabaseSource.' + 'from_db_to_view_service_record', + from_db_to_view_service_record): + yield + + +@pytest.fixture +def patch_from_db_to_geometry_records(geometry_records): + def from_db_to_geometry_records(obj, public_law_restriction_from_db): + return geometry_records + with patch( + 'pyramid_oereb.contrib.data_sources.standard.sources.plr.DatabaseSource.' + 'from_db_to_geometry_records', + from_db_to_geometry_records): + yield + + +@pytest.fixture +def patch_from_db_to_document_records(document_records): + def from_db_to_document_records(obj, documents_from_db): + return document_records + with patch( + 'pyramid_oereb.contrib.data_sources.standard.sources.plr.DatabaseSource.' + 'from_db_to_document_records', + from_db_to_document_records): + yield + + +@pytest.fixture +def patch_config_get_document_types_lookups(plr_source_params): + def get_document_types_lookups(theme_code): + return plr_source_params['document_types_lookup'] + with patch( + 'pyramid_oereb.core.config.Config.get_document_types_lookups', + get_document_types_lookups): + yield + + +@pytest.fixture +def patch_config_get_document_type_by_data_code(document_type_record): + def get_document_type_by_data_code(theme_code, data_code): + return document_type_record + with patch( + 'pyramid_oereb.core.config.Config.get_document_type_by_data_code', + get_document_type_by_data_code): + yield + + +@pytest.fixture +def office_model_class(base): + from pyramid_oereb.contrib.data_sources.standard.models.main import get_office + Office = get_office(base, 'test', String) + yield Office + + +@pytest.fixture +def office_from_db(office_model_class): + yield [ + office_model_class(**{ + 'id': "1", + 'name': {'de': 'Office1'}, + 'office_at_web': {'de': 'https://office1.url'}, + 'uid': 'abcde', + 'line1': 'entrance 1', + 'line2': 'building 1', + 'street': 'Office1 street', + 'number': '1a', + 'postal_code': 4444, + 'city': 'Office1 City' + }), + office_model_class(**{ + 'id': "2", + 'name': {'de': 'Office2'}, + 'office_at_web': {'de': 'https://office2.url'}, + 'uid': 'fghij', + 'line1': 'entrance 2', + 'line2': 'building 2', + 'street': 'Office2 street', + 'number': '2a', + 'postal_code': 5555, + 'city': 'Office2 City' + }) + ] + + +@pytest.fixture +def document_db_values(png_binary, yesterday, tomorrow): + yield [{ + 'id': "1", + 'document_type': 'Hinweis', + 'index': 1, + 'law_status': 'inKraft', + 'title': {'de': 'Titel1'}, + 'office_id': 1, + 'published_from': yesterday, + 'published_until': tomorrow, + 'text_at_web': {'de': 'https://test1.abcd'}, + 'abbreviation': {'de': 'abkrz'}, + 'official_number': {'de': 'ch.abc.d123'}, + 'only_in_municipality': 1234, + 'file': png_binary + }, { + 'id': "2", + 'document_type': 'Gesetz', + 'index': 2, + 'law_status': 'inKraft', + 'title': {'de': 'Titel2'}, + 'office_id': 1, + 'published_from': yesterday, + 'published_until': tomorrow, + 'text_at_web': {'de': 'https://test2.abcd'}, + 'abbreviation': {'de': 'abkrz'}, + 'official_number': {'de': 'ch.abc.d321'}, + 'only_in_municipality': 4567, + 'file': png_binary + }] + + +@pytest.fixture +def document_model_class(base, office_model_class): + from pyramid_oereb.contrib.data_sources.standard.models.main import get_document + document_model = get_document(base, 'test', String, office_model_class) + yield document_model + + +@pytest.fixture +def documents_from_db(document_model_class, document_db_values): + yield [ + document_model_class(**document_db_values[0]), + document_model_class(**document_db_values[1]) + ] + + +@pytest.fixture +def plr_model_class(models): + yield models.PublicLawRestriction + + +@pytest.fixture +def plrs_from_db(plr_model_class, yesterday, tomorrow, view_service_from_db, + office_from_db, legend_entries_from_db, geometries_from_db): + geometries_from_db[0].public_law_restriction_id = '1' + plr_from_db_1 = plr_model_class(**{ + 'id': "1", + 'law_status': 'inKraft', + 'published_from': yesterday, + 'published_until': tomorrow, + 'view_service_id': view_service_from_db.id, + 'view_service': view_service_from_db, + 'office_id': office_from_db[0].id, + 'legend_entry_id': legend_entries_from_db[0].id, + 'legend_entry': legend_entries_from_db[0], + 'geometries': [geometries_from_db[0]], + }) + yield [ + plr_from_db_1 + ] + + +@pytest.fixture +def wkb_geom(): + yield [WKTElement( + "SRID=2056;LINESTRING((" + "2609229.759 1263666.789," + "2609231.206 1263670.558," + "2609229.561 1263672.672," + "2609229.472 1263675.47," + "2609251.865 1263727.506," + "2609275.847 1263783.29," + "2609229.759 1263666.789" + "))", + extended=True + ), WKTElement( + "SRID=2056;LINESTRING((" + "2608901.529 1261990.655," + "2608898.665 1261991.598," + "2608895.798 1261992.53," + "2608892.928 1261993.452," + "2608890.054 1261994.363," + "2608880.256 1261996.496" + "2608901.529 1261990.655" + "))", + extended=True + )] + + +@pytest.fixture +def geometry_model_class(models): + yield models.Geometry + + +@pytest.fixture +def geometries_from_db(geometry_model_class, wkb_geom): + published_from = datetime.date.today() - datetime.timedelta(days=1) + published_until = datetime.date.today() + datetime.timedelta(days=1) + geo_metadata = 'https://geocat.ch' + yield [ + geometry_model_class(**{ + "id": "1", + "law_status": 'inKraft', + "published_from": published_from, + "published_until": published_until, + "geo_metadata": geo_metadata, + "geom": wkb_geom[0] + }) + ] + + +@pytest.fixture +def params(): + yield Parameter('xml', language='de') + + +def test_init(plr_source_params): + from pyramid_oereb.contrib.data_sources.oereblex.sources.plr_oereblex import DatabaseOEREBlexSource + from pyramid_oereb.contrib.data_sources.oereblex.sources.document import OEREBlexSource + source = DatabaseOEREBlexSource(**plr_source_params) + assert source._queried_geolinks == {} + assert isinstance(source._oereblex_source, OEREBlexSource) + + +@pytest.mark.parametrize('url_param_config,plr_code,output', [ + ( + [{"code": "ch.StatischeWaldgrenzen", "url_param": "oereb_id=5"}], + "ch.StatischeWaldgrenzen", "oereb_id=5" + ), + ( + [{"code": "ch.StatischeWaldgrenzen"}], + "ch.StatischeWaldgrenzen", None + ), + ( + [{"code": "ch.StatischeWaldgrenzen", "url_param": "oereb_id=5"}], + "BogusPlrCode", None + ) +]) +def test_get_config_value_for_plr_code(plr_source_params, url_param_config, plr_code, output): + from pyramid_oereb.contrib.data_sources.oereblex.sources.plr_oereblex import DatabaseOEREBlexSource + assert output == DatabaseOEREBlexSource.get_config_value_for_plr_code(url_param_config, plr_code) + + +@pytest.mark.parametrize('url_param_config,plr_code,output', [ + ([{"url_param": "oereb_id=5"}], "ch.StatischeWaldgrenzen", "oereb_id=5") +]) +def test_get_config_value_for_plr_code_raises(plr_source_params, url_param_config, plr_code, output): + from pyramid_oereb.contrib.data_sources.oereblex.sources.plr_oereblex import DatabaseOEREBlexSource + with pytest.raises(LookupError): + DatabaseOEREBlexSource.get_config_value_for_plr_code(url_param_config, plr_code) + + +def test_get_document_records(plr_source_params, document_records, params, plrs_from_db, law_status_records): + with patch( + 'pyramid_oereb.contrib.data_sources.oereblex.sources.plr_oereblex.DatabaseOEREBlexSource' + '.document_records_from_oereblex', + return_value=document_records), \ + patch('pyramid_oereb.core.config.Config.law_status', law_status_records), \ + patch( + 'pyramid_oereb.core.config.Config.get_law_status_lookups', + return_value=plr_source_params['law_status_lookup'] + ): + from pyramid_oereb.contrib.data_sources.oereblex.sources.plr_oereblex import DatabaseOEREBlexSource + source = DatabaseOEREBlexSource(**plr_source_params) + assert source.get_document_records(params, plrs_from_db[0]) == document_records + + +def test_document_records_from_oereblex(plr_source_params, document_records, params, law_status_records): + with patch( + 'pyramid_oereb.contrib.data_sources.oereblex.sources.document.OEREBlexSource.read', + return_value=None + ), patch( + "pyramid_oereb.contrib.data_sources.oereblex.sources.document.OEREBlexSource.records", + document_records + ): + from pyramid_oereb.contrib.data_sources.oereblex.sources.plr_oereblex import DatabaseOEREBlexSource + + source = DatabaseOEREBlexSource(**plr_source_params) + assert source.document_records_from_oereblex( + params, + 1, + law_status_records[0], + "oereb_id=5" + ) == document_records diff --git a/tests/contrib.data_sources.oereblex/test_create_tables.py b/tests/contrib.data_sources.oereblex/test_create_tables.py new file mode 100644 index 0000000000..dbd9e2218e --- /dev/null +++ b/tests/contrib.data_sources.oereblex/test_create_tables.py @@ -0,0 +1,31 @@ +import pytest +import sys + + +def test_call_no_args(): + from pyramid_oereb.contrib.data_sources.oereblex.create_tables import create_oereblex_tables + sys.argv = [] + with pytest.raises(IndexError): + create_oereblex_tables() + + +def test_call_config_missing(): + from pyramid_oereb.contrib.data_sources.oereblex.create_tables import create_oereblex_tables + sys.argv = ["-h"] + with pytest.raises(SystemExit): + create_oereblex_tables() + + +def test_call_help(): + from pyramid_oereb.contrib.data_sources.oereblex.create_tables import create_oereblex_tables + sys.argv = [ + # first element int array is always the script path, + # we can leave empty because we fake the syscall + # directly in python + "", + "-h" + ] + with pytest.raises(SystemExit) as code: + create_oereblex_tables() + # means script exited correctly + assert code.value.code == 0 From dc34f2cf627b14923df11b1e54bb8f51bff3354d Mon Sep 17 00:00:00 2001 From: Anne Maier Date: Fri, 1 Dec 2023 07:46:55 +0100 Subject: [PATCH 17/60] add simple tests for get_config functions --- tests/core/test_config.py | 191 +++++++++++++++++++++++++++++++++++++- 1 file changed, 189 insertions(+), 2 deletions(-) diff --git a/tests/core/test_config.py b/tests/core/test_config.py index 77decb9523..50b69be72c 100644 --- a/tests/core/test_config.py +++ b/tests/core/test_config.py @@ -397,7 +397,7 @@ def test_get_glossary_config(test_value, expected_results): @pytest.mark.run(order=-1) -def test_get_document_config_none(): +def test_get_glossary_config_none(): Config._config = None with pytest.raises(AssertionError): Config.get_glossary_config() @@ -1090,8 +1090,195 @@ def mock_read_offices(): @pytest.mark.run(order=1) def test_get_config(): Config._config = None - assert Config.get_config() == None + assert Config.get_config() is None Config._config = {} assert Config.get_config() == {} # set config back to None. Config._config = None + + +@pytest.mark.parametrize('test_value,expected_value', [ + ({'real_estate': {'plan_for_land_register_main_page': {}}}, {}), + ({'not_expecting_key': {}}, None) +]) +@pytest.mark.run(order=-1) +def test_get_plan_for_land_register_main_page_config(test_value, expected_value): + Config._config = test_value + assert Config.get_plan_for_land_register_main_page_config() == expected_value + + +@pytest.mark.run(order=-1) +def test_get_plan_for_land_register_main_page_config_none(): + Config._config = None + with pytest.raises(AssertionError): + Config.get_plan_for_land_register_main_page_config() + + +@pytest.mark.parametrize('test_value,expected_value', [ + ({'real_estate': {'plan_for_land_register': {}}}, {}), + ({'not_expecting_key': {}}, None) +]) +@pytest.mark.run(order=-1) +def test_get_plan_for_land_register_config(test_value, expected_value): + Config._config = test_value + assert Config.get_plan_for_land_register_config() == expected_value + + +@pytest.mark.run(order=-1) +def test_get_plan_for_land_register_config_none(): + Config._config = None + with pytest.raises(AssertionError): + Config.get_plan_for_land_register_config() + + +@pytest.mark.parametrize('test_value,expected_value', [ + ({'address': {}}, {}), + ({'not_expecting_key': {}}, None) +]) +@pytest.mark.run(order=-1) +def test_get_address_config(test_value, expected_value): + Config._config = test_value + assert Config.get_address_config() == expected_value + + +@pytest.mark.run(order=-1) +def test_get_address_config_none(): + Config._config = None + with pytest.raises(AssertionError): + Config.get_address_config() + + +@pytest.mark.parametrize('test_value,expected_value', [ + ({'theme_document': {}}, {}), + ({'not_expecting_key': {}}, None) +]) +@pytest.mark.run(order=-1) +def test_get_theme_document_config(test_value, expected_value): + Config._config = test_value + assert Config.get_theme_document_config() == expected_value + + +@pytest.mark.run(order=-1) +def test_get_theme_document_config_none(): + Config._config = None + with pytest.raises(AssertionError): + Config.get_theme_document_config() + + +@pytest.mark.parametrize('test_value,expected_value', [ + ({'document_types': {}}, {}), + ({'not_expecting_key': {}}, None) +]) +@pytest.mark.run(order=-1) +def test_get_document_types_config(test_value, expected_value): + Config._config = test_value + assert Config.get_document_types_config() == expected_value + + +@pytest.mark.run(order=-1) +def test_get_document_types_config_none(): + Config._config = None + with pytest.raises(AssertionError): + Config.get_document_types_config() + + +@pytest.mark.parametrize('test_value,expected_value', [ + ({'disclaimer': {}}, {}), + ({'not_expecting_key': {}}, None) +]) +@pytest.mark.run(order=-1) +def test_get_disclaimer_config(test_value, expected_value): + Config._config = test_value + assert Config.get_disclaimer_config() == expected_value + + +@pytest.mark.run(order=-1) +def test_get_disclaimer_config_none(): + Config._config = None + with pytest.raises(AssertionError): + Config.get_disclaimer_config() + + +@pytest.mark.parametrize('test_value,expected_value', [ + ({'general_information': {}}, {}), + ({'not_expecting_key': {}}, None) +]) +@pytest.mark.run(order=-1) +def test_get_info_config(test_value, expected_value): + Config._config = test_value + assert Config.get_info_config() == expected_value + + +@pytest.mark.run(order=-1) +def test_get_info_config_none(): + Config._config = None + with pytest.raises(AssertionError): + Config.get_info_config() + + +@pytest.mark.parametrize('test_value,expected_value', [ + ({'documents': {}}, {}), + ({'not_expecting_key': {}}, None) +]) +@pytest.mark.run(order=-1) +def test_get_document_config(test_value, expected_value): + Config._config = test_value + assert Config.get_document_config() == expected_value + + +@pytest.mark.run(order=-1) +def test_get_document_config_none(): + Config._config = None + with pytest.raises(AssertionError): + Config.get_document_config() + + +@pytest.mark.parametrize('test_value,expected_value', [ + ({'offices': {}}, {}), + ({'not_expecting_key': {}}, None) +]) +@pytest.mark.run(order=-1) +def test_get_office_config(test_value, expected_value): + Config._config = test_value + assert Config.get_office_config() == expected_value + + +@pytest.mark.run(order=-1) +def test_get_office_config_none(): + Config._config = None + with pytest.raises(AssertionError): + Config.get_office_config() + + +@pytest.mark.parametrize('test_value,expected_value', [ + ({'municipality': {}}, {}), + ({'not_expecting_key': {}}, None) +]) +@pytest.mark.run(order=-1) +def test_get_municipality_config(test_value, expected_value): + Config._config = test_value + assert Config.get_municipality_config() == expected_value + + +@pytest.mark.run(order=-1) +def test_get_municipality_config_none(): + Config._config = None + with pytest.raises(AssertionError): + Config.get_municipality_config() + + +@pytest.mark.parametrize('test_value,expected_value', [ + ({'availability': {}}, {}), + ({'not_expecting_key': {}}, None) +]) +@pytest.mark.run(order=-1) +def test_get_availability_config(test_value, expected_value): + Config._config = test_value + assert Config.get_availability_config() == expected_value + + +@pytest.mark.run(order=-1) +def test_get_availability_config_none(): + Config._config = None + with pytest.raises(AssertionError): + Config.get_availability_config() From 4b50c01444de971b4774a9c311701b3f16cfdc71 Mon Sep 17 00:00:00 2001 From: Anne Maier Date: Fri, 1 Dec 2023 10:08:49 +0100 Subject: [PATCH 18/60] test_availability_by_theme_code_municipality_fosnr --- tests/core/test_config.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/core/test_config.py b/tests/core/test_config.py index 8c506d7db5..e457c9f188 100644 --- a/tests/core/test_config.py +++ b/tests/core/test_config.py @@ -23,6 +23,7 @@ from pyramid_oereb.core.readers.document_types import DocumentTypeReader from pyramid_oereb.core.readers.real_estate_type import RealEstateTypeReader from pyramid_oereb.core.readers.map_layering import MapLayeringReader +from pyramid_oereb.core.records.availability import AvailabilityRecord # order=-1 to run them after all and don't screw the configuration in Config @@ -1085,3 +1086,31 @@ def mock_read_offices(): Config._config = None Config.init_offices() assert Config.offices is None + + +@pytest.fixture() +def availabilities_records(): + yield [AvailabilityRecord(2771, 'ch.Nutzungsplanung', True), + AvailabilityRecord(2772, 'ch.Nutzungsplanung', False)] + + +@pytest.mark.parametrize('test_value,expected_value', [ + ({"theme_code": "ch.Nutzungsplanung", + "fosnr": 2771}, True), + ({"theme_code": "ch.Nutzungsplanung", + "fosnr": 2772}, False) +]) +@pytest.mark.run(order=1) +def test_availability_by_theme_code_municipality_fosnr(test_value, expected_value, availabilities_records): + Config.availabilities = availabilities_records + assert Config.availability_by_theme_code_municipality_fosnr( + test_value.get("theme_code"), test_value.get("fosnr")) == expected_value + assert Config.availability_by_theme_code_municipality_fosnr('notInList', test_value.get("fosnr")) is True + assert Config.availability_by_theme_code_municipality_fosnr(test_value.get("theme_code"), 0) is True + + +@pytest.mark.run(order=1) +def test_availability_by_theme_code_municipality_fosnr_config_none(): + Config.availabilities = None + with pytest.raises(ConfigurationError): + Config.availability_by_theme_code_municipality_fosnr('BN', 2771) From c7f197c4499a1ca0094e08e43330355690664dd0 Mon Sep 17 00:00:00 2001 From: Anne Maier Date: Fri, 1 Dec 2023 10:12:24 +0100 Subject: [PATCH 19/60] test_municipality_by_fosnr --- pyramid_oereb/core/config.py | 2 ++ tests/core/test_config.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/pyramid_oereb/core/config.py b/pyramid_oereb/core/config.py index 849f80f294..84319b1c90 100644 --- a/pyramid_oereb/core/config.py +++ b/pyramid_oereb/core/config.py @@ -2087,6 +2087,8 @@ def municipality_by_fosnr(fosnr): ConfigurationError: If no match was found """ + if Config.municipalities is None: + raise ConfigurationError("The municipalities have not been initialized") for municipality in Config.municipalities: if municipality.fosnr == fosnr: return municipality diff --git a/tests/core/test_config.py b/tests/core/test_config.py index 8c506d7db5..93f73bc9f2 100644 --- a/tests/core/test_config.py +++ b/tests/core/test_config.py @@ -23,6 +23,7 @@ from pyramid_oereb.core.readers.document_types import DocumentTypeReader from pyramid_oereb.core.readers.real_estate_type import RealEstateTypeReader from pyramid_oereb.core.readers.map_layering import MapLayeringReader +from pyramid_oereb.core.records.municipality import MunicipalityRecord # order=-1 to run them after all and don't screw the configuration in Config @@ -1085,3 +1086,33 @@ def mock_read_offices(): Config._config = None Config.init_offices() assert Config.offices is None + + +@pytest.fixture() +def municipality_records(): + yield [MunicipalityRecord(2771, 'Gemeinde', True), + MunicipalityRecord(2772, 'Gemeinde2', False)] + + +@pytest.mark.parametrize('test_value,expected_index', [ + (2771, 0), + (2772, 1) +]) +@pytest.mark.run(order=1) +def test_municipality_by_fosnr(test_value, expected_index, municipality_records): + Config.municipalities = municipality_records + assert Config.municipality_by_fosnr(test_value) == municipality_records[expected_index] + + +@pytest.mark.run(order=1) +def test_municipality_by_fosnr_config_none(): + Config.municipalities = None + with pytest.raises(ConfigurationError): + Config.municipality_by_fosnr(0) + + +@pytest.mark.run(order=1) +def test_municipality_by_fosnr_not_in_list(municipality_records): + Config.municipalities = municipality_records + with pytest.raises(ConfigurationError): + Config.municipality_by_fosnr(0) From bdf0d027de1cecea36d1279062628fbbc69eb020 Mon Sep 17 00:00:00 2001 From: Anne Maier Date: Fri, 1 Dec 2023 10:27:11 +0100 Subject: [PATCH 20/60] test_get_law_status_lookups --- tests/core/test_config.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/core/test_config.py b/tests/core/test_config.py index 8c506d7db5..a6cb707330 100644 --- a/tests/core/test_config.py +++ b/tests/core/test_config.py @@ -1085,3 +1085,22 @@ def mock_read_offices(): Config._config = None Config.init_offices() assert Config.offices is None + + +@pytest.mark.parametrize('test_value,expected_value', [ + ({"law_status_lookup": {}}, {}), + ({"law_status_lookup": ""}, "") +]) +@pytest.mark.run(order=1) +def test_get_law_status_lookups(test_value, expected_value): + Config._config = None + with patch.object(Config, 'get_theme_config_by_code', return_value=test_value): + assert Config.get_law_status_lookups('theme_code') == expected_value + + +@pytest.mark.run(order=1) +def test_get_law_status_lookups_lookups_none(): + Config._config = None + with patch.object(Config, 'get_theme_config_by_code', return_value={"law_status_lookup": None}): + with pytest.raises(ConfigurationError): + Config.get_law_status_lookups('theme_code') From ce71ace09b977aaf751d9aca47aafce7e871d982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Voisard?= Date: Fri, 1 Dec 2023 10:59:17 +0100 Subject: [PATCH 21/60] 1392 test interlis theme (#1876) * basic model creation test * typo * linting * linting * some more test cases for theme * linting * added some fixtures * fixed some descriptions * use declarative_base from fixture * fix rebase conflict --------- Co-authored-by: Clemens Rudert --- doc/source/contrib/print_proxy/xml2pdf.rst | 39 ++++++++ .../data_sources/interlis_2_3/models/theme.py | 11 ++- .../conftest.py | 29 +++++- .../models/test_theme.py | 91 +++++++++++++++++++ 4 files changed, 161 insertions(+), 9 deletions(-) create mode 100644 doc/source/contrib/print_proxy/xml2pdf.rst create mode 100644 tests/contrib.data_sources.interlis_2_3/models/test_theme.py diff --git a/doc/source/contrib/print_proxy/xml2pdf.rst b/doc/source/contrib/print_proxy/xml2pdf.rst new file mode 100644 index 0000000000..a4ba133243 --- /dev/null +++ b/doc/source/contrib/print_proxy/xml2pdf.rst @@ -0,0 +1,39 @@ +.. _contrib-print_proxy-xml2pdf: + +XML2PDF +------- + +Configuration +............. + + +To properly configure the XML2PDF print service of GISDATEN AG, you need specific configuration in the section +``print`` of your ``yaml`` file. +Please see the `standard configuration file +`__ +as an example, or use the ``create_standard_yaml`` script to regenerate your configuration file with the desired options. + + + + +.. _api-pyramid_oereb-contrib-print_proxy-xml_2_pdf: + +.. automodule:: pyramid_oereb.contrib.print_proxy.xml_2_pdf + + +.. _api-pyramid_oereb-contrib-print_proxy-xml_2_pdf-xml_2_pdf: + +.. automodule:: pyramid_oereb.contrib.print_proxy.xml_2_pdf.xml_2_pdf + + +.. _api-pyramid_oereb-contrib-print_proxy-xml_2_pdf-xml_2_pdf-renderer: + +*Xml 2 Pdf Renderer* +^^^^^^^^^^^^^^^^^^^^ + +.. autoclass:: pyramid_oereb.contrib.print_proxy.xml_2_pdf.xml_2_pdf.Renderer + :members: + :inherited-members: + + .. automethod:: __init__ + diff --git a/pyramid_oereb/contrib/data_sources/interlis_2_3/models/theme.py b/pyramid_oereb/contrib/data_sources/interlis_2_3/models/theme.py index dd3c203ec9..6af295a206 100644 --- a/pyramid_oereb/contrib/data_sources/interlis_2_3/models/theme.py +++ b/pyramid_oereb/contrib/data_sources/interlis_2_3/models/theme.py @@ -30,7 +30,7 @@ def __init__(self, office, document, view_service, def generic_models(base, schema_name, pk_type): """ - Factory to produce a set of generic standard models. + Factory to produce a set of generic interlis 2.3 models. Args: base (): The SQLAlchemy base which is assigned to the models. @@ -170,7 +170,7 @@ class Document(base): def model_factory(schema_name, pk_type, srid, db_connection): """ - Factory to produce a set of standard models. + Factory to produce a set of interlis 2.3 models. Args: schema_name (str): The name of the database schema where this models belong to. @@ -179,9 +179,10 @@ def model_factory(schema_name, pk_type, srid, db_connection): needs geometry_type (str): The geoalchemy geometry type defined as well known string. srid (int): The SRID defining the projection of the geometries stored in standard db schema. + db_connection (str): the db connection string Returns: - Models: the produced set of standard models + Models: the produced set of interlis 2.3 models """ Base = declarative_base() @@ -531,7 +532,7 @@ def model_factory_integer_pk(schema_name, geometry_type, srid, db_connection): db_connection (str): the db connection string Returns: - Models: the produced set of standard models + Models: the produced set of interlis 2.3 models """ if geometry_type is not None: geometry_type = None @@ -547,7 +548,7 @@ def model_factory_string_pk(schema_name, geometry_type, srid, db_connection): db_connection (str): the db connection string Returns: - Models: the produced set of standard models + Models: the produced set of interlis 2.3 models """ if geometry_type is not None: geometry_type = None diff --git a/tests/contrib.data_sources.interlis_2_3/conftest.py b/tests/contrib.data_sources.interlis_2_3/conftest.py index b10b5c474b..b607ec579f 100644 --- a/tests/contrib.data_sources.interlis_2_3/conftest.py +++ b/tests/contrib.data_sources.interlis_2_3/conftest.py @@ -3,6 +3,8 @@ from unittest.mock import patch from PIL import Image +from sqlalchemy import Integer +from sqlalchemy.orm import declarative_base @pytest.fixture @@ -35,10 +37,9 @@ def one(self): @pytest.fixture(autouse=True) def srid(): - def srid(): - return 2056 - with patch('pyramid_oereb.core.config.Config.get_srid', srid): - yield + srid_value = 2056 + with patch('pyramid_oereb.core.config.Config.get_srid', return_value=srid_value): + yield srid_value @pytest.fixture @@ -51,3 +52,23 @@ def png_binary(png_image): output = io.BytesIO() png_image.save(output, format='PNG') yield output.getvalue() + + +@pytest.fixture +def base(): + yield declarative_base() + + +@pytest.fixture +def db_connection(): + yield "postgresql://mock_user:pass@123.123.123.123:5432/oereb_mock_db" + + +@pytest.fixture +def pk_type(): + yield Integer + + +@pytest.fixture +def schema_name(): + yield 'test_schema' diff --git a/tests/contrib.data_sources.interlis_2_3/models/test_theme.py b/tests/contrib.data_sources.interlis_2_3/models/test_theme.py new file mode 100644 index 0000000000..b40d7fe62b --- /dev/null +++ b/tests/contrib.data_sources.interlis_2_3/models/test_theme.py @@ -0,0 +1,91 @@ +from sqlalchemy import Integer, String +from geoalchemy2.types import Geometry as GeoAlchemyGeometry + +from pyramid_oereb.contrib.data_sources.interlis_2_3.models.theme import ( + Models, model_factory, model_factory_string_pk, model_factory_integer_pk +) + + +def test_models(db_connection, schema_name, base): + + office = 'ne.scat' + document = 'some document object' + view_service = 'https://www.example.com' + legend_entry = 1 + public_law_restriction = [{'id': 1, 'type_code': '5b'}, {'id': 2, 'type_code': '3a'}] + geometry = 'geom' + public_law_restriction_document = 'a' + localised_blob = 'blob' + localised_uri = 'https://www.cadastre.ch/fr' + multilingual_blob = {'fr': 'blob', 'de': 'blubb, blubb'} + multilingual_uri = {'de': 'https://www.cadastre.ch/de/home.html', + 'fr': 'https://www.cadastre.ch/fr/home.html'} + + new_model = Models(office, document, view_service, + legend_entry, public_law_restriction, geometry, + public_law_restriction_document, + localised_blob, localised_uri, multilingual_blob, multilingual_uri, + base, db_connection, schema_name + ) + + assert new_model.Office == 'ne.scat' + assert new_model.Document == 'some document object' + assert new_model.ViewService == 'https://www.example.com' + assert new_model.LegendEntry == 1 + assert isinstance(new_model.PublicLawRestriction, list) + assert new_model.PublicLawRestriction[1] == {'id': 2, 'type_code': '3a'} + assert new_model.Geometry == 'geom' + assert new_model.PublicLawRestrictionDocument == 'a' + assert new_model.LocalisedBlob == 'blob' + assert new_model.LocalisedUri == 'https://www.cadastre.ch/fr' + assert new_model.MultilingualBlob == {'fr': 'blob', 'de': 'blubb, blubb'} + assert isinstance(new_model.MultilingualUri, dict) + assert new_model.MultilingualUri['de'] == 'https://www.cadastre.ch/de/home.html' + assert new_model.Base == base + assert new_model.db_connection == 'postgresql://mock_user:pass@123.123.123.123:5432/oereb_mock_db' + assert new_model.schema_name == 'test_schema' + + +def test_model_factory(db_connection, schema_name, pk_type, srid): + + models = model_factory( + schema_name, + pk_type, + srid, + db_connection + ) + assert isinstance(models, Models) + assert models.db_connection == db_connection + assert models.PublicLawRestriction.__table_args__['schema'] == schema_name + assert isinstance(models.PublicLawRestriction.t_id.type, pk_type) + assert isinstance(models.Geometry.point.type, GeoAlchemyGeometry) + assert models.Geometry.point.type.geometry_type == 'POINT' + assert models.Geometry.line.type.geometry_type == 'LINESTRING' + assert models.Geometry.surface.type.geometry_type == 'POLYGON' + assert models.Geometry.point.type.srid == srid + + +def test_model_factory_string_pk(db_connection, schema_name, srid): + + geometry_type = 'POINT' + + models = model_factory_string_pk( + schema_name, + geometry_type, + srid, + db_connection + ) + assert isinstance(models.PublicLawRestriction.t_id.type, String) + + +def test_model_factory_integer_pk(db_connection, schema_name, srid): + + geometry_type = 'POINT' + + models = model_factory_integer_pk( + schema_name, + geometry_type, + srid, + db_connection + ) + assert isinstance(models.PublicLawRestriction.t_id.type, Integer) From 07324f3414afe16f3ebfba7f52680c4e3458941f Mon Sep 17 00:00:00 2001 From: Anne Maier Date: Fri, 1 Dec 2023 11:25:00 +0100 Subject: [PATCH 22/60] test_get_law_status_lookup_by_theme_code_key_code --- pyramid_oereb/core/config.py | 5 +++++ tests/core/test_config.py | 42 ++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/pyramid_oereb/core/config.py b/pyramid_oereb/core/config.py index 849f80f294..925c1483a4 100644 --- a/pyramid_oereb/core/config.py +++ b/pyramid_oereb/core/config.py @@ -1666,6 +1666,11 @@ def get_law_status_lookup_by_theme_code_key_code(theme_code, key, code): """ lookups = Config.get_law_status_lookups(theme_code) + if lookups is None: + raise ConfigurationError( + 'Law status lookup for theme {} is not ' + 'defined in configuration!'.format(theme_code) + ) for lookup in lookups: if lookup[key] == code: return lookup diff --git a/tests/core/test_config.py b/tests/core/test_config.py index 8c506d7db5..cb644d5c8c 100644 --- a/tests/core/test_config.py +++ b/tests/core/test_config.py @@ -1085,3 +1085,45 @@ def mock_read_offices(): Config._config = None Config.init_offices() assert Config.offices is None + + +@pytest.fixture() +def law_status_lookups(): + yield [{"data_code": "inKraft", + "transfer_code": "inKraft", + "extract_code": "inForce"}, + {"data_code": "AenderungMitVorwirkung", + "transfer_code": "AenderungMitVorwirkung", + "extract_code": "changeWithPreEffect"}] + + +@pytest.mark.parametrize('test_value,expected_value', [ + ({"theme_code": "ch.Nutzungsplanung", + "key": "data_code", + "code": "inKraft"}, "inForce"), + ({"theme_code": "ch.Nutzungsplanung", + "key": "data_code", + "code": "AenderungMitVorwirkung"}, "changeWithPreEffect") +]) +@pytest.mark.run(order=1) +def test_get_law_status_lookup_by_theme_code_key_code(test_value, expected_value, law_status_lookups): + with patch.object(Config, 'get_law_status_lookups', return_value=law_status_lookups): + assert Config.get_law_status_lookup_by_theme_code_key_code( + test_value.get("theme_code"), + test_value.get("key"), + test_value.get("code")).get("extract_code") == expected_value + + +@pytest.mark.parametrize('test_value', [ + ({}), + ([]), + (None) +]) +@pytest.mark.run(order=1) +def test_get_law_status_lookup_by_theme_code_key_code_no_key(test_value): + with patch.object(Config, 'get_law_status_lookups', return_value=test_value): + with pytest.raises(ConfigurationError): + Config.get_law_status_lookup_by_theme_code_key_code( + "ch.Nutzungsplanung", + "data_code", + "inKraft") From 8b6eec2a99ef079e749f2cc5913946a9f3cdcafd Mon Sep 17 00:00:00 2001 From: Anne Maier Date: Fri, 1 Dec 2023 11:37:45 +0100 Subject: [PATCH 23/60] test_get_law_status_lookup_by_data_code --- tests/core/test_config.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/core/test_config.py b/tests/core/test_config.py index 8c506d7db5..388a9cf146 100644 --- a/tests/core/test_config.py +++ b/tests/core/test_config.py @@ -1085,3 +1085,19 @@ def mock_read_offices(): Config._config = None Config.init_offices() assert Config.offices is None + + +@pytest.mark.parametrize('test_value', [ + ({"data_code": "inKraft", + "transfer_code": "inKraft", + "extract_code": "inForce"}), + ({"data_code": "AenderungMitVorwirkung", + "transfer_code": "AenderungMitVorwirkung", + "extract_code": "changeWithPreEffect"}) +]) +@pytest.mark.run(order=1) +def test_get_law_status_lookup_by_data_code(test_value): + with patch.object(Config, 'get_law_status_lookup_by_theme_code_key_code', return_value=test_value): + assert Config.get_law_status_lookup_by_data_code( + "theme_code", + "data_code") == test_value From c8201eec7848cf6f655aa9cb63f4dffd7e3586ba Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Fri, 1 Dec 2023 11:40:30 +0100 Subject: [PATCH 24/60] update adapter tests --- tests/adapter/__init__.py | 1 - tests/adapter/test_database.py | 45 --------------- tests/core/test_adapter_database.py | 57 +++++++++++++++++++ .../test_adapter_file.py} | 2 +- 4 files changed, 58 insertions(+), 47 deletions(-) delete mode 100644 tests/adapter/__init__.py delete mode 100644 tests/adapter/test_database.py create mode 100644 tests/core/test_adapter_database.py rename tests/{adapter/test_file.py => core/test_adapter_file.py} (98%) diff --git a/tests/adapter/__init__.py b/tests/adapter/__init__.py deleted file mode 100644 index 40a96afc6f..0000000000 --- a/tests/adapter/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# -*- coding: utf-8 -*- diff --git a/tests/adapter/test_database.py b/tests/adapter/test_database.py deleted file mode 100644 index 4715523fd2..0000000000 --- a/tests/adapter/test_database.py +++ /dev/null @@ -1,45 +0,0 @@ -# -*- coding: utf-8 -*- -import pytest -from sqlalchemy.exc import ArgumentError -from sqlalchemy.orm import Session - -from pyramid_oereb.core.config import Config -from pyramid_oereb.core.adapter import DatabaseAdapter - - -def test_init(): - adapter = DatabaseAdapter() - assert isinstance(adapter._connections_, dict) - - -def test_get_connections(): - adapter = DatabaseAdapter() - assert isinstance(adapter.get_connections(), dict) - - -def test_add_connection(): - db_url = Config.get('app_schema').get('db_connection') - adapter = DatabaseAdapter() - adapter.add_connection(db_url) - assert isinstance(adapter.get_session(db_url), Session) - - -def test_add_existing_connection(): - db_url = Config.get('app_schema').get('db_connection') - adapter = DatabaseAdapter() - adapter.add_connection(db_url) - expected_length = len(adapter.get_connections()) - adapter.add_connection(db_url) - assert len(adapter.get_connections()) == expected_length - - -def test_add_connection_fail(): - adapter = DatabaseAdapter() - with pytest.raises(ArgumentError): - adapter.add_connection('not_a_connection_string') - - -def test_get_connection_fail(): - adapter = DatabaseAdapter() - with pytest.raises(ArgumentError): - adapter.get_session('not_a_connection_string') diff --git a/tests/core/test_adapter_database.py b/tests/core/test_adapter_database.py new file mode 100644 index 0000000000..68ddad75f3 --- /dev/null +++ b/tests/core/test_adapter_database.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +import logging +from sqlalchemy.orm import Session +from pyramid_oereb.core.adapter import DatabaseAdapter + + +def test_init(): + adapter = DatabaseAdapter() + assert isinstance(adapter._connections_, dict) + + +def test_get_connections(): + adapter = DatabaseAdapter() + assert isinstance(adapter.get_connections(), dict) + + +def test_add_connection(): + db_url = 'postgresql://adapter_user:adapter_pswd@adapter-tests-00:5432/adapter-db' + adapter = DatabaseAdapter() + adapter.add_connection(db_url) + assert isinstance(adapter.get_session(db_url), Session) + + +def test_add_connection_already_exists(caplog): + caplog.set_level(logging.INFO) + db_url = 'postgresql://adapter_user:adapter_pswd@adapter-tests-01:5432/adapter-db' + adapter = DatabaseAdapter() + adapter.add_connection(db_url) + assert 'Connection already exists: {0}'.format(db_url) not in caplog.text + adapter.add_connection(db_url) + assert 'Connection already exists: {0}'.format(db_url) in caplog.text + + +def test_get_connections(): + db_url = 'postgresql://adapter_user:adapter_pswd@adapter-tests-02:5432/adapter-db' + test_connection = {db_url: {"engine": "test_engne", "session": "test_session"}} + adapter = DatabaseAdapter() + adapter._connections_ = test_connection + assert adapter.get_connections() == test_connection + + +def test_get_session_that_exists(): + db_url = 'postgresql://adapter_user:adapter_pswd@adapter-tests-03:5432/adapter-db' + adapter = DatabaseAdapter() + adapter.add_connection(db_url) + assert adapter.get_connections().get(db_url) is not None + session_00 = adapter.get_session(db_url) + assert isinstance(session_00, Session) + + +def test_get_session_that_does_not_exists(): + db_url = 'postgresql://adapter_user:adapter_pswd@adapter-tests-04:5432/adapter-db' + adapter = DatabaseAdapter() + assert adapter.get_connections().get(db_url, None) is None + session_00 = adapter.get_session(db_url) + assert adapter.get_connections().get(db_url, None) is not None + assert isinstance(session_00, Session) diff --git a/tests/adapter/test_file.py b/tests/core/test_adapter_file.py similarity index 98% rename from tests/adapter/test_file.py rename to tests/core/test_adapter_file.py index 378c8df365..960f8b1958 100644 --- a/tests/adapter/test_file.py +++ b/tests/core/test_adapter_file.py @@ -26,7 +26,7 @@ def test_ls(): file_adapter = FileAdapter(base_path) dir_list = file_adapter.ls() assert isinstance(dir_list, list) - assert len(dir_list) == 10 + assert len(dir_list) == 12 file_found = False dir_found = False for entry in dir_list: From 940a093ee3ddf44b234281bfad88567c0f120853 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Wed, 29 Nov 2023 16:14:17 +0100 Subject: [PATCH 25/60] add tests for interlis_2_3_utils --- .../test_interlis_2_3_utils.py | 221 ++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 tests/contrib.data_sources.interlis_2_3/test_interlis_2_3_utils.py diff --git a/tests/contrib.data_sources.interlis_2_3/test_interlis_2_3_utils.py b/tests/contrib.data_sources.interlis_2_3/test_interlis_2_3_utils.py new file mode 100644 index 0000000000..82c37bf459 --- /dev/null +++ b/tests/contrib.data_sources.interlis_2_3/test_interlis_2_3_utils.py @@ -0,0 +1,221 @@ +import io +import pytest +from PIL import Image +from sqlalchemy import INTEGER, text, orm, create_engine +from sqlalchemy.schema import CreateSchema +from sqlalchemy.engine.url import URL + +from pyramid_oereb.contrib.data_sources.interlis_2_3.models.theme import model_factory +from pyramid_oereb.contrib.data_sources.interlis_2_3.interlis_2_3_utils \ + import from_multilingual_uri_to_dict, from_multilingual_blob_to_dict, from_multilingual_text_to_dict + + +@pytest.fixture(scope="session") +def png_binary_1(): + output = io.BytesIO() + Image.new("RGB", (72, 36), (0, 0, 0)).save(output, format='PNG') + yield output.getvalue() + + +@pytest.fixture(scope="session") +def png_binary_2(): + output = io.BytesIO() + Image.new("RGB", (72, 36), (128, 128, 128)).save(output, format='PNG') + yield output.getvalue() + + +@pytest.fixture(scope="session") +def png_binary_3(): + output = io.BytesIO() + Image.new("RGB", (72, 36), (255, 255, 255)).save(output, format='PNG') + yield output.getvalue() + + +@pytest.fixture(scope="session") +def interlis_utils_db_engine(base_engine): + # def test_db_engine(base_engine, test_db_name, config_path): + # """ + # create a new test DB called test_db_name and its engine + # """ + + test_interlis_db_name = "interlis_utils_test" + with base_engine.begin() as base_connection: + # terminate existing connections to be able to DROP the DB + term_stmt = 'SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity ' \ + f'WHERE pg_stat_activity.datname = \'{test_interlis_db_name}\' AND pid <> pg_backend_pid();' + base_connection.execute(text(term_stmt)) + # sqlalchemy uses transactions by default, COMMIT end the current transaction and allows + # creation and destruction of DB + base_connection.execute(text('COMMIT')) + base_connection.execute(text(f"DROP DATABASE if EXISTS {test_interlis_db_name}")) + base_connection.execute(text('COMMIT')) + base_connection.execute(text(f"CREATE DATABASE {test_interlis_db_name}")) + + test_db_url = URL.create( + base_engine.url.get_backend_name(), + base_engine.url.username, + base_engine.url.password, + base_engine.url.host, + base_engine.url.port, + database=test_interlis_db_name + ) + engine = create_engine(test_db_url) + with engine.begin() as connection: + connection.execute(text("CREATE EXTENSION POSTGIS")) + connection.execute(CreateSchema('interlis_utils_test', if_not_exists=True)) + return engine + + +@pytest.fixture(scope="session") +def test_data_session(interlis_utils_db_engine, png_binary_1, png_binary_2, png_binary_3): + session = orm.sessionmaker(bind=interlis_utils_db_engine)() + models = model_factory("interlis_utils_test", INTEGER, 2056, interlis_utils_db_engine.url) + models.Base.metadata.create_all(interlis_utils_db_engine) + + # Multilingual URI + session.add( + models.MultilingualUri( + t_id=1 + ) + ) + session.add( + models.MultilingualUri( + t_id=2 + ) + ) + + # Localised URI + session.add( + models.LocalisedUri( + t_id=3, + language="fr", + text="Exemple 1", + multilingualuri_id=1 + ) + ) + session.add( + models.LocalisedUri( + t_id=4, + language="de", + text="Beispiel 1", + multilingualuri_id=1, + ) + ) + session.add( + models.LocalisedUri( + t_id=5, + language="it", + text="Esempio 2", + multilingualuri_id=2 + ) + ) + + # Multilingual BLOB + session.add( + models.MultilingualBlob( + t_id=6 + ) + ) + session.add( + models.MultilingualBlob( + t_id=7 + ) + ) + + # Localised BLOB + session.add( + models.LocalisedBlob( + t_id=8, + language="de", + blob=png_binary_1, + multilingualblob_id=6 + ) + ) + session.add( + models.LocalisedBlob( + t_id=9, + language="fr", + blob=png_binary_2, + multilingualblob_id=6 + ) + ) + session.add( + models.LocalisedBlob( + t_id=10, + language="it", + blob=png_binary_3, + multilingualblob_id=7 + ) + ) + + session.commit() + yield session + + +def test_from_multilingual_uri_to_dict(interlis_utils_db_engine, test_data_session): + models = model_factory("interlis_utils_test", INTEGER, 2056, interlis_utils_db_engine.url) + session = test_data_session + result_1 = session.query(models.MultilingualUri).filter(models.MultilingualUri.t_id == 1) + result_2 = session.query(models.MultilingualUri).filter(models.MultilingualUri.t_id == 2) + + dict_1 = from_multilingual_uri_to_dict(result_1) + dict_2 = from_multilingual_uri_to_dict(result_2) + + dict_1_keys = list(dict_1.keys()) + dict_1_keys.sort() + dict_1 = {i: dict_1[i] for i in dict_1_keys} + + dict_2_keys = list(dict_2.keys()) + dict_2_keys.sort() + dict_2 = {i: dict_2[i] for i in dict_2_keys} + + assert dict_1 == {"de": "Beispiel 1", "fr": "Exemple 1"} + assert dict_2 == {"it": "Esempio 2"} + + +def test_from_multilingual_blob_to_dict(interlis_utils_db_engine, test_data_session, + png_binary_1, png_binary_2, png_binary_3): + models = model_factory("interlis_utils_test", INTEGER, 2056, interlis_utils_db_engine.url) + session = test_data_session + result_1 = session.query(models.MultilingualBlob).filter(models.MultilingualBlob.t_id == 6) + result_2 = session.query(models.MultilingualBlob).filter(models.MultilingualBlob.t_id == 7) + + dict_1 = from_multilingual_blob_to_dict(result_1) + dict_2 = from_multilingual_blob_to_dict(result_2) + + dict_1_keys = list(dict_1.keys()) + dict_1_keys.sort() + dict_1 = {i: dict_1[i] for i in dict_1_keys} + + dict_2_keys = list(dict_2.keys()) + dict_2_keys.sort() + dict_2 = {i: dict_2[i] for i in dict_2_keys} + + assert dict_1 == {"de": png_binary_1, "fr": png_binary_2} + assert dict_2 == {"it": png_binary_3} + + +def test_from_multilingual_text_to_dict(): + result_dict = from_multilingual_text_to_dict(de="Beispiel", fr="Exemple", it="Esempio", + rm="Exempel", en="Example") + assert result_dict == { + "de": "Beispiel", + "fr": "Exemple", + "it": "Esempio", + "rm": "Exempel", + "en": "Example" + } + + +def test_from_multilingual_text_to_dict_some_None(): + result_dict = from_multilingual_text_to_dict(de="Beispiel", it="Esempio", en="Example") + assert result_dict == { + "de": "Beispiel", + "it": "Esempio", + "en": "Example" + } + + +def test_from_multilingual_text_to_dict_all_None(): + result_dict = from_multilingual_text_to_dict(de=None, fr=None, it=None, rm=None, en=None) + assert result_dict is None From 4547e59faee1fbaf823a1e4ccd3b05298129bad4 Mon Sep 17 00:00:00 2001 From: Anne Maier Date: Thu, 30 Nov 2023 11:28:18 +0100 Subject: [PATCH 26/60] add mockups without DB --- .../test_interlis_2_3_utils.py | 191 +++++------------- 1 file changed, 54 insertions(+), 137 deletions(-) diff --git a/tests/contrib.data_sources.interlis_2_3/test_interlis_2_3_utils.py b/tests/contrib.data_sources.interlis_2_3/test_interlis_2_3_utils.py index 82c37bf459..b8a8ab075a 100644 --- a/tests/contrib.data_sources.interlis_2_3/test_interlis_2_3_utils.py +++ b/tests/contrib.data_sources.interlis_2_3/test_interlis_2_3_utils.py @@ -1,9 +1,7 @@ import io import pytest from PIL import Image -from sqlalchemy import INTEGER, text, orm, create_engine -from sqlalchemy.schema import CreateSchema -from sqlalchemy.engine.url import URL +from sqlalchemy import INTEGER from pyramid_oereb.contrib.data_sources.interlis_2_3.models.theme import model_factory from pyramid_oereb.contrib.data_sources.interlis_2_3.interlis_2_3_utils \ @@ -32,134 +30,58 @@ def png_binary_3(): @pytest.fixture(scope="session") -def interlis_utils_db_engine(base_engine): - # def test_db_engine(base_engine, test_db_name, config_path): - # """ - # create a new test DB called test_db_name and its engine - # """ - - test_interlis_db_name = "interlis_utils_test" - with base_engine.begin() as base_connection: - # terminate existing connections to be able to DROP the DB - term_stmt = 'SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity ' \ - f'WHERE pg_stat_activity.datname = \'{test_interlis_db_name}\' AND pid <> pg_backend_pid();' - base_connection.execute(text(term_stmt)) - # sqlalchemy uses transactions by default, COMMIT end the current transaction and allows - # creation and destruction of DB - base_connection.execute(text('COMMIT')) - base_connection.execute(text(f"DROP DATABASE if EXISTS {test_interlis_db_name}")) - base_connection.execute(text('COMMIT')) - base_connection.execute(text(f"CREATE DATABASE {test_interlis_db_name}")) - - test_db_url = URL.create( - base_engine.url.get_backend_name(), - base_engine.url.username, - base_engine.url.password, - base_engine.url.host, - base_engine.url.port, - database=test_interlis_db_name - ) - engine = create_engine(test_db_url) - with engine.begin() as connection: - connection.execute(text("CREATE EXTENSION POSTGIS")) - connection.execute(CreateSchema('interlis_utils_test', if_not_exists=True)) - return engine +def model_example1(): + models = model_factory("interlis_utils_test", INTEGER, 2056, "") + model = models + local_uri = models.LocalisedUri() + local_uri.language = "de" + local_uri.text = "Beispiel 1" + local_uri2 = models.LocalisedUri() + local_uri2.language = "fr" + local_uri2.text = "Exemple 1" + model.localised_uri = [local_uri, local_uri2] + yield [model] @pytest.fixture(scope="session") -def test_data_session(interlis_utils_db_engine, png_binary_1, png_binary_2, png_binary_3): - session = orm.sessionmaker(bind=interlis_utils_db_engine)() - models = model_factory("interlis_utils_test", INTEGER, 2056, interlis_utils_db_engine.url) - models.Base.metadata.create_all(interlis_utils_db_engine) - - # Multilingual URI - session.add( - models.MultilingualUri( - t_id=1 - ) - ) - session.add( - models.MultilingualUri( - t_id=2 - ) - ) - - # Localised URI - session.add( - models.LocalisedUri( - t_id=3, - language="fr", - text="Exemple 1", - multilingualuri_id=1 - ) - ) - session.add( - models.LocalisedUri( - t_id=4, - language="de", - text="Beispiel 1", - multilingualuri_id=1, - ) - ) - session.add( - models.LocalisedUri( - t_id=5, - language="it", - text="Esempio 2", - multilingualuri_id=2 - ) - ) - - # Multilingual BLOB - session.add( - models.MultilingualBlob( - t_id=6 - ) - ) - session.add( - models.MultilingualBlob( - t_id=7 - ) - ) - - # Localised BLOB - session.add( - models.LocalisedBlob( - t_id=8, - language="de", - blob=png_binary_1, - multilingualblob_id=6 - ) - ) - session.add( - models.LocalisedBlob( - t_id=9, - language="fr", - blob=png_binary_2, - multilingualblob_id=6 - ) - ) - session.add( - models.LocalisedBlob( - t_id=10, - language="it", - blob=png_binary_3, - multilingualblob_id=7 - ) - ) - - session.commit() - yield session - - -def test_from_multilingual_uri_to_dict(interlis_utils_db_engine, test_data_session): - models = model_factory("interlis_utils_test", INTEGER, 2056, interlis_utils_db_engine.url) - session = test_data_session - result_1 = session.query(models.MultilingualUri).filter(models.MultilingualUri.t_id == 1) - result_2 = session.query(models.MultilingualUri).filter(models.MultilingualUri.t_id == 2) - - dict_1 = from_multilingual_uri_to_dict(result_1) - dict_2 = from_multilingual_uri_to_dict(result_2) +def model_example2(): + models = model_factory("interlis_utils_test", INTEGER, 2056, "") + model = models + local_uri = models.LocalisedUri() + local_uri.language = "it" + local_uri.text = "Esempio 2" + model.localised_uri = [local_uri] + yield [model] + + +@pytest.fixture(scope="session") +def model_example_blob(png_binary_1, png_binary_2): + models = model_factory("interlis_utils_test", INTEGER, 2056, "") + model = models + local_uri = models.LocalisedUri() + local_uri.language = "de" + local_uri.blob = png_binary_1 + local_uri2 = models.LocalisedUri() + local_uri2.language = "fr" + local_uri2.blob = png_binary_2 + model.localised_blob = [local_uri, local_uri2] + yield [model] + + +@pytest.fixture(scope="session") +def model_example_blob2(png_binary_3): + models = model_factory("interlis_utils_test", INTEGER, 2056, "") + model = models + local_uri = models.LocalisedUri() + local_uri.language = "it" + local_uri.blob = png_binary_3 + model.localised_blob = [local_uri] + yield [model] + + +def test_from_multilingual_uri_to_dict(model_example1, model_example2): + dict_1 = from_multilingual_uri_to_dict(model_example1) + dict_2 = from_multilingual_uri_to_dict(model_example2) dict_1_keys = list(dict_1.keys()) dict_1_keys.sort() @@ -173,15 +95,10 @@ def test_from_multilingual_uri_to_dict(interlis_utils_db_engine, test_data_sessi assert dict_2 == {"it": "Esempio 2"} -def test_from_multilingual_blob_to_dict(interlis_utils_db_engine, test_data_session, - png_binary_1, png_binary_2, png_binary_3): - models = model_factory("interlis_utils_test", INTEGER, 2056, interlis_utils_db_engine.url) - session = test_data_session - result_1 = session.query(models.MultilingualBlob).filter(models.MultilingualBlob.t_id == 6) - result_2 = session.query(models.MultilingualBlob).filter(models.MultilingualBlob.t_id == 7) - - dict_1 = from_multilingual_blob_to_dict(result_1) - dict_2 = from_multilingual_blob_to_dict(result_2) +def test_from_multilingual_blob_to_dict(png_binary_1, png_binary_2, png_binary_3, + model_example_blob, model_example_blob2): + dict_1 = from_multilingual_blob_to_dict(model_example_blob) + dict_2 = from_multilingual_blob_to_dict(model_example_blob2) dict_1_keys = list(dict_1.keys()) dict_1_keys.sort() From 1d1f40eeea9252605cc5d442e6aa8b5c610db9c7 Mon Sep 17 00:00:00 2001 From: Anne Maier Date: Fri, 1 Dec 2023 11:25:00 +0100 Subject: [PATCH 27/60] test_get_law_status_lookup_by_theme_code_key_code --- pyramid_oereb/core/config.py | 5 +++++ tests/core/test_config.py | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/pyramid_oereb/core/config.py b/pyramid_oereb/core/config.py index 849f80f294..925c1483a4 100644 --- a/pyramid_oereb/core/config.py +++ b/pyramid_oereb/core/config.py @@ -1666,6 +1666,11 @@ def get_law_status_lookup_by_theme_code_key_code(theme_code, key, code): """ lookups = Config.get_law_status_lookups(theme_code) + if lookups is None: + raise ConfigurationError( + 'Law status lookup for theme {} is not ' + 'defined in configuration!'.format(theme_code) + ) for lookup in lookups: if lookup[key] == code: return lookup diff --git a/tests/core/test_config.py b/tests/core/test_config.py index e457c9f188..aec1176d40 100644 --- a/tests/core/test_config.py +++ b/tests/core/test_config.py @@ -1114,3 +1114,27 @@ def test_availability_by_theme_code_municipality_fosnr_config_none(): Config.availabilities = None with pytest.raises(ConfigurationError): Config.availability_by_theme_code_municipality_fosnr('BN', 2771) + + +@pytest.mark.run(order=1) +def test_get_law_status_lookup_by_theme_code_key_code(test_value, expected_value, law_status_lookups): + with patch.object(Config, 'get_law_status_lookups', return_value=law_status_lookups): + assert Config.get_law_status_lookup_by_theme_code_key_code( + test_value.get("theme_code"), + test_value.get("key"), + test_value.get("code")).get("extract_code") == expected_value + + +@pytest.mark.parametrize('test_value', [ + ({}), + ([]), + (None) +]) +@pytest.mark.run(order=1) +def test_get_law_status_lookup_by_theme_code_key_code_no_key(test_value): + with patch.object(Config, 'get_law_status_lookups', return_value=test_value): + with pytest.raises(ConfigurationError): + Config.get_law_status_lookup_by_theme_code_key_code( + "ch.Nutzungsplanung", + "data_code", + "inKraft") From ee2f9b9e62abb53b317a7f97a7aeda21818c663c Mon Sep 17 00:00:00 2001 From: Anne Maier Date: Thu, 30 Nov 2023 14:27:06 +0100 Subject: [PATCH 28/60] test_get_config --- tests/core/test_config.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/core/test_config.py b/tests/core/test_config.py index 1c947950c9..e52b8c66c3 100644 --- a/tests/core/test_config.py +++ b/tests/core/test_config.py @@ -1156,3 +1156,11 @@ def test_get_law_status_lookup_by_theme_code_key_code_no_key(test_value): "ch.Nutzungsplanung", "data_code", "inKraft") +@pytest.mark.run(order=1) +def test_get_config(): + Config._config = None + assert Config.get_config() == None + Config._config = {} + assert Config.get_config() == {} + # set config back to None. + Config._config = None From daa93c853ef8d1cdc3d264c3668ee962cafba1af Mon Sep 17 00:00:00 2001 From: Anne Maier Date: Fri, 1 Dec 2023 07:46:55 +0100 Subject: [PATCH 29/60] add simple tests for get_config functions --- tests/core/test_config.py | 191 +++++++++++++++++++++++++++++++++++++- 1 file changed, 189 insertions(+), 2 deletions(-) diff --git a/tests/core/test_config.py b/tests/core/test_config.py index e52b8c66c3..b36ba70e4e 100644 --- a/tests/core/test_config.py +++ b/tests/core/test_config.py @@ -398,7 +398,7 @@ def test_get_glossary_config(test_value, expected_results): @pytest.mark.run(order=-1) -def test_get_document_config_none(): +def test_get_glossary_config_none(): Config._config = None with pytest.raises(AssertionError): Config.get_glossary_config() @@ -1159,8 +1159,195 @@ def test_get_law_status_lookup_by_theme_code_key_code_no_key(test_value): @pytest.mark.run(order=1) def test_get_config(): Config._config = None - assert Config.get_config() == None + assert Config.get_config() is None Config._config = {} assert Config.get_config() == {} # set config back to None. Config._config = None + + +@pytest.mark.parametrize('test_value,expected_value', [ + ({'real_estate': {'plan_for_land_register_main_page': {}}}, {}), + ({'not_expecting_key': {}}, None) +]) +@pytest.mark.run(order=-1) +def test_get_plan_for_land_register_main_page_config(test_value, expected_value): + Config._config = test_value + assert Config.get_plan_for_land_register_main_page_config() == expected_value + + +@pytest.mark.run(order=-1) +def test_get_plan_for_land_register_main_page_config_none(): + Config._config = None + with pytest.raises(AssertionError): + Config.get_plan_for_land_register_main_page_config() + + +@pytest.mark.parametrize('test_value,expected_value', [ + ({'real_estate': {'plan_for_land_register': {}}}, {}), + ({'not_expecting_key': {}}, None) +]) +@pytest.mark.run(order=-1) +def test_get_plan_for_land_register_config(test_value, expected_value): + Config._config = test_value + assert Config.get_plan_for_land_register_config() == expected_value + + +@pytest.mark.run(order=-1) +def test_get_plan_for_land_register_config_none(): + Config._config = None + with pytest.raises(AssertionError): + Config.get_plan_for_land_register_config() + + +@pytest.mark.parametrize('test_value,expected_value', [ + ({'address': {}}, {}), + ({'not_expecting_key': {}}, None) +]) +@pytest.mark.run(order=-1) +def test_get_address_config(test_value, expected_value): + Config._config = test_value + assert Config.get_address_config() == expected_value + + +@pytest.mark.run(order=-1) +def test_get_address_config_none(): + Config._config = None + with pytest.raises(AssertionError): + Config.get_address_config() + + +@pytest.mark.parametrize('test_value,expected_value', [ + ({'theme_document': {}}, {}), + ({'not_expecting_key': {}}, None) +]) +@pytest.mark.run(order=-1) +def test_get_theme_document_config(test_value, expected_value): + Config._config = test_value + assert Config.get_theme_document_config() == expected_value + + +@pytest.mark.run(order=-1) +def test_get_theme_document_config_none(): + Config._config = None + with pytest.raises(AssertionError): + Config.get_theme_document_config() + + +@pytest.mark.parametrize('test_value,expected_value', [ + ({'document_types': {}}, {}), + ({'not_expecting_key': {}}, None) +]) +@pytest.mark.run(order=-1) +def test_get_document_types_config(test_value, expected_value): + Config._config = test_value + assert Config.get_document_types_config() == expected_value + + +@pytest.mark.run(order=-1) +def test_get_document_types_config_none(): + Config._config = None + with pytest.raises(AssertionError): + Config.get_document_types_config() + + +@pytest.mark.parametrize('test_value,expected_value', [ + ({'disclaimer': {}}, {}), + ({'not_expecting_key': {}}, None) +]) +@pytest.mark.run(order=-1) +def test_get_disclaimer_config(test_value, expected_value): + Config._config = test_value + assert Config.get_disclaimer_config() == expected_value + + +@pytest.mark.run(order=-1) +def test_get_disclaimer_config_none(): + Config._config = None + with pytest.raises(AssertionError): + Config.get_disclaimer_config() + + +@pytest.mark.parametrize('test_value,expected_value', [ + ({'general_information': {}}, {}), + ({'not_expecting_key': {}}, None) +]) +@pytest.mark.run(order=-1) +def test_get_info_config(test_value, expected_value): + Config._config = test_value + assert Config.get_info_config() == expected_value + + +@pytest.mark.run(order=-1) +def test_get_info_config_none(): + Config._config = None + with pytest.raises(AssertionError): + Config.get_info_config() + + +@pytest.mark.parametrize('test_value,expected_value', [ + ({'documents': {}}, {}), + ({'not_expecting_key': {}}, None) +]) +@pytest.mark.run(order=-1) +def test_get_document_config(test_value, expected_value): + Config._config = test_value + assert Config.get_document_config() == expected_value + + +@pytest.mark.run(order=-1) +def test_get_document_config_none(): + Config._config = None + with pytest.raises(AssertionError): + Config.get_document_config() + + +@pytest.mark.parametrize('test_value,expected_value', [ + ({'offices': {}}, {}), + ({'not_expecting_key': {}}, None) +]) +@pytest.mark.run(order=-1) +def test_get_office_config(test_value, expected_value): + Config._config = test_value + assert Config.get_office_config() == expected_value + + +@pytest.mark.run(order=-1) +def test_get_office_config_none(): + Config._config = None + with pytest.raises(AssertionError): + Config.get_office_config() + + +@pytest.mark.parametrize('test_value,expected_value', [ + ({'municipality': {}}, {}), + ({'not_expecting_key': {}}, None) +]) +@pytest.mark.run(order=-1) +def test_get_municipality_config(test_value, expected_value): + Config._config = test_value + assert Config.get_municipality_config() == expected_value + + +@pytest.mark.run(order=-1) +def test_get_municipality_config_none(): + Config._config = None + with pytest.raises(AssertionError): + Config.get_municipality_config() + + +@pytest.mark.parametrize('test_value,expected_value', [ + ({'availability': {}}, {}), + ({'not_expecting_key': {}}, None) +]) +@pytest.mark.run(order=-1) +def test_get_availability_config(test_value, expected_value): + Config._config = test_value + assert Config.get_availability_config() == expected_value + + +@pytest.mark.run(order=-1) +def test_get_availability_config_none(): + Config._config = None + with pytest.raises(AssertionError): + Config.get_availability_config() From 1f7fb1c354eb0217313b910a63328162b4459bc6 Mon Sep 17 00:00:00 2001 From: Anne Maier Date: Fri, 1 Dec 2023 15:46:10 +0100 Subject: [PATCH 30/60] linting --- tests/core/test_config.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/core/test_config.py b/tests/core/test_config.py index b36ba70e4e..19499fcc82 100644 --- a/tests/core/test_config.py +++ b/tests/core/test_config.py @@ -1156,6 +1156,8 @@ def test_get_law_status_lookup_by_theme_code_key_code_no_key(test_value): "ch.Nutzungsplanung", "data_code", "inKraft") + + @pytest.mark.run(order=1) def test_get_config(): Config._config = None From df70afbf5ecb6ffb45df2aaf6dbdc73103b2e9a3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 07:46:37 +0100 Subject: [PATCH 31/60] Update dependency pypdf to v3.17.2 (#1906) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 26d00547f8..749a306108 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -pypdf==3.17.1 +pypdf==3.17.2 filetype==1.2.0 geoalchemy2==0.14.2 pyramid==2.0.2 From f61ccf394cb8ccead3f8c802e73ffc9f00b8c284 Mon Sep 17 00:00:00 2001 From: Anne Maier Date: Fri, 1 Dec 2023 10:12:24 +0100 Subject: [PATCH 32/60] test_municipality_by_fosnr --- pyramid_oereb/core/config.py | 2 ++ tests/core/test_config.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/pyramid_oereb/core/config.py b/pyramid_oereb/core/config.py index 925c1483a4..22b8da703d 100644 --- a/pyramid_oereb/core/config.py +++ b/pyramid_oereb/core/config.py @@ -2092,6 +2092,8 @@ def municipality_by_fosnr(fosnr): ConfigurationError: If no match was found """ + if Config.municipalities is None: + raise ConfigurationError("The municipalities have not been initialized") for municipality in Config.municipalities: if municipality.fosnr == fosnr: return municipality diff --git a/tests/core/test_config.py b/tests/core/test_config.py index 19499fcc82..37adae6889 100644 --- a/tests/core/test_config.py +++ b/tests/core/test_config.py @@ -24,6 +24,7 @@ from pyramid_oereb.core.readers.real_estate_type import RealEstateTypeReader from pyramid_oereb.core.readers.map_layering import MapLayeringReader from pyramid_oereb.core.records.availability import AvailabilityRecord +from pyramid_oereb.core.records.municipality import MunicipalityRecord # order=-1 to run them after all and don't screw the configuration in Config @@ -1353,3 +1354,30 @@ def test_get_availability_config_none(): Config._config = None with pytest.raises(AssertionError): Config.get_availability_config() +def municipality_records(): + yield [MunicipalityRecord(2771, 'Gemeinde', True), + MunicipalityRecord(2772, 'Gemeinde2', False)] + + +@pytest.mark.parametrize('test_value,expected_index', [ + (2771, 0), + (2772, 1) +]) +@pytest.mark.run(order=1) +def test_municipality_by_fosnr(test_value, expected_index, municipality_records): + Config.municipalities = municipality_records + assert Config.municipality_by_fosnr(test_value) == municipality_records[expected_index] + + +@pytest.mark.run(order=1) +def test_municipality_by_fosnr_config_none(): + Config.municipalities = None + with pytest.raises(ConfigurationError): + Config.municipality_by_fosnr(0) + + +@pytest.mark.run(order=1) +def test_municipality_by_fosnr_not_in_list(municipality_records): + Config.municipalities = municipality_records + with pytest.raises(ConfigurationError): + Config.municipality_by_fosnr(0) From b857feec11f53d1b4e688107311ad3bbd7f87a45 Mon Sep 17 00:00:00 2001 From: Anne Maier Date: Thu, 14 Dec 2023 12:55:46 +0100 Subject: [PATCH 33/60] linting --- tests/core/test_config.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/core/test_config.py b/tests/core/test_config.py index 794cc67d3a..95b7edbfe3 100644 --- a/tests/core/test_config.py +++ b/tests/core/test_config.py @@ -1355,6 +1355,7 @@ def test_get_availability_config_none(): with pytest.raises(AssertionError): Config.get_availability_config() + @pytest.fixture() def municipality_records(): yield [MunicipalityRecord(2771, 'Gemeinde', True), From d23a46be95540c16431f9bee2ae0dcda27b0973e Mon Sep 17 00:00:00 2001 From: Anne Maier Date: Fri, 1 Dec 2023 10:27:11 +0100 Subject: [PATCH 34/60] test_get_law_status_lookups --- tests/core/test_config.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/core/test_config.py b/tests/core/test_config.py index 95b7edbfe3..8ce266742b 100644 --- a/tests/core/test_config.py +++ b/tests/core/test_config.py @@ -1384,3 +1384,20 @@ def test_municipality_by_fosnr_not_in_list(municipality_records): Config.municipalities = municipality_records with pytest.raises(ConfigurationError): Config.municipality_by_fosnr(0) +@pytest.mark.parametrize('test_value,expected_value', [ + ({"law_status_lookup": {}}, {}), + ({"law_status_lookup": ""}, "") +]) +@pytest.mark.run(order=1) +def test_get_law_status_lookups(test_value, expected_value): + Config._config = None + with patch.object(Config, 'get_theme_config_by_code', return_value=test_value): + assert Config.get_law_status_lookups('theme_code') == expected_value + + +@pytest.mark.run(order=1) +def test_get_law_status_lookups_lookups_none(): + Config._config = None + with patch.object(Config, 'get_theme_config_by_code', return_value={"law_status_lookup": None}): + with pytest.raises(ConfigurationError): + Config.get_law_status_lookups('theme_code') From 178e8bb54db55e64523709d586e4f6a9e87da4fb Mon Sep 17 00:00:00 2001 From: Anne Maier Date: Fri, 1 Dec 2023 11:37:45 +0100 Subject: [PATCH 35/60] test_get_law_status_lookup_by_data_code --- tests/core/test_config.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/core/test_config.py b/tests/core/test_config.py index f07ccf7157..4b857a85fb 100644 --- a/tests/core/test_config.py +++ b/tests/core/test_config.py @@ -1403,3 +1403,19 @@ def test_get_law_status_lookups_lookups_none(): with patch.object(Config, 'get_theme_config_by_code', return_value={"law_status_lookup": None}): with pytest.raises(ConfigurationError): Config.get_law_status_lookups('theme_code') + + +@pytest.mark.parametrize('test_value', [ + ({"data_code": "inKraft", + "transfer_code": "inKraft", + "extract_code": "inForce"}), + ({"data_code": "AenderungMitVorwirkung", + "transfer_code": "AenderungMitVorwirkung", + "extract_code": "changeWithPreEffect"}) +]) +@pytest.mark.run(order=1) +def test_get_law_status_lookup_by_data_code(test_value): + with patch.object(Config, 'get_law_status_lookup_by_theme_code_key_code', return_value=test_value): + assert Config.get_law_status_lookup_by_data_code( + "theme_code", + "data_code") == test_value From 75b1e6753ff3a32a2e3c0ed48632ab8d43b5d7f7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 18 Dec 2023 07:27:31 +0100 Subject: [PATCH 36/60] Update dependency pypdf to v3.17.3 (#1907) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 749a306108..8d9bfd4f4b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -pypdf==3.17.2 +pypdf==3.17.3 filetype==1.2.0 geoalchemy2==0.14.2 pyramid==2.0.2 From 3e1c50a21153d8d7e523486f88d8da1d145b050e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 20 Dec 2023 07:07:33 +0100 Subject: [PATCH 37/60] Update dependency lxml to v4.9.4 (#1908) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- tests-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests-requirements.txt b/tests-requirements.txt index 94457834c5..3e6883862d 100644 --- a/tests-requirements.txt +++ b/tests-requirements.txt @@ -1,5 +1,5 @@ jsonschema==4.20.0 -lxml==4.9.3 +lxml==4.9.4 pytest==7.4.3 pytest-cov==4.1.0 pytest-ordering==0.6 From dd72a0176117501913903abdbd0730c004113263 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 26 Dec 2023 05:57:28 +0100 Subject: [PATCH 38/60] Update dependency geoalchemy2 to v0.14.3 (#1909) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 8d9bfd4f4b..6611b192ee 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ pypdf==3.17.3 filetype==1.2.0 -geoalchemy2==0.14.2 +geoalchemy2==0.14.3 pyramid==2.0.2 pyramid-debugtoolbar==4.10 qrcode==7.4.2 From 6de8c2c22442bbe62a70c41d83184f1947938733 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 26 Dec 2023 05:57:49 +0100 Subject: [PATCH 39/60] Update dependency pypdf to v3.17.4 (#1910) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 6611b192ee..078f15b9f6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -pypdf==3.17.3 +pypdf==3.17.4 filetype==1.2.0 geoalchemy2==0.14.3 pyramid==2.0.2 From 9751487e78b94f36d3170478a5f7802975c8cd5d Mon Sep 17 00:00:00 2001 From: Wolfgang Kaltz Date: Tue, 26 Dec 2023 09:17:20 +0100 Subject: [PATCH 40/60] New release --- CHANGES.rst | 10 +++++++--- doc/source/changes.rst | 10 ++++++++++ setup.py | 2 +- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index abbcbb69ed..80e5efc23a 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,9 +1,13 @@ Changelog ========= -master ------- -- Remove print proxy "xml2pdf" (#1889) +2.4.7 +----- +- Interlis bug fix (#1881) +- Library upgrades (geoalchemy2, SQLAlchemy, jsonschema, lxml, responses, urllib3, pypdf) +- Test coverage improvements +- Python 3.8 is no longer explicitly supported +- Remove print proxy xml2pdf, no longer used by the community (#1889) 2.4.6 ----- diff --git a/doc/source/changes.rst b/doc/source/changes.rst index a9983d4cff..575acd9db4 100644 --- a/doc/source/changes.rst +++ b/doc/source/changes.rst @@ -6,6 +6,16 @@ Changes/Hints for migration This chapter will give you hints on how to handle version migration, in particular regarding what you may need to adapt in your project configuration, database etc. when upgrading to a new version. +Version 2.4.7 +------------- +Bug-fix and maintenance release: + +* Interlis bug fix (#1881) +* Library upgrades (geoalchemy2, SQLAlchemy, jsonschema, lxml, responses, urllib3, pypdf) +* Test coverage improvements +* Python 3.8 is no longer explicitly supported +* Remove print proxy xml2pdf, no longer used by the community (#1889) + Version 2.4.6 ------------- Bug-fix and maintenance release: diff --git a/setup.py b/setup.py index c9d7c4c135..2951a14105 100644 --- a/setup.py +++ b/setup.py @@ -20,7 +20,7 @@ setup( name='pyramid_oereb', - version='2.4.6', + version='2.4.7', description='pyramid_oereb, extension for pyramid web frame work to provide ' 'a basic server part for the oereb project', long_description='{readme}\n\n{changes}'.format(readme=README, changes=CHANGES), From 0e166c3dd738b213355ebb1bbc8bd6143996c763 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 26 Dec 2023 09:46:58 +0100 Subject: [PATCH 41/60] Update dependency c2cwsgiutils to v6 (#1827) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 078f15b9f6..9aeecd2b14 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,4 +15,4 @@ mako-render==0.1.0 requests==2.31.0 geolink-formatter==2.0.4 pyconizer==0.1.4 -c2cwsgiutils[standard]==5.2.3 +c2cwsgiutils[standard]==6.0.6 From 84c861b4ebcc308ac84c47b39cab19e1da2fe284 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 28 Dec 2023 06:21:59 +0100 Subject: [PATCH 42/60] Update actions/setup-python action to v5 (#1905) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/ci.yaml | 4 ++-- .github/workflows/daily_check.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 9185541790..5268fcb924 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -53,7 +53,7 @@ jobs: steps: - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4 - name: Set up Python v${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} architecture: x64 @@ -114,7 +114,7 @@ jobs: steps: - uses: actions/checkout@master - name: Set up Python 3.11 - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.11 - name: Install pypa/build diff --git a/.github/workflows/daily_check.yaml b/.github/workflows/daily_check.yaml index b253efe889..9dbabf03fd 100644 --- a/.github/workflows/daily_check.yaml +++ b/.github/workflows/daily_check.yaml @@ -55,7 +55,7 @@ jobs: PYTHON_TEST_VERSION: ${{ matrix.python-version }} run: make tests - name: Set up Python 3.11 - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.11 - name: Install pypa/build From d3891a91a2ab21d69b96c055770cdb03393cc4dc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 28 Dec 2023 06:32:53 +0100 Subject: [PATCH 43/60] Update JamesIves/github-pages-deploy-action action to v4.5.0 (#1867) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 5268fcb924..15fddc0642 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -102,7 +102,7 @@ jobs: sudo apt-get install libpq-dev make doc-html - name: Deploy 🚀 - uses: JamesIves/github-pages-deploy-action@v4.4.3 + uses: JamesIves/github-pages-deploy-action@v4.5.0 with: branch: gh-pages # The branch the action should deploy to. folder: doc/build/html # The folder the action should deploy. From 19ab8de55d722d0d1aca4a8c3e7ec71ed8004924 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 28 Dec 2023 06:47:44 +0100 Subject: [PATCH 44/60] Update actions/checkout digest to b4ffde6 (#1848) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/ci.yaml | 10 +++++----- .github/workflows/daily_check.yaml | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 15fddc0642..008d975a69 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -7,7 +7,7 @@ jobs: name: Check style (lint) runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 - run: sudo rm /etc/apt/sources.list.d/*.list - run: sudo apt update - run: sudo apt-get install libpq-dev @@ -18,7 +18,7 @@ jobs: name: Check style (git-attributes) runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 - run: sudo rm /etc/apt/sources.list.d/*.list - run: sudo apt update - run: sudo apt-get install libpq-dev @@ -51,7 +51,7 @@ jobs: - '3.10' - '3.11' steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 - name: Set up Python v${{ matrix.python-version }} uses: actions/setup-python@v5 with: @@ -77,7 +77,7 @@ jobs: name: Check federal data definitions runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 - run: sudo rm /etc/apt/sources.list.d/*.list - run: sudo apt update - run: sudo apt-get install xsltproc @@ -94,7 +94,7 @@ jobs: if: github.ref == 'refs/heads/master' runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 - name: Make documentation run: | sudo rm /etc/apt/sources.list.d/*.list diff --git a/.github/workflows/daily_check.yaml b/.github/workflows/daily_check.yaml index 9dbabf03fd..991de87987 100644 --- a/.github/workflows/daily_check.yaml +++ b/.github/workflows/daily_check.yaml @@ -8,7 +8,7 @@ jobs: name: Check federal data definitions runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 - run: sudo rm /etc/apt/sources.list.d/*.list - run: sudo apt update - run: sudo apt-get install xsltproc @@ -46,7 +46,7 @@ jobs: - python3.10 - python3.11 steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 - run: sudo rm /etc/apt/sources.list.d/*.list - run: sudo apt update - run: sudo apt-get install libpq-dev From 53a8f8371d7d99e5c363830fe406a6a83d33b091 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 29 Dec 2023 07:31:47 +0100 Subject: [PATCH 45/60] Update dependency SQLAlchemy to v2.0.24 (#1916) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 9aeecd2b14..b6f35fc11b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ pyramid-debugtoolbar==4.10 qrcode==7.4.2 image==1.5.33 shapely==2.0.2 -SQLAlchemy==2.0.23 +SQLAlchemy==2.0.24 pyaml-env==1.2.1 urllib3==2.1.0 waitress==2.1.2 From c604bb6cbf49a93d9bb94d4b75935ae428b03288 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Fri, 5 Jan 2024 12:11:48 +0100 Subject: [PATCH 46/60] move adapter tests to separate folder / extend tests --- .coveragerc.core_adapter | 3 +++ .gitignore | 1 + Makefile | 6 +++++- tests/{core => core_adapter}/test_adapter_database.py | 6 +++++- tests/{core => core_adapter}/test_adapter_file.py | 0 5 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 .coveragerc.core_adapter rename tests/{core => core_adapter}/test_adapter_database.py (88%) rename tests/{core => core_adapter}/test_adapter_file.py (100%) diff --git a/.coveragerc.core_adapter b/.coveragerc.core_adapter new file mode 100644 index 0000000000..49ee4ae2f0 --- /dev/null +++ b/.coveragerc.core_adapter @@ -0,0 +1,3 @@ +[run] +source = + pyramid_oereb/core/adapter.py diff --git a/.gitignore b/.gitignore index 803fb3fec7..5528c6d517 100644 --- a/.gitignore +++ b/.gitignore @@ -84,5 +84,6 @@ DataExtract.json /coverage.contrib-print_proxy-mapfish_print.xml /coverage.contrib-data_sources-swisstopo.xml /coverage.core.xml +/coverage.core_adapter.xml /coverage.contrib-stats.xml /coverage.xml diff --git a/Makefile b/Makefile index 8ce74694b0..a59a7c558b 100644 --- a/Makefile +++ b/Makefile @@ -305,6 +305,10 @@ test-postgis: test-core: ${VENV_ROOT}/requirements-timestamp $(VENV_BIN)/py.test -vv $(PYTEST_OPTS) --cov-config .coveragerc.core --cov $(PACKAGE)/core --cov-report=term-missing --cov-report=xml:coverage.core.xml tests/core +.PHONY: test-core_adapter +test-core_adapter: ${VENV_ROOT}/requirements-timestamp + $(VENV_BIN)/py.test -vv $(PYTEST_OPTS) --cov-config .coveragerc.core_adapter --cov $(PACKAGE)/core --cov-report=term-missing --cov-report=xml:coverage.core_adapter.xml tests/core_adapter + .PHONY: test-contrib-print_proxy-mapfish_print test-contrib-print_proxy-mapfish_print: ${VENV_ROOT}/requirements-timestamp $(VENV_BIN)/py.test -vv $(PYTEST_OPTS) --cov-config .coveragerc.contrib-print_proxy-mapfish_print --cov $(PACKAGE) --cov-report xml:coverage.contrib-print_proxy-mapfish_print.xml tests/contrib.print_proxy.mapfish_print @@ -327,7 +331,7 @@ test-contrib-stats: ${VENV_ROOT}/requirements-timestamp $(VENV_BIN)/py.test -vv $(PYTEST_OPTS) --cov-config .coveragerc.contrib-stats --cov $(PACKAGE)/contrib/stats --cov-report=xml:coverage.contrib-stats.xml tests/contrib.stats .PHONY: tests -tests: ${VENV_ROOT}/requirements-timestamp test-core test-contrib-print_proxy-mapfish_print test-contrib-data_sources-standard test-contrib-data_sources-interlis test-contrib-stats test-contrib-data_sources-swisstopo +tests: ${VENV_ROOT}/requirements-timestamp test-core test-core_adapter test-contrib-print_proxy-mapfish_print test-contrib-data_sources-standard test-contrib-data_sources-interlis test-contrib-stats test-contrib-data_sources-swisstopo .PHONY: docker-tests docker-tests: diff --git a/tests/core/test_adapter_database.py b/tests/core_adapter/test_adapter_database.py similarity index 88% rename from tests/core/test_adapter_database.py rename to tests/core_adapter/test_adapter_database.py index 68ddad75f3..5914240883 100644 --- a/tests/core/test_adapter_database.py +++ b/tests/core_adapter/test_adapter_database.py @@ -9,7 +9,7 @@ def test_init(): assert isinstance(adapter._connections_, dict) -def test_get_connections(): +def test_get_connections_instance(): adapter = DatabaseAdapter() assert isinstance(adapter.get_connections(), dict) @@ -43,15 +43,19 @@ def test_get_session_that_exists(): db_url = 'postgresql://adapter_user:adapter_pswd@adapter-tests-03:5432/adapter-db' adapter = DatabaseAdapter() adapter.add_connection(db_url) + n_connections = len(adapter.get_connections()) assert adapter.get_connections().get(db_url) is not None session_00 = adapter.get_session(db_url) assert isinstance(session_00, Session) + assert len(adapter.get_connections()) == n_connections def test_get_session_that_does_not_exists(): db_url = 'postgresql://adapter_user:adapter_pswd@adapter-tests-04:5432/adapter-db' adapter = DatabaseAdapter() + n_connections = len(adapter.get_connections()) assert adapter.get_connections().get(db_url, None) is None session_00 = adapter.get_session(db_url) assert adapter.get_connections().get(db_url, None) is not None assert isinstance(session_00, Session) + assert len(adapter.get_connections()) == (n_connections + 1) diff --git a/tests/core/test_adapter_file.py b/tests/core_adapter/test_adapter_file.py similarity index 100% rename from tests/core/test_adapter_file.py rename to tests/core_adapter/test_adapter_file.py From 9283d6c638354e4b57b9bbae6367466057c83631 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 8 Jan 2024 07:57:16 +0100 Subject: [PATCH 47/60] Update dependency pytest to v7.4.4 (#1918) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- tests-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests-requirements.txt b/tests-requirements.txt index 3e6883862d..db8acf8bd9 100644 --- a/tests-requirements.txt +++ b/tests-requirements.txt @@ -1,6 +1,6 @@ jsonschema==4.20.0 lxml==4.9.4 -pytest==7.4.3 +pytest==7.4.4 pytest-cov==4.1.0 pytest-ordering==0.6 requests-mock==1.11.0 From aad11b58824c97a69a97c2a6ce03f75ecbc22f3d Mon Sep 17 00:00:00 2001 From: Wolfgang Kaltz Date: Mon, 8 Jan 2024 08:03:24 +0100 Subject: [PATCH 48/60] Clarify create_tables script (#1914) --- .../data_sources/standard/create_tables.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/pyramid_oereb/contrib/data_sources/standard/create_tables.py b/pyramid_oereb/contrib/data_sources/standard/create_tables.py index ff92c61456..662bc72764 100644 --- a/pyramid_oereb/contrib/data_sources/standard/create_tables.py +++ b/pyramid_oereb/contrib/data_sources/standard/create_tables.py @@ -60,23 +60,17 @@ def create_standard_tables(): options, args = parser.parse_args() if not options.configuration: parser.error('No configuration file set.') + if not options.sql_file: + parser.error('No sql filename specified.') config_source = 'pyramid_oereb.contrib.data_sources.standard.sources.plr.DatabaseSource' - if options.sql_file is None: + + append_to_sql = 'w' if options.append_to_sql else 'a' + with open(options.sql_file, append_to_sql) as sql_file: create_tables_from_standard_configuration( configuration_yaml_path=options.configuration, source_class=config_source, section=options.section, c2ctemplate_style=options.c2ctemplate_style, - tables_only=options.tables_only + sql_file=sql_file ) - else: - append_to_sql = 'w' if options.append_to_sql else 'a' - with open(options.sql_file, append_to_sql) as sql_file: - create_tables_from_standard_configuration( - configuration_yaml_path=options.configuration, - source_class=config_source, - section=options.section, - c2ctemplate_style=options.c2ctemplate_style, - sql_file=sql_file - ) From 4f5453cdbd81720f214e4d81a3a13f01ab641dfb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 8 Jan 2024 08:04:02 +0100 Subject: [PATCH 49/60] Update dependency pillow to v10.2.0 (#1919) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- tests-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests-requirements.txt b/tests-requirements.txt index db8acf8bd9..5ecc11f4e6 100644 --- a/tests-requirements.txt +++ b/tests-requirements.txt @@ -6,4 +6,4 @@ pytest-ordering==0.6 requests-mock==1.11.0 responses==0.24.1 webtest==3.0.0 -pillow==10.1.0 +pillow==10.2.0 From 2240a58d1161c826dbe0ee4c099afcc7b451cde7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 8 Jan 2024 08:04:22 +0100 Subject: [PATCH 50/60] Update dependency SQLAlchemy to v2.0.25 (#1920) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b6f35fc11b..0137950854 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ pyramid-debugtoolbar==4.10 qrcode==7.4.2 image==1.5.33 shapely==2.0.2 -SQLAlchemy==2.0.24 +SQLAlchemy==2.0.25 pyaml-env==1.2.1 urllib3==2.1.0 waitress==2.1.2 From 21cfcb97a1b9c9cc3ed57e2268324ddaadda1964 Mon Sep 17 00:00:00 2001 From: Wolfgang Kaltz Date: Mon, 8 Jan 2024 08:04:45 +0100 Subject: [PATCH 51/60] Fix deprecation (#1915) --- pyramid_oereb/contrib/data_sources/oereblex/models/theme.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pyramid_oereb/contrib/data_sources/oereblex/models/theme.py b/pyramid_oereb/contrib/data_sources/oereblex/models/theme.py index 1eabe866f8..46b4ee9190 100644 --- a/pyramid_oereb/contrib/data_sources/oereblex/models/theme.py +++ b/pyramid_oereb/contrib/data_sources/oereblex/models/theme.py @@ -1,7 +1,6 @@ from sqlalchemy import Column, ForeignKey from sqlalchemy import String, Integer, Date -from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy.orm import relationship +from sqlalchemy.orm import declarative_base, relationship from pyramid_oereb.contrib.data_sources.standard.models import ( get_office, From fa125c299c46467756f0a21d87cbad094e71ee93 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 8 Jan 2024 08:05:52 +0100 Subject: [PATCH 52/60] Update dependency lxml to v5 (#1917) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- tests-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests-requirements.txt b/tests-requirements.txt index 5ecc11f4e6..095c9c9b16 100644 --- a/tests-requirements.txt +++ b/tests-requirements.txt @@ -1,5 +1,5 @@ jsonschema==4.20.0 -lxml==4.9.4 +lxml==5.0.1 pytest==7.4.4 pytest-cov==4.1.0 pytest-ordering==0.6 From 6164fb770301c2702df7b0b5158188730695d8fc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 8 Jan 2024 13:21:08 +0100 Subject: [PATCH 53/60] Update dependency lxml to v5.1.0 (#1923) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- tests-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests-requirements.txt b/tests-requirements.txt index 095c9c9b16..52b9957435 100644 --- a/tests-requirements.txt +++ b/tests-requirements.txt @@ -1,5 +1,5 @@ jsonschema==4.20.0 -lxml==5.0.1 +lxml==5.1.0 pytest==7.4.4 pytest-cov==4.1.0 pytest-ordering==0.6 From f01bad2edc5a4da17e1d87a5bacd4f847242199a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 9 Jan 2024 16:04:00 +0100 Subject: [PATCH 54/60] Update dependency c2cwsgiutils to v6.0.7 (#1924) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 0137950854..0679a8d3f2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,4 +15,4 @@ mako-render==0.1.0 requests==2.31.0 geolink-formatter==2.0.4 pyconizer==0.1.4 -c2cwsgiutils[standard]==6.0.6 +c2cwsgiutils[standard]==6.0.7 From 14f2071513ac244e0c1db9769c458ca3a7df4ce8 Mon Sep 17 00:00:00 2001 From: Wolfgang Kaltz Date: Tue, 9 Jan 2024 16:46:25 +0100 Subject: [PATCH 55/60] Do simultaneous update of flake and pyflake due to mutual version dependency (#1925) --- dev-requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev-requirements.txt b/dev-requirements.txt index b1c9f4eb9c..cf271f9afc 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,5 +1,5 @@ -flake8==6.1.0 -pyflakes==3.1.0 +flake8==7.0.0 +pyflakes==3.2.0 pycodestyle==2.11.1 Sphinx==7.2.6 sphinx_rtd_theme==2.0.0 From 12a7ac6d607decf79f2fa1042f041b0889801f4b Mon Sep 17 00:00:00 2001 From: Wolfgang Kaltz Date: Wed, 10 Jan 2024 08:52:15 +0100 Subject: [PATCH 56/60] Fix the create_theme script (#1913) * Fixes #1562 --- .../contrib/data_sources/create_tables.py | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/pyramid_oereb/contrib/data_sources/create_tables.py b/pyramid_oereb/contrib/data_sources/create_tables.py index 386b0c4539..ebad3cf090 100644 --- a/pyramid_oereb/contrib/data_sources/create_tables.py +++ b/pyramid_oereb/contrib/data_sources/create_tables.py @@ -198,7 +198,7 @@ def create_main_schema_tables(): def create_theme_tables(): parser = optparse.OptionParser( usage='usage: %prog [options]', - description='Create all content for the standard database' + description='Create theme tables SQL' ) parser.add_option( '-c', '--configuration', @@ -241,11 +241,20 @@ def create_theme_tables(): default=False, help='Is the yaml file using a c2ctemplate style (starting with vars)' ) + parser.add_option( + '--config-source', + type='string', + default='pyramid_oereb.contrib.data_sources.standard.sources.plr.DatabaseSource', + help='Config source to use, it must be an implementation corresponding to the standard schema.' + 'Note: parameter must match the actual config; a default value is provided.' + ) options, args = parser.parse_args() if not options.configuration: parser.error('No configuration file set.') if not options.theme: parser.error('No theme code specified.') + if not options.sql_file: + parser.error('No sql filename specified.') if Config.get_config() is None: Config.init( @@ -258,15 +267,10 @@ def create_theme_tables(): if theme_config is None: parser.error('Specified theme not found in configuration.') - if options.sql_file is None: + with open(options.sql_file, 'w') as sql_file: create_theme_tables_( theme_config, - tables_only=options.tables_only + options.config_source, + tables_only=options.tables_only, + sql_file=sql_file ) - else: - with open(options.sql_file, 'w') as sql_file: - create_theme_tables_( - theme_config, - tables_only=options.tables_only, - sql_file=sql_file - ) From 1f358f109167e82edbbb33018e2ea077b912fbde Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Wed, 10 Jan 2024 16:09:20 +0100 Subject: [PATCH 57/60] fix typo --- tests/core_adapter/test_adapter_database.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core_adapter/test_adapter_database.py b/tests/core_adapter/test_adapter_database.py index 5914240883..df66403c51 100644 --- a/tests/core_adapter/test_adapter_database.py +++ b/tests/core_adapter/test_adapter_database.py @@ -33,7 +33,7 @@ def test_add_connection_already_exists(caplog): def test_get_connections(): db_url = 'postgresql://adapter_user:adapter_pswd@adapter-tests-02:5432/adapter-db' - test_connection = {db_url: {"engine": "test_engne", "session": "test_session"}} + test_connection = {db_url: {"engine": "test_engine", "session": "test_session"}} adapter = DatabaseAdapter() adapter._connections_ = test_connection assert adapter.get_connections() == test_connection From 3c6e8843fd7b969ea47eeb11b83024661a8d6f53 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Mon, 15 Jan 2024 09:06:59 +0100 Subject: [PATCH 58/60] geolink-formatter==2.0.5 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 0679a8d3f2..1aac089986 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,6 +13,6 @@ waitress==2.1.2 pyreproj==3.0.0 mako-render==0.1.0 requests==2.31.0 -geolink-formatter==2.0.4 +geolink-formatter==2.0.5 pyconizer==0.1.4 c2cwsgiutils[standard]==6.0.7 From c139975ab7ec5c1e175d5675726cd2252aff848f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 16 Jan 2024 17:16:34 +0100 Subject: [PATCH 59/60] Update dependency jsonschema to v4.21.0 (#1929) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- tests-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests-requirements.txt b/tests-requirements.txt index 52b9957435..6a7ce03a0b 100644 --- a/tests-requirements.txt +++ b/tests-requirements.txt @@ -1,4 +1,4 @@ -jsonschema==4.20.0 +jsonschema==4.21.0 lxml==5.1.0 pytest==7.4.4 pytest-cov==4.1.0 From a8954ef03bdda8f3457864558e449b982dbc94d5 Mon Sep 17 00:00:00 2001 From: Anne Maier Date: Thu, 18 Jan 2024 13:37:02 +0100 Subject: [PATCH 60/60] adjust changes.rst with extract_index column --- CHANGES.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.rst b/CHANGES.rst index 80e5efc23a..581e950268 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -3,6 +3,7 @@ Changelog 2.4.7 ----- +- Add extract_index to disclaimer and general infomation (#1753) - Interlis bug fix (#1881) - Library upgrades (geoalchemy2, SQLAlchemy, jsonschema, lxml, responses, urllib3, pypdf) - Test coverage improvements