flood-adapt 0.3.9__py3-none-any.whl → 0.3.11__py3-none-any.whl

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.
Files changed (100) hide show
  1. flood_adapt/__init__.py +26 -22
  2. flood_adapt/adapter/__init__.py +9 -9
  3. flood_adapt/adapter/fiat_adapter.py +1541 -1541
  4. flood_adapt/adapter/interface/hazard_adapter.py +70 -70
  5. flood_adapt/adapter/interface/impact_adapter.py +36 -36
  6. flood_adapt/adapter/interface/model_adapter.py +89 -89
  7. flood_adapt/adapter/interface/offshore.py +19 -19
  8. flood_adapt/adapter/sfincs_adapter.py +1853 -1848
  9. flood_adapt/adapter/sfincs_offshore.py +187 -193
  10. flood_adapt/config/config.py +248 -248
  11. flood_adapt/config/fiat.py +219 -219
  12. flood_adapt/config/gui.py +331 -331
  13. flood_adapt/config/sfincs.py +481 -336
  14. flood_adapt/config/site.py +129 -129
  15. flood_adapt/database_builder/database_builder.py +2210 -2210
  16. flood_adapt/database_builder/templates/default_units/imperial.toml +9 -9
  17. flood_adapt/database_builder/templates/default_units/metric.toml +9 -9
  18. flood_adapt/database_builder/templates/green_infra_table/green_infra_lookup_table.csv +10 -10
  19. flood_adapt/database_builder/templates/infographics/OSM/config_charts.toml +90 -90
  20. flood_adapt/database_builder/templates/infographics/OSM/config_people.toml +57 -57
  21. flood_adapt/database_builder/templates/infographics/OSM/config_risk_charts.toml +121 -121
  22. flood_adapt/database_builder/templates/infographics/OSM/config_roads.toml +65 -65
  23. flood_adapt/database_builder/templates/infographics/OSM/styles.css +45 -45
  24. flood_adapt/database_builder/templates/infographics/US_NSI/config_charts.toml +126 -126
  25. flood_adapt/database_builder/templates/infographics/US_NSI/config_people.toml +60 -60
  26. flood_adapt/database_builder/templates/infographics/US_NSI/config_risk_charts.toml +121 -121
  27. flood_adapt/database_builder/templates/infographics/US_NSI/config_roads.toml +65 -65
  28. flood_adapt/database_builder/templates/infographics/US_NSI/styles.css +45 -45
  29. flood_adapt/database_builder/templates/infometrics/OSM/metrics_additional_risk_configs.toml +4 -4
  30. flood_adapt/database_builder/templates/infometrics/OSM/with_SVI/infographic_metrics_config.toml +143 -143
  31. flood_adapt/database_builder/templates/infometrics/OSM/with_SVI/infographic_metrics_config_risk.toml +153 -153
  32. flood_adapt/database_builder/templates/infometrics/OSM/without_SVI/infographic_metrics_config.toml +127 -127
  33. flood_adapt/database_builder/templates/infometrics/OSM/without_SVI/infographic_metrics_config_risk.toml +57 -57
  34. flood_adapt/database_builder/templates/infometrics/US_NSI/metrics_additional_risk_configs.toml +4 -4
  35. flood_adapt/database_builder/templates/infometrics/US_NSI/with_SVI/infographic_metrics_config.toml +191 -191
  36. flood_adapt/database_builder/templates/infometrics/US_NSI/with_SVI/infographic_metrics_config_risk.toml +153 -153
  37. flood_adapt/database_builder/templates/infometrics/US_NSI/without_SVI/infographic_metrics_config.toml +178 -178
  38. flood_adapt/database_builder/templates/infometrics/US_NSI/without_SVI/infographic_metrics_config_risk.toml +57 -57
  39. flood_adapt/database_builder/templates/infometrics/mandatory_metrics_config.toml +9 -9
  40. flood_adapt/database_builder/templates/infometrics/mandatory_metrics_config_risk.toml +65 -65
  41. flood_adapt/database_builder/templates/output_layers/bin_colors.toml +5 -5
  42. flood_adapt/database_builder.py +16 -16
  43. flood_adapt/dbs_classes/__init__.py +21 -21
  44. flood_adapt/dbs_classes/database.py +533 -684
  45. flood_adapt/dbs_classes/dbs_benefit.py +77 -76
  46. flood_adapt/dbs_classes/dbs_event.py +61 -59
  47. flood_adapt/dbs_classes/dbs_measure.py +112 -111
  48. flood_adapt/dbs_classes/dbs_projection.py +34 -34
  49. flood_adapt/dbs_classes/dbs_scenario.py +137 -137
  50. flood_adapt/dbs_classes/dbs_static.py +274 -273
  51. flood_adapt/dbs_classes/dbs_strategy.py +130 -129
  52. flood_adapt/dbs_classes/dbs_template.py +279 -278
  53. flood_adapt/dbs_classes/interface/database.py +107 -139
  54. flood_adapt/dbs_classes/interface/element.py +121 -121
  55. flood_adapt/dbs_classes/interface/static.py +47 -47
  56. flood_adapt/flood_adapt.py +1229 -1178
  57. flood_adapt/misc/database_user.py +16 -16
  58. flood_adapt/misc/exceptions.py +22 -0
  59. flood_adapt/misc/log.py +183 -183
  60. flood_adapt/misc/path_builder.py +54 -54
  61. flood_adapt/misc/utils.py +185 -185
  62. flood_adapt/objects/__init__.py +82 -82
  63. flood_adapt/objects/benefits/benefits.py +61 -61
  64. flood_adapt/objects/events/event_factory.py +135 -135
  65. flood_adapt/objects/events/event_set.py +88 -84
  66. flood_adapt/objects/events/events.py +236 -234
  67. flood_adapt/objects/events/historical.py +58 -58
  68. flood_adapt/objects/events/hurricane.py +68 -67
  69. flood_adapt/objects/events/synthetic.py +46 -50
  70. flood_adapt/objects/forcing/__init__.py +92 -92
  71. flood_adapt/objects/forcing/csv.py +68 -68
  72. flood_adapt/objects/forcing/discharge.py +66 -66
  73. flood_adapt/objects/forcing/forcing.py +150 -150
  74. flood_adapt/objects/forcing/forcing_factory.py +182 -182
  75. flood_adapt/objects/forcing/meteo_handler.py +93 -93
  76. flood_adapt/objects/forcing/netcdf.py +40 -40
  77. flood_adapt/objects/forcing/plotting.py +453 -429
  78. flood_adapt/objects/forcing/rainfall.py +98 -98
  79. flood_adapt/objects/forcing/tide_gauge.py +191 -191
  80. flood_adapt/objects/forcing/time_frame.py +90 -90
  81. flood_adapt/objects/forcing/timeseries.py +564 -564
  82. flood_adapt/objects/forcing/unit_system.py +580 -580
  83. flood_adapt/objects/forcing/waterlevels.py +108 -108
  84. flood_adapt/objects/forcing/wind.py +124 -124
  85. flood_adapt/objects/measures/measure_factory.py +92 -92
  86. flood_adapt/objects/measures/measures.py +551 -529
  87. flood_adapt/objects/object_model.py +74 -68
  88. flood_adapt/objects/projections/projections.py +103 -103
  89. flood_adapt/objects/scenarios/scenarios.py +22 -22
  90. flood_adapt/objects/strategies/strategies.py +89 -89
  91. flood_adapt/workflows/benefit_runner.py +579 -554
  92. flood_adapt/workflows/floodmap.py +85 -85
  93. flood_adapt/workflows/impacts_integrator.py +85 -85
  94. flood_adapt/workflows/scenario_runner.py +70 -70
  95. {flood_adapt-0.3.9.dist-info → flood_adapt-0.3.11.dist-info}/LICENSE +674 -674
  96. {flood_adapt-0.3.9.dist-info → flood_adapt-0.3.11.dist-info}/METADATA +867 -865
  97. flood_adapt-0.3.11.dist-info/RECORD +140 -0
  98. flood_adapt-0.3.9.dist-info/RECORD +0 -139
  99. {flood_adapt-0.3.9.dist-info → flood_adapt-0.3.11.dist-info}/WHEEL +0 -0
  100. {flood_adapt-0.3.9.dist-info → flood_adapt-0.3.11.dist-info}/top_level.txt +0 -0
@@ -1,278 +1,279 @@
1
- import shutil
2
- from datetime import datetime
3
- from pathlib import Path
4
- from typing import Any, Optional, TypeVar
5
-
6
- import tomli
7
- import tomli_w
8
-
9
- from flood_adapt.dbs_classes.interface.database import IDatabase
10
- from flood_adapt.dbs_classes.interface.element import AbstractDatabaseElement
11
- from flood_adapt.objects.object_model import Object
12
-
13
- T_OBJECTMODEL = TypeVar("T_OBJECTMODEL", bound=Object)
14
-
15
-
16
- class DbsTemplate(AbstractDatabaseElement[T_OBJECTMODEL]):
17
- display_name: str
18
- dir_name: str
19
- _object_class: type[T_OBJECTMODEL]
20
-
21
- def __init__(
22
- self, database: IDatabase, standard_objects: Optional[list[str]] = None
23
- ):
24
- """Initialize any necessary attributes."""
25
- self._database = database
26
- self.input_path = database.input_path / self.dir_name
27
- self.output_path = database.output_path / self.dir_name
28
- self.standard_objects = standard_objects
29
-
30
- def get(self, name: str) -> T_OBJECTMODEL:
31
- """Return an object of the type of the database with the given name.
32
-
33
- Parameters
34
- ----------
35
- name : str
36
- name of the object to be returned
37
-
38
- Returns
39
- -------
40
- Object
41
- object of the type of the specified object model
42
- """
43
- # Make the full path to the object
44
- full_path = self.input_path / name / f"{name}.toml"
45
-
46
- # Check if the object exists
47
- if not Path(full_path).is_file():
48
- raise ValueError(f"{self.display_name}: '{name}' does not exist.")
49
-
50
- # Load and return the object
51
- return self._object_class.load_file(full_path)
52
-
53
- def summarize_objects(self) -> dict[str, list[Any]]:
54
- """Return a dictionary with info on the objects that currently exist in the database.
55
-
56
- Returns
57
- -------
58
- dict[str, list[Any]]
59
- A dictionary that contains the keys: `name`, `description`, `path` and `last_modification_date`.
60
- Each key has a list of the corresponding values, where the index of the values corresponds to the same object.
61
- """
62
- return self._get_object_summary()
63
-
64
- def copy(self, old_name: str, new_name: str, new_description: str):
65
- """Copy (duplicate) an existing object, and give it a new name.
66
-
67
- Parameters
68
- ----------
69
- old_name : str
70
- name of the existing measure
71
- new_name : str
72
- name of the new measure
73
- new_description : str
74
- description of the new measure
75
- """
76
- copy_object = self.get(old_name)
77
- copy_object.name = new_name
78
- copy_object.description = new_description
79
-
80
- # After changing the name and description, re-trigger the validators
81
- copy_object.model_validate(copy_object)
82
-
83
- # Checking whether the new name is already in use
84
- self._validate_to_save(copy_object, overwrite=False)
85
-
86
- # Write only the toml file
87
- toml_path = self.input_path / new_name / f"{new_name}.toml"
88
- toml_path.parent.mkdir(parents=True)
89
- with open(toml_path, "wb") as f:
90
- tomli_w.dump(copy_object.model_dump(exclude_none=True), f)
91
-
92
- # Then copy all the accompanied files
93
- src = self.input_path / old_name
94
- dest = self.input_path / new_name
95
-
96
- EXCLUDE = [".spw", ".toml"]
97
- for file in src.glob("*"):
98
- if file.suffix in EXCLUDE:
99
- continue
100
- if file.is_dir():
101
- shutil.copytree(file, dest / file.name, dirs_exist_ok=True)
102
- else:
103
- shutil.copy2(file, dest / file.name)
104
-
105
- def save(
106
- self,
107
- object_model: T_OBJECTMODEL,
108
- overwrite: bool = False,
109
- ):
110
- """Save an object in the database and all associated files.
111
-
112
- This saves the toml file and any additional files attached to the object.
113
-
114
- Parameters
115
- ----------
116
- object_model : Object
117
- object to be saved in the database
118
- overwrite : bool, optional
119
- whether to overwrite the object if it already exists in the
120
- database, by default False
121
-
122
- Raises
123
- ------
124
- ValueError
125
- Raise error if name is already in use.
126
- """
127
- self._validate_to_save(object_model, overwrite=overwrite)
128
-
129
- # If the folder doesnt exist yet, make the folder and save the object
130
- if not (self.input_path / object_model.name).exists():
131
- (self.input_path / object_model.name).mkdir()
132
-
133
- # Save the object and any additional files
134
- object_model.save(
135
- self.input_path / object_model.name / f"{object_model.name}.toml",
136
- )
137
-
138
- def delete(self, name: str, toml_only: bool = False):
139
- """Delete an already existing object in the database.
140
-
141
- Parameters
142
- ----------
143
- name : str
144
- name of the object to be deleted
145
- toml_only : bool, optional
146
- whether to only delete the toml file or the entire folder. If the folder is empty after deleting the toml,
147
- it will always be deleted. By default False
148
-
149
- Raises
150
- ------
151
- ValueError
152
- Raise error if object to be deleted is already in use.
153
- """
154
- # Check if the object is a standard object. If it is, raise an error
155
- if self._check_standard_objects(name):
156
- raise ValueError(
157
- f"'{name}' cannot be deleted/modified since it is a standard {self.display_name}."
158
- )
159
-
160
- # Check if object is used in a higher level object. If it is, raise an error
161
- if used_in := self.check_higher_level_usage(name):
162
- raise ValueError(
163
- f"{self.display_name}: '{name}' cannot be deleted/modified since it is already used in: {', '.join(used_in)}"
164
- )
165
-
166
- # Once all checks are passed, delete the object
167
- toml_path = self.input_path / name / f"{name}.toml"
168
- if toml_only:
169
- # Only delete the toml file
170
- toml_path.unlink(missing_ok=True)
171
- # If the folder is empty, delete the folder
172
- if not list(toml_path.parent.iterdir()):
173
- toml_path.parent.rmdir()
174
- else:
175
- # Delete the entire folder
176
- shutil.rmtree(toml_path.parent, ignore_errors=True)
177
- if (self.output_path / name).exists():
178
- shutil.rmtree(self.output_path / name, ignore_errors=True)
179
-
180
- def _check_standard_objects(self, name: str) -> bool:
181
- """Check if an object is a standard object.
182
-
183
- Parameters
184
- ----------
185
- name : str
186
- name of the object to be checked
187
-
188
- Returns
189
- -------
190
- bool
191
- True if the object is a standard object, False otherwise
192
- """
193
- if self.standard_objects:
194
- return name in self.standard_objects
195
- return False
196
-
197
- def check_higher_level_usage(self, name: str) -> list[str]:
198
- """Check if an object is used in a higher level object.
199
-
200
- Parameters
201
- ----------
202
- name : str
203
- name of the object to be checked
204
-
205
- Returns
206
- -------
207
- list[str]
208
- list of higher level objects that use the object
209
- """
210
- # If this function is not implemented for the object type, it cannot be used in a higher
211
- # level object. By default, return an empty list
212
- return []
213
-
214
- def _get_object_summary(self) -> dict[str, list[Any]]:
215
- """Get a dictionary with all the toml paths and last modification dates that exist in the database of the given object_type.
216
-
217
- Returns
218
- -------
219
- dict[str, Any]
220
- A dictionary that contains the keys: `name`, `description`, `path` and `last_modification_date`.
221
- Each key has a list of the corresponding values, where the index of the values corresponds to the same object.
222
- """
223
- # If the toml doesnt exist, we might be in the middle of saving a new object or could be a broken object.
224
- # In any case, we should not list it in the database
225
- directories = [
226
- dir
227
- for dir in self.input_path.iterdir()
228
- if (dir / f"{dir.name}.toml").is_file()
229
- ]
230
- paths = [Path(dir / f"{dir.name}.toml") for dir in directories]
231
-
232
- names = [self._read_variable_in_toml("name", path) for path in paths]
233
- descriptions = [
234
- self._read_variable_in_toml("description", path) for path in paths
235
- ]
236
-
237
- last_modification_date = [
238
- datetime.fromtimestamp(file.stat().st_mtime) for file in paths
239
- ]
240
-
241
- objects = {
242
- "name": names,
243
- "description": descriptions,
244
- "path": paths,
245
- "last_modification_date": last_modification_date,
246
- }
247
- return objects
248
-
249
- @staticmethod
250
- def _read_variable_in_toml(variable_name: str, toml_path: Path) -> str:
251
- with open(toml_path, "rb") as f:
252
- data = tomli.load(f)
253
- return data.get(variable_name, "")
254
-
255
- def _validate_to_save(self, object_model: T_OBJECTMODEL, overwrite: bool) -> None:
256
- """Validate if the object can be saved.
257
-
258
- Parameters
259
- ----------
260
- object_model : Object
261
- object to be validated
262
-
263
- Raises
264
- ------
265
- ValueError
266
- Raise error if name is already in use.
267
- """
268
- # Check if the object exists
269
- object_exists = object_model.name in self.summarize_objects()["name"]
270
-
271
- # If you want to overwrite the object, and the object already exists, first delete it. If it exists and you
272
- # don't want to overwrite, raise an error.
273
- if overwrite and object_exists:
274
- self.delete(object_model.name, toml_only=True)
275
- elif not overwrite and object_exists:
276
- raise ValueError(
277
- f"'{object_model.name}' name is already used by another {self.display_name.lower()}. Choose a different name"
278
- )
1
+ import shutil
2
+ from datetime import datetime
3
+ from pathlib import Path
4
+ from typing import Any, Optional, TypeVar
5
+
6
+ import tomli
7
+ import tomli_w
8
+
9
+ from flood_adapt.dbs_classes.interface.database import IDatabase
10
+ from flood_adapt.dbs_classes.interface.element import AbstractDatabaseElement
11
+ from flood_adapt.misc.exceptions import DatabaseError
12
+ from flood_adapt.objects.object_model import Object
13
+
14
+ T_OBJECTMODEL = TypeVar("T_OBJECTMODEL", bound=Object)
15
+
16
+
17
+ class DbsTemplate(AbstractDatabaseElement[T_OBJECTMODEL]):
18
+ display_name: str
19
+ dir_name: str
20
+ _object_class: type[T_OBJECTMODEL]
21
+
22
+ def __init__(
23
+ self, database: IDatabase, standard_objects: Optional[list[str]] = None
24
+ ):
25
+ """Initialize any necessary attributes."""
26
+ self._database = database
27
+ self.input_path = database.input_path / self.dir_name
28
+ self.output_path = database.output_path / self.dir_name
29
+ self.standard_objects = standard_objects
30
+
31
+ def get(self, name: str) -> T_OBJECTMODEL:
32
+ """Return an object of the type of the database with the given name.
33
+
34
+ Parameters
35
+ ----------
36
+ name : str
37
+ name of the object to be returned
38
+
39
+ Returns
40
+ -------
41
+ Object
42
+ object of the type of the specified object model
43
+ """
44
+ # Make the full path to the object
45
+ full_path = self.input_path / name / f"{name}.toml"
46
+
47
+ # Check if the object exists
48
+ if not Path(full_path).is_file():
49
+ raise DatabaseError(f"{self.display_name}: '{name}' does not exist.")
50
+
51
+ # Load and return the object
52
+ return self._object_class.load_file(full_path)
53
+
54
+ def summarize_objects(self) -> dict[str, list[Any]]:
55
+ """Return a dictionary with info on the objects that currently exist in the database.
56
+
57
+ Returns
58
+ -------
59
+ dict[str, list[Any]]
60
+ A dictionary that contains the keys: `name`, `description`, `path` and `last_modification_date`.
61
+ Each key has a list of the corresponding values, where the index of the values corresponds to the same object.
62
+ """
63
+ return self._get_object_summary()
64
+
65
+ def copy(self, old_name: str, new_name: str, new_description: str):
66
+ """Copy (duplicate) an existing object, and give it a new name.
67
+
68
+ Parameters
69
+ ----------
70
+ old_name : str
71
+ name of the existing measure
72
+ new_name : str
73
+ name of the new measure
74
+ new_description : str
75
+ description of the new measure
76
+ """
77
+ copy_object = self.get(old_name)
78
+ copy_object.name = new_name
79
+ copy_object.description = new_description
80
+
81
+ # After changing the name and description, re-trigger the validators
82
+ copy_object.model_validate(copy_object)
83
+
84
+ # Checking whether the new name is already in use
85
+ self._validate_to_save(copy_object, overwrite=False)
86
+
87
+ # Write only the toml file
88
+ toml_path = self.input_path / new_name / f"{new_name}.toml"
89
+ toml_path.parent.mkdir(parents=True)
90
+ with open(toml_path, "wb") as f:
91
+ tomli_w.dump(copy_object.model_dump(exclude_none=True), f)
92
+
93
+ # Then copy all the accompanied files
94
+ src = self.input_path / old_name
95
+ dest = self.input_path / new_name
96
+
97
+ EXCLUDE = [".spw", ".toml"]
98
+ for file in src.glob("*"):
99
+ if file.suffix in EXCLUDE:
100
+ continue
101
+ if file.is_dir():
102
+ shutil.copytree(file, dest / file.name, dirs_exist_ok=True)
103
+ else:
104
+ shutil.copy2(file, dest / file.name)
105
+
106
+ def save(
107
+ self,
108
+ object_model: T_OBJECTMODEL,
109
+ overwrite: bool = False,
110
+ ):
111
+ """Save an object in the database and all associated files.
112
+
113
+ This saves the toml file and any additional files attached to the object.
114
+
115
+ Parameters
116
+ ----------
117
+ object_model : Object
118
+ object to be saved in the database
119
+ overwrite : bool, optional
120
+ whether to overwrite the object if it already exists in the
121
+ database, by default False
122
+
123
+ Raises
124
+ ------
125
+ DatabaseError
126
+ Raise error if name is already in use.
127
+ """
128
+ self._validate_to_save(object_model, overwrite=overwrite)
129
+
130
+ # If the folder doesnt exist yet, make the folder and save the object
131
+ if not (self.input_path / object_model.name).exists():
132
+ (self.input_path / object_model.name).mkdir()
133
+
134
+ # Save the object and any additional files
135
+ object_model.save(
136
+ self.input_path / object_model.name / f"{object_model.name}.toml",
137
+ )
138
+
139
+ def delete(self, name: str, toml_only: bool = False):
140
+ """Delete an already existing object in the database.
141
+
142
+ Parameters
143
+ ----------
144
+ name : str
145
+ name of the object to be deleted
146
+ toml_only : bool, optional
147
+ whether to only delete the toml file or the entire folder. If the folder is empty after deleting the toml,
148
+ it will always be deleted. By default False
149
+
150
+ Raises
151
+ ------
152
+ DatabaseError
153
+ Raise error if object to be deleted is already in use.
154
+ """
155
+ # Check if the object is a standard object. If it is, raise an error
156
+ if self._check_standard_objects(name):
157
+ raise DatabaseError(
158
+ f"'{name}' cannot be deleted/modified since it is a standard {self.display_name}."
159
+ )
160
+
161
+ # Check if object is used in a higher level object. If it is, raise an error
162
+ if used_in := self.check_higher_level_usage(name):
163
+ raise DatabaseError(
164
+ f"{self.display_name}: '{name}' cannot be deleted/modified since it is already used in: {', '.join(used_in)}"
165
+ )
166
+
167
+ # Once all checks are passed, delete the object
168
+ toml_path = self.input_path / name / f"{name}.toml"
169
+ if toml_only:
170
+ # Only delete the toml file
171
+ toml_path.unlink(missing_ok=True)
172
+ # If the folder is empty, delete the folder
173
+ if not list(toml_path.parent.iterdir()):
174
+ toml_path.parent.rmdir()
175
+ else:
176
+ # Delete the entire folder
177
+ shutil.rmtree(toml_path.parent, ignore_errors=True)
178
+ if (self.output_path / name).exists():
179
+ shutil.rmtree(self.output_path / name, ignore_errors=True)
180
+
181
+ def _check_standard_objects(self, name: str) -> bool:
182
+ """Check if an object is a standard object.
183
+
184
+ Parameters
185
+ ----------
186
+ name : str
187
+ name of the object to be checked
188
+
189
+ Returns
190
+ -------
191
+ bool
192
+ True if the object is a standard object, False otherwise
193
+ """
194
+ if self.standard_objects:
195
+ return name in self.standard_objects
196
+ return False
197
+
198
+ def check_higher_level_usage(self, name: str) -> list[str]:
199
+ """Check if an object is used in a higher level object.
200
+
201
+ Parameters
202
+ ----------
203
+ name : str
204
+ name of the object to be checked
205
+
206
+ Returns
207
+ -------
208
+ list[str]
209
+ list of higher level objects that use the object
210
+ """
211
+ # If this function is not implemented for the object type, it cannot be used in a higher
212
+ # level object. By default, return an empty list
213
+ return []
214
+
215
+ def _get_object_summary(self) -> dict[str, list[Any]]:
216
+ """Get a dictionary with all the toml paths and last modification dates that exist in the database of the given object_type.
217
+
218
+ Returns
219
+ -------
220
+ dict[str, Any]
221
+ A dictionary that contains the keys: `name`, `description`, `path` and `last_modification_date`.
222
+ Each key has a list of the corresponding values, where the index of the values corresponds to the same object.
223
+ """
224
+ # If the toml doesnt exist, we might be in the middle of saving a new object or could be a broken object.
225
+ # In any case, we should not list it in the database
226
+ directories = [
227
+ dir
228
+ for dir in self.input_path.iterdir()
229
+ if (dir / f"{dir.name}.toml").is_file()
230
+ ]
231
+ paths = [Path(dir / f"{dir.name}.toml") for dir in directories]
232
+
233
+ names = [self._read_variable_in_toml("name", path) for path in paths]
234
+ descriptions = [
235
+ self._read_variable_in_toml("description", path) for path in paths
236
+ ]
237
+
238
+ last_modification_date = [
239
+ datetime.fromtimestamp(file.stat().st_mtime) for file in paths
240
+ ]
241
+
242
+ objects = {
243
+ "name": names,
244
+ "description": descriptions,
245
+ "path": paths,
246
+ "last_modification_date": last_modification_date,
247
+ }
248
+ return objects
249
+
250
+ @staticmethod
251
+ def _read_variable_in_toml(variable_name: str, toml_path: Path) -> str:
252
+ with open(toml_path, "rb") as f:
253
+ data = tomli.load(f)
254
+ return data.get(variable_name, "")
255
+
256
+ def _validate_to_save(self, object_model: T_OBJECTMODEL, overwrite: bool) -> None:
257
+ """Validate if the object can be saved.
258
+
259
+ Parameters
260
+ ----------
261
+ object_model : Object
262
+ object to be validated
263
+
264
+ Raises
265
+ ------
266
+ DatabaseError
267
+ Raise error if name is already in use.
268
+ """
269
+ # Check if the object exists
270
+ object_exists = object_model.name in self.summarize_objects()["name"]
271
+
272
+ # If you want to overwrite the object, and the object already exists, first delete it. If it exists and you
273
+ # don't want to overwrite, raise an error.
274
+ if overwrite and object_exists:
275
+ self.delete(object_model.name, toml_only=True)
276
+ elif not overwrite and object_exists:
277
+ raise DatabaseError(
278
+ f"'{object_model.name}' name is already used by another {self.display_name.lower()}. Choose a different name"
279
+ )