Skip to content

Commit d4a06de

Browse files
committed
read plan regulations data from QGIS layer
- modified PlanRegulationConfig and PlanRegulationSet classes - modified kaavammaraykset.yaml to only include missing information about regulations - initialize PlanRegulationSet only when it is needed for the first time
1 parent 0afb9b8 commit d4a06de

File tree

3 files changed

+129
-240
lines changed

3 files changed

+129
-240
lines changed

arho_feature_template/core/plan_regulation_config.py

+72-44
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from numbers import Number
1818
from typing import Literal
1919

20+
from qgis.core import QgsFeature
2021
from qgis.gui import QgisInterface
2122

2223
iface: QgisInterface = cast("QgisInterface", iface) # type: ignore[no-redef]
@@ -68,15 +69,15 @@ class PlanRegulationsSet:
6869

6970
version: str
7071
regulations: list[PlanRegulationConfig]
71-
regulations_dict: dict[str, PlanRegulationConfig] = field(default_factory=dict)
72+
regulations_dict: dict[str, PlanRegulationConfig]
7273

7374
_instance: PlanRegulationsSet | None = None
7475

7576
@classmethod
7677
def get_instance(cls) -> PlanRegulationsSet:
7778
"""Get the singleton instance, if initialized."""
7879
if cls._instance is None:
79-
raise UninitializedError
80+
return cls.initialize()
8081
return cls._instance
8182

8283
@classmethod
@@ -101,71 +102,98 @@ def initialize(
101102
type_of_plan_regulations_layer_name="Kaavamääräyslaji",
102103
language: Literal["fin", "eng", "swe"] = "fin",
103104
) -> PlanRegulationsSet:
104-
# Initialize PlanRegulationsSet and PlanRegulationConfigs from config file
105-
with config_path.open(encoding="utf-8") as f:
106-
data = yaml.safe_load(f)
107-
cls._instance = cls.from_dict(data)
105+
# Initialize PlanRegulationsSet and PlanRegulationConfigs from QGIS layer and config file
108106

109-
regulations = cls.get_regulations()
110-
regulations_dict: dict[str, PlanRegulationConfig] = {}
111-
mapping = get_name_mapping_for_plan_regulations(type_of_plan_regulations_layer_name)
107+
# 1. Read config file into a dict
108+
with config_path.open(encoding="utf-8") as f:
109+
config_data = yaml.safe_load(f)
112110

113-
# Add names to dictionary, add names to regulations
114-
for regulation in regulations:
115-
regulation.add_to_dictionary(regulations_dict)
116-
if mapping:
117-
regulation.add_name(mapping, language)
111+
# 2. Read code layer
112+
layer = get_layer_by_name(type_of_plan_regulations_layer_name)
113+
if layer is None:
114+
msg = f"Could not find layer {type_of_plan_regulations_layer_name}!"
115+
raise KeyError(msg)
118116

119-
cls._instance.regulations_dict = regulations_dict
120-
logger.info("PlanRegulationsSet initialized successfully.")
121-
return cls._instance
117+
# 3. Initialize regulation configs from layer. Storing them by their ID is handy for adding childs later
118+
id_to_regulation_map: dict[str, PlanRegulationConfig] = {
119+
feature["id"]: PlanRegulationConfig.from_feature(feature, language) for feature in layer.getFeatures()
120+
}
122121

123-
@classmethod
124-
def from_dict(cls, data: dict) -> PlanRegulationsSet:
125-
file_version = data["version"]
122+
# 4. Add information from config file (value, unit, category only) and link child regulations
126123
try:
127-
return cls(
128-
version=file_version,
129-
regulations=[PlanRegulationConfig.from_dict(config) for config in data["plan_regulations"]],
130-
)
124+
regulation_data: dict = {data["regulation_code"]: data for data in config_data["plan_regulations"]}
125+
top_level_regulations: list[PlanRegulationConfig] = []
126+
for regulation_config in id_to_regulation_map.values():
127+
# Add possible information from config data file
128+
data = regulation_data.get(regulation_config.regulation_code)
129+
if data:
130+
regulation_config.category_only = data.get("category_only", False)
131+
regulation_config.value_type = ValueType(data["value_type"]) if "value_type" in data else None
132+
regulation_config.unit = Unit(data["unit"]) if "unit" in data else None
133+
134+
# Top-level, add to list
135+
if not regulation_config.parent_id:
136+
top_level_regulations.append(regulation_config)
137+
else:
138+
# Add as child of another regulation
139+
id_to_regulation_map[regulation_config.parent_id].child_regulations.append(regulation_config)
131140
except KeyError as e:
132141
raise ConfigSyntaxError(str(e)) from e
133142

143+
# 5. Create dictionary, useful when creating PlanRegulationDefinitions at least
144+
regulations_dict: dict[str, PlanRegulationConfig] = {}
145+
for reg in top_level_regulations:
146+
reg.add_to_dictionary(regulations_dict)
147+
148+
# 5. Create instance
149+
cls._instance = cls(
150+
version=config_data["version"], regulations=top_level_regulations, regulations_dict=regulations_dict
151+
)
152+
logger.info("PlanRegulationsSet initialized successfully.")
153+
return cls._instance
154+
134155

135156
@dataclass
136157
class PlanRegulationConfig:
137-
"""Describes the configuration of a plan regulation."""
158+
"""
159+
Describes the configuration of a plan regulation.
138160
161+
Combination of information read from code layer in QGIS / DB and other information
162+
from a configuration file.
163+
"""
164+
165+
id: str
139166
regulation_code: str
140167
name: str
141-
category_only: bool
142-
value_type: ValueType | None
143-
unit: Unit | None
144-
child_regulations: list[PlanRegulationConfig]
168+
description: str
169+
status: str
170+
level: int
171+
parent_id: str | None
172+
child_regulations: list[PlanRegulationConfig] = field(default_factory=list)
173+
174+
category_only: bool = False
175+
value_type: ValueType | None = None
176+
unit: Unit | None = None
145177

146178
@classmethod
147-
def from_dict(cls, data: dict) -> PlanRegulationConfig:
179+
def from_feature(cls, feature: QgsFeature, language: str = "fin") -> PlanRegulationConfig:
148180
"""
149-
Initialize PlanRegulationConfig from dict.
181+
Initialize PlanRegulationConfig from QgsFeature.
150182
151-
Intializes child regulations recursively.
183+
Child regulations, value type ,category only and unit need to be set separately.
152184
"""
153185
return cls(
154-
regulation_code=data["regulation_code"],
155-
name=data["regulation_code"],
156-
category_only=data.get("category_only", False),
157-
value_type=ValueType(data["value_type"]) if "value_type" in data else None,
158-
unit=Unit(data["unit"]) if "unit" in data else None,
159-
child_regulations=[PlanRegulationConfig.from_dict(config) for config in data.get("child_regulations", [])],
186+
id=feature["id"],
187+
regulation_code=feature["value"],
188+
name=feature["name"][language],
189+
description=feature["description"][language],
190+
status=feature["status"],
191+
level=feature["level"],
192+
parent_id=feature["parent_id"],
160193
)
161194

162-
def add_name(self, code_to_name_mapping: dict[str, dict[str, str]], language: Literal["fin", "eng", "swe"]):
163-
language_to_name_dict = code_to_name_mapping.get(self.regulation_code)
164-
self.name = language_to_name_dict[language] if language_to_name_dict else self.regulation_code
165-
for regulation in self.child_regulations:
166-
regulation.add_name(code_to_name_mapping, language)
167-
168195
def add_to_dictionary(self, dictionary: dict[str, PlanRegulationConfig]):
196+
"""Add child regulations to dictionary too."""
169197
dictionary[self.regulation_code] = self
170198
for regulation in self.child_regulations:
171199
regulation.add_to_dictionary(dictionary)

arho_feature_template/plugin.py

-4
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
from arho_feature_template.core.feature_template_library import FeatureTemplater, TemplateGeometryDigitizeMapTool
1111
from arho_feature_template.core.plan_manager import PlanManager
12-
from arho_feature_template.core.plan_regulation_config import PlanRegulationsSet
1312
from arho_feature_template.gui.new_plan_regulation_group_form import NewPlanRegulationGroupForm
1413
from arho_feature_template.gui.plugin_settings import PluginSettings
1514
from arho_feature_template.qgis_plugin_tools.tools.custom_logging import setup_logger, teardown_logger
@@ -44,9 +43,6 @@ def __init__(self) -> None:
4443
self.actions: list[QAction] = []
4544
self.menu = Plugin.name
4645

47-
# Initialize plan regulations set
48-
PlanRegulationsSet.initialize()
49-
5046
def add_action(
5147
self,
5248
icon_path: str,

0 commit comments

Comments
 (0)