hydamo-validation 1.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of hydamo-validation might be problematic. Click here for more details.

Files changed (48) hide show
  1. hydamo_validation-1.3.0/LICENSE +21 -0
  2. hydamo_validation-1.3.0/PKG-INFO +67 -0
  3. hydamo_validation-1.3.0/README.md +48 -0
  4. hydamo_validation-1.3.0/hydamo_validation/__init__.py +24 -0
  5. hydamo_validation-1.3.0/hydamo_validation/datamodel.py +500 -0
  6. hydamo_validation-1.3.0/hydamo_validation/datasets.py +109 -0
  7. hydamo_validation-1.3.0/hydamo_validation/functions/__init__.py +0 -0
  8. hydamo_validation-1.3.0/hydamo_validation/functions/general.py +319 -0
  9. hydamo_validation-1.3.0/hydamo_validation/functions/logic.py +338 -0
  10. hydamo_validation-1.3.0/hydamo_validation/functions/topologic.py +665 -0
  11. hydamo_validation-1.3.0/hydamo_validation/geometry.py +144 -0
  12. hydamo_validation-1.3.0/hydamo_validation/logical_validation.py +380 -0
  13. hydamo_validation-1.3.0/hydamo_validation/schemas/hydamo/HyDAMO_2.2.json +5946 -0
  14. hydamo_validation-1.3.0/hydamo_validation/schemas/hydamo/HyDAMO_2.3.json +6602 -0
  15. hydamo_validation-1.3.0/hydamo_validation/schemas/rules/rules_1.0.json +1134 -0
  16. hydamo_validation-1.3.0/hydamo_validation/schemas/rules/rules_1.1.json +1134 -0
  17. hydamo_validation-1.3.0/hydamo_validation/schemas/rules/rules_1.2.json +1128 -0
  18. hydamo_validation-1.3.0/hydamo_validation/schemas/rules/rules_1.3.json +1128 -0
  19. hydamo_validation-1.3.0/hydamo_validation/styles/hydroobject.qml +497 -0
  20. hydamo_validation-1.3.0/hydamo_validation/styles/hydroobject.sld +15 -0
  21. hydamo_validation-1.3.0/hydamo_validation/styles.py +124 -0
  22. hydamo_validation-1.3.0/hydamo_validation/summaries.py +269 -0
  23. hydamo_validation-1.3.0/hydamo_validation/syntax_validation.py +269 -0
  24. hydamo_validation-1.3.0/hydamo_validation/utils.py +75 -0
  25. hydamo_validation-1.3.0/hydamo_validation/validator.py +370 -0
  26. hydamo_validation-1.3.0/hydamo_validation.egg-info/PKG-INFO +67 -0
  27. hydamo_validation-1.3.0/hydamo_validation.egg-info/SOURCES.txt +46 -0
  28. hydamo_validation-1.3.0/hydamo_validation.egg-info/dependency_links.txt +1 -0
  29. hydamo_validation-1.3.0/hydamo_validation.egg-info/requires.txt +9 -0
  30. hydamo_validation-1.3.0/hydamo_validation.egg-info/top_level.txt +1 -0
  31. hydamo_validation-1.3.0/hydamo_validation.egg-info/zip-safe +1 -0
  32. hydamo_validation-1.3.0/pyproject.toml +46 -0
  33. hydamo_validation-1.3.0/setup.cfg +4 -0
  34. hydamo_validation-1.3.0/setup.py +3 -0
  35. hydamo_validation-1.3.0/tests/test_datasets.py +46 -0
  36. hydamo_validation-1.3.0/tests/test_dommelerwaard.py +87 -0
  37. hydamo_validation-1.3.0/tests/test_general_functions.py +154 -0
  38. hydamo_validation-1.3.0/tests/test_hydamo_2_2.py +135 -0
  39. hydamo_validation-1.3.0/tests/test_init.py +45 -0
  40. hydamo_validation-1.3.0/tests/test_logic_functions.py +84 -0
  41. hydamo_validation-1.3.0/tests/test_not_overlapping.py +113 -0
  42. hydamo_validation-1.3.0/tests/test_productie.py +103 -0
  43. hydamo_validation-1.3.0/tests/test_structures_at_interersections.py +35 -0
  44. hydamo_validation-1.3.0/tests/test_summaries.py +110 -0
  45. hydamo_validation-1.3.0/tests/test_topologic_functions.py +157 -0
  46. hydamo_validation-1.3.0/tests/test_validationrules.py +60 -0
  47. hydamo_validation-1.3.0/tests/test_wrij.py +183 -0
  48. hydamo_validation-1.3.0/tests/test_wrij_profielen.py +25 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 HyDAMO ValidatieTool
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,67 @@
1
+ Metadata-Version: 2.1
2
+ Name: hydamo_validation
3
+ Version: 1.3.0
4
+ Summary: Validation module for HyDAMO data
5
+ Author-email: Daniel Tollenaar <daniel@d2hydro.nl>
6
+ License: MIT
7
+ Project-URL: Source, https://github.com/HetWaterschapshuis/HyDAMOValidatieModule
8
+ Requires-Python: >=3.12
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: geopandas
12
+ Requires-Dist: pandas>=2
13
+ Requires-Dist: pyogrio
14
+ Requires-Dist: rasterio
15
+ Requires-Dist: shapely>=2
16
+ Requires-Dist: rasterstats
17
+ Provides-Extra: tests
18
+ Requires-Dist: pytest; extra == "tests"
19
+
20
+ # The HyDAMO Validation Module: hydamo_validation
21
+
22
+ Validation Module for HyDAMO data.
23
+
24
+ ## Installation
25
+
26
+ ### Python installation
27
+ Make sure you have an Miniconda or Anaconda installation. You can download these here:
28
+ - https://www.anaconda.com/products/individual
29
+ - https://docs.conda.io/en/latest/miniconda.html
30
+
31
+ During installation, tick the box "Add Anaconda to PATH", ignore the red remarks
32
+
33
+ ### Create the `validatietool` environment
34
+ Use the `env/environment.yml` in the repository to create the conda environment: `validatietool`
35
+
36
+ ```
37
+ conda env create -f environment.yml
38
+ ```
39
+
40
+ After installation you can activate your environment in command prompt
41
+
42
+ ```
43
+ conda activate validatietool
44
+ ```
45
+
46
+ ### Install hydamo_validation
47
+ Simply install the module in the activated environment:
48
+
49
+ ```
50
+ pip install hydamo_validation
51
+ ```
52
+
53
+ ### Develop-install hydamo_validation
54
+ Download or clone the repository. Now simply install the module in the activated environment:
55
+
56
+ ```
57
+ pip install .
58
+ ```
59
+
60
+ ## Run an example
61
+ A working example with data can be found in `notebooks/test_wrij.ipynb`. In the activated environment launch jupyter notebook by:
62
+
63
+ ```
64
+ jupyter notebook
65
+ ```
66
+
67
+ Select `test_wrij.ipynb` read and run it.
@@ -0,0 +1,48 @@
1
+ # The HyDAMO Validation Module: hydamo_validation
2
+
3
+ Validation Module for HyDAMO data.
4
+
5
+ ## Installation
6
+
7
+ ### Python installation
8
+ Make sure you have an Miniconda or Anaconda installation. You can download these here:
9
+ - https://www.anaconda.com/products/individual
10
+ - https://docs.conda.io/en/latest/miniconda.html
11
+
12
+ During installation, tick the box "Add Anaconda to PATH", ignore the red remarks
13
+
14
+ ### Create the `validatietool` environment
15
+ Use the `env/environment.yml` in the repository to create the conda environment: `validatietool`
16
+
17
+ ```
18
+ conda env create -f environment.yml
19
+ ```
20
+
21
+ After installation you can activate your environment in command prompt
22
+
23
+ ```
24
+ conda activate validatietool
25
+ ```
26
+
27
+ ### Install hydamo_validation
28
+ Simply install the module in the activated environment:
29
+
30
+ ```
31
+ pip install hydamo_validation
32
+ ```
33
+
34
+ ### Develop-install hydamo_validation
35
+ Download or clone the repository. Now simply install the module in the activated environment:
36
+
37
+ ```
38
+ pip install .
39
+ ```
40
+
41
+ ## Run an example
42
+ A working example with data can be found in `notebooks/test_wrij.ipynb`. In the activated environment launch jupyter notebook by:
43
+
44
+ ```
45
+ jupyter notebook
46
+ ```
47
+
48
+ Select `test_wrij.ipynb` read and run it.
@@ -0,0 +1,24 @@
1
+ __author__ = ["Het Waterschapshuis", "D2HYDRO", "HKV", "HydroConsult"]
2
+ __copyright__ = "Copyright 2021, HyDAMO ValidatieTool"
3
+ __credits__ = ["D2HYDRO", "HKV", "HydroConsult"]
4
+ __version__ = "1.3.0"
5
+
6
+ __license__ = "MIT"
7
+ __maintainer__ = "Daniel Tollenaar"
8
+ __email__ = "daniel@d2hydro.nl"
9
+
10
+ import fiona # top-level import to avoid fiona import issue: https://github.com/conda-forge/fiona-feedstock/issues/213
11
+ from pathlib import Path
12
+ from hydamo_validation.functions import topologic as topologic_functions
13
+ from hydamo_validation.functions import logic as logic_functions
14
+ from hydamo_validation.functions import general as general_functions
15
+ from hydamo_validation.validator import validator
16
+
17
+ __all__ = [
18
+ "fiona",
19
+ "topologic_functions",
20
+ "logic_functions",
21
+ "general_functions",
22
+ "validator",
23
+ "SCHEMAS_PATH",
24
+ ]
@@ -0,0 +1,500 @@
1
+ """HyDAMO datamodel for ValidatieTool."""
2
+
3
+ import json
4
+ import logging
5
+ import re
6
+ import warnings
7
+ from pathlib import Path
8
+ from typing import Any, Literal
9
+
10
+ import fiona
11
+ import geopandas as gpd
12
+ from geopandas import GeoSeries
13
+ import numpy as np
14
+ from shapely.geometry import LineString, MultiLineString, MultiPolygon, Point, Polygon
15
+
16
+ from hydamo_validation import geometry
17
+ from hydamo_validation.styles import add_styles_to_geopackage
18
+
19
+ warnings.filterwarnings("ignore", category=UserWarning)
20
+ warnings.filterwarnings("ignore", category=RuntimeWarning)
21
+ warnings.filterwarnings("ignore", category=FutureWarning)
22
+
23
+ FIELD_TYPES_MAP_REV = fiona.schema.FIELD_TYPES_MAP_REV
24
+ FIELD_TYPES_MAP = fiona.schema.FIELD_TYPES_MAP
25
+ MODEL_CRS = "epsg:28992"
26
+ SCHEMAS_DIR = Path(__file__).parent.joinpath("schemas", "hydamo")
27
+
28
+ GEOTYPE_MAPPING = {
29
+ "LineString": LineString,
30
+ "MultiLineString": MultiLineString,
31
+ "Point": Point,
32
+ "PointZ": Point,
33
+ "Polygon": Polygon,
34
+ "MultiPolygon": MultiPolygon,
35
+ }
36
+
37
+ DTYPE_MAPPING = {
38
+ "string": "str",
39
+ "integer": "int64",
40
+ "date-time": "datetime",
41
+ "number": "float",
42
+ }
43
+
44
+ default_properties: dict[str, Any] = {
45
+ "id": None,
46
+ "dtype": "str",
47
+ "required": False,
48
+ "unique": False,
49
+ }
50
+
51
+
52
+ def map_definition(definition: dict[str, Any]) -> list[dict[str, Any]]:
53
+ """
54
+
55
+
56
+ Parameters
57
+ ----------
58
+ definition : dict[str, Any]
59
+ HyDAMO definition as specified in the HyDAMO JSON specification.
60
+
61
+ Returns
62
+ -------
63
+ list[dict[str, Any]]
64
+ Validation schema for the HyDAMO class.
65
+
66
+ """
67
+
68
+ # start with an empty list to populate
69
+ result = []
70
+
71
+ for k, v in definition.items():
72
+ # convert geometry if shape
73
+ if k == "shape":
74
+ properties: dict[str, Any] = {"id": "geometry"}
75
+ dtype = v["type"]
76
+ if not isinstance(dtype, list):
77
+ dtype = [dtype]
78
+ properties["dtype"] = dtype
79
+ properties["required"] = True
80
+ result.append(properties)
81
+
82
+ # set properties if not shape
83
+ else:
84
+ properties = default_properties.copy()
85
+ properties["id"] = k
86
+ if "type" in v.keys():
87
+ properties["dtype"] = DTYPE_MAPPING[v["type"]]
88
+ if "format" in v.keys():
89
+ properties["dtype"] = DTYPE_MAPPING[v["format"]]
90
+
91
+ # set required
92
+ if "minItems" in v.keys():
93
+ if v["minItems"] == 1:
94
+ properties["required"] = True
95
+
96
+ # set unique
97
+ if "uniqueItems" in v.keys():
98
+ properties["unique"] = v["uniqueItems"]
99
+
100
+ # set domain
101
+ if "enum" in v.keys():
102
+ properties["domain"] = [{"value": i} for i in v["enum"]]
103
+ result.append(properties)
104
+ return result
105
+
106
+
107
+ class ExtendedGeoDataFrame(gpd.GeoDataFrame): # type: ignore
108
+ """A GeoPandas GeoDataFrame with extended properties and methods."""
109
+
110
+ # ignores subclassing Any: https://github.com/geopandas/geopandas/discussions/2750
111
+
112
+ _metadata = [
113
+ "required_columns",
114
+ "geotype",
115
+ "layer_name",
116
+ ] + gpd.GeoDataFrame._metadata
117
+
118
+ def __init__(
119
+ self,
120
+ validation_schema: list[dict[str, Any]],
121
+ geotype: (
122
+ list[
123
+ Literal[
124
+ "LineString",
125
+ "MultiLineString",
126
+ "Point",
127
+ "PointZ",
128
+ "Polygon",
129
+ "MultiPolygon",
130
+ ]
131
+ ]
132
+ | None
133
+ ),
134
+ layer_name: str = "",
135
+ required_columns: list[str] = [],
136
+ logger=logging,
137
+ *args,
138
+ **kwargs,
139
+ ):
140
+ # Check type
141
+ required_columns = [i.lower() for i in required_columns]
142
+
143
+ # Add required columns to column list
144
+ kwargs["columns"] = required_columns
145
+ kwargs["geometry"] = GeoSeries()
146
+
147
+ super().__init__(*args, **kwargs)
148
+
149
+ self.validation_schema = validation_schema
150
+ self.required_columns = required_columns
151
+ self.layer_name = layer_name
152
+ self.geotype = geotype
153
+
154
+ if "geometry" not in self.required_columns:
155
+ self.required_columns += ["geometry"]
156
+ self.crs = MODEL_CRS
157
+
158
+ def _check_columns(self, gdf):
159
+ """Check presence of columns in GeoDataFrame"""
160
+ present_columns = gdf.columns.tolist()
161
+ for column in self.required_columns:
162
+ if column not in present_columns:
163
+ raise KeyError(
164
+ 'Column "{}" not found. Got {}, Expected at least {}'.format(
165
+ column,
166
+ ", ".join(present_columns),
167
+ ", ".join(self.required_columns),
168
+ )
169
+ )
170
+
171
+ def _check_geotype(self):
172
+ """Check geometry type"""
173
+ if self.geotype:
174
+ if not all(
175
+ any(isinstance(geo, GEOTYPE_MAPPING[i]) for i in self.geotype)
176
+ for geo in self.geometry
177
+ ):
178
+ raise TypeError(
179
+ 'Geometry-type "{}" required in layer "{}". The input feature-file has geometry type(s) {}.'.format(
180
+ re.findall("([A-Z].*)'", repr(self.geotype))[0],
181
+ self.layer_name,
182
+ self.geometry.type.unique().tolist(),
183
+ )
184
+ )
185
+
186
+ def _get_schema(self):
187
+ """Return fiona schema dict from validation_schema."""
188
+ properties = {
189
+ i["id"]: i["dtype"] for i in self.validation_schema if i["id"] != "geometry"
190
+ }
191
+ # properties = {k: (v if v != "datetime" else "str") for k, v in properties}
192
+ geometry = next(
193
+ (i["dtype"] for i in self.validation_schema if i["id"] == "geometry"),
194
+ None,
195
+ )
196
+ return {"properties": properties, "geometry": geometry}
197
+
198
+ def set_data(
199
+ self,
200
+ gdf,
201
+ layer="",
202
+ index_col=None,
203
+ check_columns=True,
204
+ check_geotype=True,
205
+ extra_attributes={},
206
+ ):
207
+ """
208
+
209
+
210
+ Parameters
211
+ ----------
212
+ gdf : GeoDataFrame
213
+ GeoDataFrame with a HyDAMO object-layer
214
+ index_col : str, optional
215
+ Column to be used as index. The default is None.
216
+ check_columns : bool, optional
217
+ Check if all required columns are present in the GeoDataFrame.
218
+ The default is True.
219
+ check_geotype : bool, optional
220
+ Check if the geometry is of the required type. The default is True.
221
+
222
+ Returns
223
+ -------
224
+ None.
225
+
226
+ """
227
+
228
+ if not self.empty:
229
+ self.delete_all()
230
+
231
+ # reproject to crs if necessary
232
+ if (gdf.crs is not None) and ("geometry" in self.required_columns):
233
+ if f"epsg:{gdf.crs.to_epsg()}" == MODEL_CRS:
234
+ gdf.set_crs(MODEL_CRS, inplace=True, allow_override=True)
235
+ else:
236
+ gdf.to_crs(MODEL_CRS, inplace=True)
237
+
238
+ # Check columns
239
+ gdf.columns = [i.lower() for i in gdf.columns]
240
+ if check_columns:
241
+ self._check_columns(gdf)
242
+
243
+ # Copy content
244
+ for col, values in gdf.items():
245
+ self[col] = values.to_numpy()
246
+
247
+ if index_col is None:
248
+ self.index = gdf.index
249
+ self.index.name = gdf.index.name
250
+
251
+ else:
252
+ self.index = gdf[index_col]
253
+ self.index.name = index_col
254
+
255
+ # Check geometry types
256
+ if check_geotype:
257
+ self._check_geotype()
258
+
259
+ # Set extra attribute-values
260
+ for k, v in extra_attributes.items():
261
+ if k not in self.columns:
262
+ self[k] = v
263
+
264
+ def delete_all(self):
265
+ """Empty the dataframe"""
266
+ if not self.empty:
267
+ self.iloc[:, 0] = np.nan
268
+ self.dropna(inplace=True)
269
+
270
+ def snap_to_branch(self, branches, snap_method, maxdist=5):
271
+ """
272
+
273
+
274
+ Parameters
275
+ ----------
276
+ branches : GeoDataFrame
277
+ GeoDataFrame with branches
278
+ snap_method : str
279
+ Options for snapping
280
+ maxdist : float, optional
281
+ The maximal distance for snapping. The default is 5.
282
+
283
+ Returns
284
+ -------
285
+ None.
286
+
287
+ """
288
+
289
+ """Snap the geometries to the branch."""
290
+ geometry.find_nearest_branch(
291
+ branches=branches, geometries=self, method=snap_method, maxdist=maxdist
292
+ )
293
+
294
+
295
+ class HyDAMO:
296
+ """Definition of the HyDAMO datamodel."""
297
+
298
+ def __init__(
299
+ self,
300
+ version: str = "2.2",
301
+ schemas_path: Path = SCHEMAS_DIR,
302
+ ignored_layers: list[str] = [
303
+ "afvoeraanvoergebied",
304
+ "imwa_geoobject",
305
+ "leggerwatersysteem",
306
+ "leggerwaterveiligheid",
307
+ "waterbeheergebied",
308
+ ],
309
+ ):
310
+ self.version = version
311
+ self.schema_json = schemas_path.joinpath(f"HyDAMO_{version}.json")
312
+ self.layers: list[str] = []
313
+ self.ignored_layers = ignored_layers
314
+
315
+ self.init_datamodel()
316
+
317
+ @property
318
+ def data_layers(self):
319
+ return [layer for layer in self.layers if not getattr(self, layer).empty]
320
+
321
+ def init_datamodel(self) -> None:
322
+ """Initialize DataModel from self.schemas_path."""
323
+ self.validation_schemas: dict[str, Any] = {}
324
+
325
+ # read schema as dict
326
+ with open(self.schema_json) as src:
327
+ schema = json.load(src)
328
+ hydamo_layers = [
329
+ Path(i["$ref"]).name for i in schema["properties"]["HyDAMO"]["anyOf"]
330
+ ]
331
+ self.layers = [i for i in hydamo_layers if i not in self.ignored_layers]
332
+
333
+ for hydamo_layer in self.layers:
334
+ definition = schema["definitions"][hydamo_layer]["properties"]
335
+ layer_schema = map_definition(definition)
336
+ self.validation_schemas[hydamo_layer] = layer_schema
337
+
338
+ # add layer to data_model
339
+ geotype = next(
340
+ (i["dtype"] for i in layer_schema if i["id"] == "geometry"), None
341
+ )
342
+
343
+ required_columns = [
344
+ i["id"]
345
+ for i in [i for i in layer_schema if "required" in i.keys()]
346
+ if i["required"]
347
+ ]
348
+
349
+ setattr(
350
+ self,
351
+ hydamo_layer,
352
+ ExtendedGeoDataFrame(
353
+ validation_schema=layer_schema,
354
+ layer_name=hydamo_layer,
355
+ geotype=geotype,
356
+ required_columns=required_columns,
357
+ ),
358
+ )
359
+
360
+ def get(self, layer: str, global_id: str):
361
+ """
362
+ Get a DataFrame row (feature) providing a layer an global_id.
363
+
364
+ Parameters
365
+ ----------
366
+ layer : str
367
+ DESCRIPTION.
368
+ global_id : str
369
+ DESCRIPTION.
370
+
371
+ Returns
372
+ -------
373
+ TYPE
374
+ DESCRIPTION.
375
+
376
+ """
377
+ return getattr(self, layer).set_index("globalid").loc[global_id]
378
+
379
+ def set_data(
380
+ self,
381
+ gdf,
382
+ layer,
383
+ index_col=None,
384
+ check_columns=True,
385
+ check_geotype=True,
386
+ extra_attributes={},
387
+ ):
388
+ """
389
+
390
+
391
+ Parameters
392
+ ----------
393
+ gdf : GeoDataFrame
394
+ GeoDataFrame with a HyDAMO object-layer
395
+ layer : TYPE
396
+ HyDAMO layer to be set
397
+ index_col : str, optional
398
+ Column to be used as index. The default is None.
399
+ check_columns : bool, optional
400
+ Check if all required columns are present in the GeoDataFrame.
401
+ The default is True.
402
+ check_geotype : bool, optional
403
+ Check if the geometry is of the required type. The default is True.
404
+
405
+ Returns
406
+ -------
407
+ None.
408
+
409
+ """
410
+
411
+ getattr(self, layer).set_data(
412
+ gdf,
413
+ index_col=index_col,
414
+ check_columns=check_columns,
415
+ check_geotype=check_geotype,
416
+ extra_attributes={},
417
+ )
418
+
419
+ def to_geopackage(self, file_path, use_schema=True):
420
+ """
421
+
422
+ Parameters
423
+ ----------
424
+ file_path : path-string
425
+ Path-string where the file should be written to
426
+ use_schema : bool, optional
427
+ Use the schema to specify column-properties The default is True.
428
+
429
+ Returns
430
+ -------
431
+ None.
432
+
433
+ """
434
+ file_path = Path(file_path)
435
+ for layer in self.layers:
436
+ gdf = getattr(self, layer).copy()
437
+ if not gdf.empty:
438
+ if use_schema:
439
+ # match fiona layer schema keys with gdf.columns
440
+ schema = getattr(self, layer)._get_schema()
441
+ schema_cols = list(schema["properties"].keys()) + ["geometry"]
442
+ drop_cols = [i for i in gdf.columns if i not in schema_cols]
443
+ gdf.drop(columns=drop_cols, inplace=True)
444
+
445
+ schema["properties"] = {
446
+ k: v
447
+ for k, v in schema["properties"].items()
448
+ if k in gdf.columns
449
+ }
450
+
451
+ # write gdf to geopackage, including schema
452
+ if gdf.index.name in gdf.columns:
453
+ gdf.reset_index(drop=True, inplace=True)
454
+ gdf.to_file(
455
+ file_path,
456
+ layer=layer,
457
+ driver="GPKG",
458
+ engine="pyogrio",
459
+ )
460
+ else:
461
+ # write gdf to geopackage as is
462
+ if gdf.index.name in gdf.columns:
463
+ gdf = gdf.reset_index(drop=True).copy()
464
+ gdf.to_file(file_path, layer=layer, driver="GPKG", engine="pyogrio")
465
+ if file_path.is_file():
466
+ add_styles_to_geopackage(file_path)
467
+
468
+ @classmethod
469
+ def from_geopackage(
470
+ cls, file_path, version="2.2", check_columns=True, check_geotype=True
471
+ ):
472
+ """
473
+ Initialize HyDAMO class from GeoPackage
474
+
475
+ Parameters
476
+ ----------
477
+ file_path : path-string
478
+ Path-string to the hydamo GeoPackage
479
+ check_columns : bool, optional
480
+ Check if all required columns are present in the GeoDataFrame.
481
+ The default is True.
482
+ check_geotype : bool, optional
483
+ Check if the geometry is of the required type. The default is True.
484
+
485
+ Returns
486
+ -------
487
+ hydamo : HyDAMO
488
+ HyDAMO object initialized with content of GeoPackage
489
+
490
+ """
491
+ hydamo = cls(version=version)
492
+ for layer in fiona.listlayers(file_path):
493
+ if layer in hydamo.layers:
494
+ hydamo_layer = getattr(hydamo, layer)
495
+ hydamo_layer.set_data(
496
+ gpd.read_file(file_path, layer=layer),
497
+ check_columns=check_columns,
498
+ check_geotype=check_geotype,
499
+ )
500
+ return hydamo