17
17
from numbers import Number
18
18
from typing import Literal
19
19
20
+ from qgis .core import QgsFeature
20
21
from qgis .gui import QgisInterface
21
22
22
23
iface : QgisInterface = cast ("QgisInterface" , iface ) # type: ignore[no-redef]
@@ -68,15 +69,15 @@ class PlanRegulationsSet:
68
69
69
70
version : str
70
71
regulations : list [PlanRegulationConfig ]
71
- regulations_dict : dict [str , PlanRegulationConfig ] = field ( default_factory = dict )
72
+ regulations_dict : dict [str , PlanRegulationConfig ]
72
73
73
74
_instance : PlanRegulationsSet | None = None
74
75
75
76
@classmethod
76
77
def get_instance (cls ) -> PlanRegulationsSet :
77
78
"""Get the singleton instance, if initialized."""
78
79
if cls ._instance is None :
79
- raise UninitializedError
80
+ return cls . initialize ()
80
81
return cls ._instance
81
82
82
83
@classmethod
@@ -101,71 +102,98 @@ def initialize(
101
102
type_of_plan_regulations_layer_name = "Kaavamääräyslaji" ,
102
103
language : Literal ["fin" , "eng" , "swe" ] = "fin" ,
103
104
) -> 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
108
106
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 )
112
110
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 )
118
116
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
+ }
122
121
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
126
123
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 )
131
140
except KeyError as e :
132
141
raise ConfigSyntaxError (str (e )) from e
133
142
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
+
134
155
135
156
@dataclass
136
157
class PlanRegulationConfig :
137
- """Describes the configuration of a plan regulation."""
158
+ """
159
+ Describes the configuration of a plan regulation.
138
160
161
+ Combination of information read from code layer in QGIS / DB and other information
162
+ from a configuration file.
163
+ """
164
+
165
+ id : str
139
166
regulation_code : str
140
167
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
145
177
146
178
@classmethod
147
- def from_dict (cls , data : dict ) -> PlanRegulationConfig :
179
+ def from_feature (cls , feature : QgsFeature , language : str = "fin" ) -> PlanRegulationConfig :
148
180
"""
149
- Initialize PlanRegulationConfig from dict .
181
+ Initialize PlanRegulationConfig from QgsFeature .
150
182
151
- Intializes child regulations recursively .
183
+ Child regulations, value type ,category only and unit need to be set separately .
152
184
"""
153
185
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" ],
160
193
)
161
194
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
-
168
195
def add_to_dictionary (self , dictionary : dict [str , PlanRegulationConfig ]):
196
+ """Add child regulations to dictionary too."""
169
197
dictionary [self .regulation_code ] = self
170
198
for regulation in self .child_regulations :
171
199
regulation .add_to_dictionary (dictionary )
0 commit comments