Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Variables as toppings #14

Merged
merged 5 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,7 @@ with a database, so your own postgres installation is not affected at all.

To run the tests, go to the main directory of the project and do

```sh
export QGIS_TEST_VERSION=latest # See https://hub.docker.com/r/qgis/qgis/tags/
export GITHUB_WORKSPACE=$PWD # only for local execution
docker run -v ${GITHUB_WORKSPACE}:/usr/src -w /usr/src opengisch/qgis:${QGIS_TEST_VERSION} sh -c 'xvfb-run pytest-3'
```

In one line, removing all containers.
```sh
QGIS_TEST_VERSION=latest GITHUB_WORKSPACE=$PWD docker run -v ${GITHUB_WORKSPACE}:/usr/src -w /usr/src opengisch/qgis:${QGIS_TEST_VERSION} sh -c 'xvfb-run pytest-3'
docker run -v $PWD:/usr/src -w /usr/src opengisch/qgis:latest sh -c 'xvfb-run pytest-3'
```
36 changes: 30 additions & 6 deletions tests/test_toppingmaker.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ class ToppingMakerTest(unittest.TestCase):
def setUpClass(cls):
"""Run before all tests."""
cls.basetestpath = tempfile.mkdtemp()
cls.testdata_path = os.path.join(
os.path.dirname(os.path.abspath(__file__)), "testdata"
)
cls.projecttopping_test_path = os.path.join(cls.basetestpath, "projecttopping")

def test_target(self):
Expand Down Expand Up @@ -143,9 +146,11 @@ def test_parse_project_with_mapthemes(self):
# check variables
variables = project_topping.variables
# Anyway in practice no spaces should be used to be able to access them in the expressions like @first_variable
assert variables.get("First Variable") == "This is a test value."
assert variables.get("First Variable")
assert variables.get("First Variable")["value"] == "This is a test value."
# QGIS is currently (3.29) not able to store structures in the project file. Still...
assert variables.get("Variable with Structure") == [
assert variables.get("Variable with Structure")
assert variables.get("Variable with Structure")["value"] == [
"Not",
"The",
"Normal",
Expand Down Expand Up @@ -416,11 +421,18 @@ def test_generate_files(self):
"Case",
]
foundVariableWithStructure = True
if variable_key == "Validation Path Variable":
assert (
projecttopping_data["variables"][variable_key]
== "freddys_projects/this_specific_project/generic/freddys_validConfig.ini"
)
foundVariableWithPath = True
variable_count += 1

assert variable_count == 2
assert variable_count == 3
assert foundFirstVariable
assert foundVariableWithStructure
assert foundVariableWithPath

# check transaction mode
with open(projecttopping_file_path) as yamlfile:
Expand Down Expand Up @@ -471,12 +483,13 @@ def test_generate_files(self):

countchecked = 0

# there should be 21 toppingfiles:
# there should be 22 toppingfiles:
# - one project topping
# - 2 x 3 qlr files (two times since the layers are multiple times in the tree)
# - 2 x 6 qml files (one layers with 3 styles, one layer with 2 styles and one layer with one style - and two times since the layers are multiple times in the tree)
# - 2 qpt template files
assert len(target.toppingfileinfo_list) == 21
# - 1 generic file (validation.ini) what is created by variable
assert len(target.toppingfileinfo_list) == 22

for toppingfileinfo in target.toppingfileinfo_list:
self.print_info(toppingfileinfo["path"])
Expand Down Expand Up @@ -703,6 +716,11 @@ def _make_project_and_export_settings(self):
QgsExpressionContextUtils.setProjectVariable(
project, "Variable with Structure", ["Not", "The", "Normal", 815, "Case"]
)
QgsExpressionContextUtils.setProjectVariable(
project,
"Validation Path Variable",
os.path.join(self.testdata_path, "validConfig.ini"),
)

# create layouts
layout = QgsPrintLayout(project)
Expand Down Expand Up @@ -788,7 +806,13 @@ def _make_project_and_export_settings(self):
export_settings.mapthemes = ["French Theme", "Robot Theme"]

# define the custom variables to export
export_settings.variables = ["First Variable", "Variable with Structure"]
export_settings.variables = [
"First Variable",
"Variable with Structure",
"Validation Path Variable",
]
# content of this variable should be exported as toppingfile
export_settings.path_variables = ["Validation Path Variable"]

# define the layouts to export
export_settings.layouts = ["Layout One", "Layout Three"]
Expand Down
7 changes: 7 additions & 0 deletions tests/testdata/validConfig.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
["PARAMETER"]
validation="on"
additionalModels="SH_ProjektdatenDB_Naturschutz_V1_0_AddChecks"

["SH_ProjektdatenDB_Naturschutz_V1_0_AddChecks.SH_ProjektdatenDB_Naturschutz_V1_0_Validierung.v_Mitarbeitende.checkNameDuplikate"]
multiplicity="on"
type="on"
2 changes: 2 additions & 0 deletions toppingmaker/exportsettings.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ def __init__(self):
self.mapthemes = []
# keys of custom variables to be exported
self.variables = []
# list of variable keys that are defined as paths and should be resolved
self.path_variables = []
# names of layouts
self.layouts = []

Expand Down
40 changes: 36 additions & 4 deletions toppingmaker/projecttopping.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class ProjectTopping(QObject):
LAYERDEFINITION_TYPE = "layerdefinition"
LAYERSTYLE_TYPE = "layerstyle"
LAYOUTTEMPLATE_TYPE = "layouttemplate"
GENERIC_TYPE = "generic"

class TreeItemProperties:
"""
Expand Down Expand Up @@ -414,19 +415,50 @@ def make_items(
class Variables(dict):
"""
A dict object of dict items describing a variable according to the variable keys listed in the ExportSettings passed on parsing the QGIS project.
The items have the keys 'name' and (optional) 'ispath' for the case that it's a path that needs to be resolved for the topping.
To define what variables are paths this needs to be set in the ExportSettings path_variables.
"""

def make_items(
self,
project: QgsProject,
export_settings: ExportSettings,
):

self.clear()
for variable_key in export_settings.variables:
variable_item = {}

variable_value = QgsExpressionContextUtils.projectScope(
project
).variable(variable_key)
self[variable_key] = variable_value or None

# if it's defined as path variable, we have to expose it as toppingfile
if variable_key in export_settings.path_variables:
path = variable_value
if project.homePath() and not os.path.isabs(variable_value):
# if it's a saved project and the path is not absolute, make it absolute
path = os.path.join(
variable_value, project.homePath(), variable_value
)
variable_item["value"] = path
variable_item["ispath"] = True
else:
variable_item["value"] = variable_value

self[variable_key] = variable_item or None

def resolved_dict(self, target: Target):
resolved_items = {}
for variable_key in self.keys():
resolved_value = self[variable_key].get("value")
if self[variable_key].get("ispath", False):
resolved_value = target.toppingfile_link(
ProjectTopping.GENERIC_TYPE,
self[variable_key].get("value"),
)
resolved_items[variable_key] = resolved_value
return resolved_items

class Properties(dict):
"""
Expand Down Expand Up @@ -613,9 +645,9 @@ def _projecttopping_dict(self, target: Target):
mapthemes_dict = dict(self.mapthemes)
if mapthemes_dict:
projecttopping_dict["mapthemes"] = mapthemes_dict
variables_dict = dict(self.variables)
if variables_dict:
projecttopping_dict["variables"] = variables_dict
variables_resolved_dict = self.variables.resolved_dict(target)
if variables_resolved_dict:
projecttopping_dict["variables"] = variables_resolved_dict
properties_dict = dict(self.properties)
if properties_dict:
projecttopping_dict["properties"] = properties_dict
Expand Down
Loading