flood-adapt 0.3.9__py3-none-any.whl → 0.3.10__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.
- flood_adapt/__init__.py +26 -22
- flood_adapt/adapter/__init__.py +9 -9
- flood_adapt/adapter/fiat_adapter.py +1541 -1541
- flood_adapt/adapter/interface/hazard_adapter.py +70 -70
- flood_adapt/adapter/interface/impact_adapter.py +36 -36
- flood_adapt/adapter/interface/model_adapter.py +89 -89
- flood_adapt/adapter/interface/offshore.py +19 -19
- flood_adapt/adapter/sfincs_adapter.py +1848 -1848
- flood_adapt/adapter/sfincs_offshore.py +193 -193
- flood_adapt/config/config.py +248 -248
- flood_adapt/config/fiat.py +219 -219
- flood_adapt/config/gui.py +331 -331
- flood_adapt/config/sfincs.py +481 -336
- flood_adapt/config/site.py +129 -129
- flood_adapt/database_builder/database_builder.py +2210 -2210
- flood_adapt/database_builder/templates/default_units/imperial.toml +9 -9
- flood_adapt/database_builder/templates/default_units/metric.toml +9 -9
- flood_adapt/database_builder/templates/green_infra_table/green_infra_lookup_table.csv +10 -10
- flood_adapt/database_builder/templates/infographics/OSM/config_charts.toml +90 -90
- flood_adapt/database_builder/templates/infographics/OSM/config_people.toml +57 -57
- flood_adapt/database_builder/templates/infographics/OSM/config_risk_charts.toml +121 -121
- flood_adapt/database_builder/templates/infographics/OSM/config_roads.toml +65 -65
- flood_adapt/database_builder/templates/infographics/OSM/styles.css +45 -45
- flood_adapt/database_builder/templates/infographics/US_NSI/config_charts.toml +126 -126
- flood_adapt/database_builder/templates/infographics/US_NSI/config_people.toml +60 -60
- flood_adapt/database_builder/templates/infographics/US_NSI/config_risk_charts.toml +121 -121
- flood_adapt/database_builder/templates/infographics/US_NSI/config_roads.toml +65 -65
- flood_adapt/database_builder/templates/infographics/US_NSI/styles.css +45 -45
- flood_adapt/database_builder/templates/infometrics/OSM/metrics_additional_risk_configs.toml +4 -4
- flood_adapt/database_builder/templates/infometrics/OSM/with_SVI/infographic_metrics_config.toml +143 -143
- flood_adapt/database_builder/templates/infometrics/OSM/with_SVI/infographic_metrics_config_risk.toml +153 -153
- flood_adapt/database_builder/templates/infometrics/OSM/without_SVI/infographic_metrics_config.toml +127 -127
- flood_adapt/database_builder/templates/infometrics/OSM/without_SVI/infographic_metrics_config_risk.toml +57 -57
- flood_adapt/database_builder/templates/infometrics/US_NSI/metrics_additional_risk_configs.toml +4 -4
- flood_adapt/database_builder/templates/infometrics/US_NSI/with_SVI/infographic_metrics_config.toml +191 -191
- flood_adapt/database_builder/templates/infometrics/US_NSI/with_SVI/infographic_metrics_config_risk.toml +153 -153
- flood_adapt/database_builder/templates/infometrics/US_NSI/without_SVI/infographic_metrics_config.toml +178 -178
- flood_adapt/database_builder/templates/infometrics/US_NSI/without_SVI/infographic_metrics_config_risk.toml +57 -57
- flood_adapt/database_builder/templates/infometrics/mandatory_metrics_config.toml +9 -9
- flood_adapt/database_builder/templates/infometrics/mandatory_metrics_config_risk.toml +65 -65
- flood_adapt/database_builder/templates/output_layers/bin_colors.toml +5 -5
- flood_adapt/database_builder.py +16 -16
- flood_adapt/dbs_classes/__init__.py +21 -21
- flood_adapt/dbs_classes/database.py +495 -684
- flood_adapt/dbs_classes/dbs_benefit.py +77 -76
- flood_adapt/dbs_classes/dbs_event.py +61 -59
- flood_adapt/dbs_classes/dbs_measure.py +112 -111
- flood_adapt/dbs_classes/dbs_projection.py +34 -34
- flood_adapt/dbs_classes/dbs_scenario.py +137 -137
- flood_adapt/dbs_classes/dbs_static.py +274 -273
- flood_adapt/dbs_classes/dbs_strategy.py +130 -129
- flood_adapt/dbs_classes/dbs_template.py +279 -278
- flood_adapt/dbs_classes/interface/database.py +107 -139
- flood_adapt/dbs_classes/interface/element.py +121 -121
- flood_adapt/dbs_classes/interface/static.py +47 -47
- flood_adapt/flood_adapt.py +1207 -1178
- flood_adapt/misc/database_user.py +16 -16
- flood_adapt/misc/exceptions.py +22 -0
- flood_adapt/misc/log.py +183 -183
- flood_adapt/misc/path_builder.py +54 -54
- flood_adapt/misc/utils.py +185 -185
- flood_adapt/objects/__init__.py +82 -82
- flood_adapt/objects/benefits/benefits.py +61 -61
- flood_adapt/objects/events/event_factory.py +135 -135
- flood_adapt/objects/events/event_set.py +88 -84
- flood_adapt/objects/events/events.py +234 -234
- flood_adapt/objects/events/historical.py +58 -58
- flood_adapt/objects/events/hurricane.py +68 -67
- flood_adapt/objects/events/synthetic.py +46 -50
- flood_adapt/objects/forcing/__init__.py +92 -92
- flood_adapt/objects/forcing/csv.py +68 -68
- flood_adapt/objects/forcing/discharge.py +66 -66
- flood_adapt/objects/forcing/forcing.py +150 -150
- flood_adapt/objects/forcing/forcing_factory.py +182 -182
- flood_adapt/objects/forcing/meteo_handler.py +93 -93
- flood_adapt/objects/forcing/netcdf.py +40 -40
- flood_adapt/objects/forcing/plotting.py +453 -429
- flood_adapt/objects/forcing/rainfall.py +98 -98
- flood_adapt/objects/forcing/tide_gauge.py +191 -191
- flood_adapt/objects/forcing/time_frame.py +90 -90
- flood_adapt/objects/forcing/timeseries.py +564 -564
- flood_adapt/objects/forcing/unit_system.py +580 -580
- flood_adapt/objects/forcing/waterlevels.py +108 -108
- flood_adapt/objects/forcing/wind.py +124 -124
- flood_adapt/objects/measures/measure_factory.py +92 -92
- flood_adapt/objects/measures/measures.py +529 -529
- flood_adapt/objects/object_model.py +74 -68
- flood_adapt/objects/projections/projections.py +103 -103
- flood_adapt/objects/scenarios/scenarios.py +22 -22
- flood_adapt/objects/strategies/strategies.py +89 -89
- flood_adapt/workflows/benefit_runner.py +579 -554
- flood_adapt/workflows/floodmap.py +85 -85
- flood_adapt/workflows/impacts_integrator.py +85 -85
- flood_adapt/workflows/scenario_runner.py +70 -70
- {flood_adapt-0.3.9.dist-info → flood_adapt-0.3.10.dist-info}/LICENSE +674 -674
- {flood_adapt-0.3.9.dist-info → flood_adapt-0.3.10.dist-info}/METADATA +866 -865
- flood_adapt-0.3.10.dist-info/RECORD +140 -0
- flood_adapt-0.3.9.dist-info/RECORD +0 -139
- {flood_adapt-0.3.9.dist-info → flood_adapt-0.3.10.dist-info}/WHEEL +0 -0
- {flood_adapt-0.3.9.dist-info → flood_adapt-0.3.10.dist-info}/top_level.txt +0 -0
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
from abc import ABC
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class DatabaseUser(ABC):
|
|
5
|
-
"""Abstract class for FloodAdapt classes that need to use / interact with the Singleton FloodAdapt database through the lazy-loading self.database property."""
|
|
6
|
-
|
|
7
|
-
_database_instance = None
|
|
8
|
-
|
|
9
|
-
@property
|
|
10
|
-
def database(self):
|
|
11
|
-
"""Return the database for the object."""
|
|
12
|
-
if self._database_instance is None:
|
|
13
|
-
from flood_adapt.dbs_classes.database import Database
|
|
14
|
-
|
|
15
|
-
self._database_instance = Database()
|
|
16
|
-
return self._database_instance
|
|
1
|
+
from abc import ABC
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class DatabaseUser(ABC):
|
|
5
|
+
"""Abstract class for FloodAdapt classes that need to use / interact with the Singleton FloodAdapt database through the lazy-loading self.database property."""
|
|
6
|
+
|
|
7
|
+
_database_instance = None
|
|
8
|
+
|
|
9
|
+
@property
|
|
10
|
+
def database(self):
|
|
11
|
+
"""Return the database for the object."""
|
|
12
|
+
if self._database_instance is None:
|
|
13
|
+
from flood_adapt.dbs_classes.database import Database
|
|
14
|
+
|
|
15
|
+
self._database_instance = Database()
|
|
16
|
+
return self._database_instance
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
class FloodAdaptError(Exception):
|
|
2
|
+
"""Base class for all exceptions in the FloodAdapt module."""
|
|
3
|
+
|
|
4
|
+
pass
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class DatabaseError(FloodAdaptError):
|
|
8
|
+
"""Base class for exceptions raised in any database related files."""
|
|
9
|
+
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ComponentError(FloodAdaptError):
|
|
14
|
+
"""Base class for exceptions raised in any component/object related files."""
|
|
15
|
+
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class WorkflowError(FloodAdaptError):
|
|
20
|
+
"""Base class for exceptions raised in any workflow related files."""
|
|
21
|
+
|
|
22
|
+
pass
|
flood_adapt/misc/log.py
CHANGED
|
@@ -1,183 +1,183 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
import warnings
|
|
3
|
-
from contextlib import contextmanager
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
from typing import List, Optional
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class FloodAdaptLogging:
|
|
9
|
-
_DEFAULT_FORMATTER = logging.Formatter(
|
|
10
|
-
fmt="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
|
11
|
-
datefmt="%Y-%m-%d %I:%M:%S %p",
|
|
12
|
-
)
|
|
13
|
-
_root_logger = logging.getLogger("FloodAdapt")
|
|
14
|
-
|
|
15
|
-
def __init__(
|
|
16
|
-
self,
|
|
17
|
-
file_path: Optional[Path] = None,
|
|
18
|
-
loglevel_console: int = logging.WARNING,
|
|
19
|
-
loglevel_root: int = logging.INFO,
|
|
20
|
-
loglevel_files: int = logging.DEBUG,
|
|
21
|
-
formatter: logging.Formatter = _DEFAULT_FORMATTER,
|
|
22
|
-
ignore_warnings: Optional[list[type[Warning]]] = None,
|
|
23
|
-
) -> None:
|
|
24
|
-
"""Initialize the logging system for the FloodAdapt."""
|
|
25
|
-
self._formatter = formatter
|
|
26
|
-
|
|
27
|
-
self._root_logger.setLevel(loglevel_root)
|
|
28
|
-
if self._root_logger.hasHandlers():
|
|
29
|
-
self._root_logger.handlers.clear()
|
|
30
|
-
|
|
31
|
-
# Add file handler if provided
|
|
32
|
-
if file_path is not None:
|
|
33
|
-
self.add_file_handler(file_path, loglevel_files, formatter)
|
|
34
|
-
|
|
35
|
-
# Add console handler
|
|
36
|
-
console_handler = logging.StreamHandler()
|
|
37
|
-
console_handler.setLevel(loglevel_console)
|
|
38
|
-
console_handler.setFormatter(formatter)
|
|
39
|
-
self._root_logger.addHandler(console_handler)
|
|
40
|
-
|
|
41
|
-
if ignore_warnings:
|
|
42
|
-
for warn_type in ignore_warnings:
|
|
43
|
-
self.configure_warnings("ignore", category=warn_type)
|
|
44
|
-
|
|
45
|
-
@classmethod
|
|
46
|
-
def add_file_handler(
|
|
47
|
-
cls,
|
|
48
|
-
file_path: Path,
|
|
49
|
-
loglevel: int = logging.DEBUG,
|
|
50
|
-
formatter: Optional[logging.Formatter] = None,
|
|
51
|
-
) -> None:
|
|
52
|
-
"""Add a file handler to the logger that directs outputs to a the file."""
|
|
53
|
-
if not file_path:
|
|
54
|
-
raise ValueError("file_path must be provided.")
|
|
55
|
-
file_path = Path(file_path)
|
|
56
|
-
|
|
57
|
-
# check if the path is a only a filename
|
|
58
|
-
if not file_path.parents:
|
|
59
|
-
file_path = Path.cwd() / file_path
|
|
60
|
-
file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
61
|
-
|
|
62
|
-
file_handler = logging.FileHandler(filename=file_path, mode="a")
|
|
63
|
-
file_handler.setLevel(loglevel)
|
|
64
|
-
|
|
65
|
-
formatter = formatter or cls._DEFAULT_FORMATTER
|
|
66
|
-
file_handler.setFormatter(formatter)
|
|
67
|
-
|
|
68
|
-
cls.getLogger().addHandler(file_handler)
|
|
69
|
-
|
|
70
|
-
@classmethod
|
|
71
|
-
def remove_file_handler(cls, file_path: Path) -> None:
|
|
72
|
-
"""Remove a file handler from the logger, which stops sending logs to that file and closes it."""
|
|
73
|
-
for handler in cls.getLogger().handlers:
|
|
74
|
-
if isinstance(handler, logging.FileHandler) and handler.baseFilename == str(
|
|
75
|
-
file_path.resolve()
|
|
76
|
-
):
|
|
77
|
-
handler.close()
|
|
78
|
-
cls.getLogger().removeHandler(handler)
|
|
79
|
-
|
|
80
|
-
@classmethod
|
|
81
|
-
def getLogger(
|
|
82
|
-
cls, name: Optional[str] = None, level: int = logging.INFO
|
|
83
|
-
) -> logging.Logger:
|
|
84
|
-
"""Get a logger with the specified name. If no name is provided, return the root logger.
|
|
85
|
-
|
|
86
|
-
If the logger does not exist, it is created with the specified level.
|
|
87
|
-
|
|
88
|
-
Parameters
|
|
89
|
-
----------
|
|
90
|
-
name : str, optional
|
|
91
|
-
The name of the logger. If not provided, the root logger is returned.
|
|
92
|
-
level : int,
|
|
93
|
-
The level of the logger. The default is logging.INFO.
|
|
94
|
-
|
|
95
|
-
Returns
|
|
96
|
-
-------
|
|
97
|
-
logging.Logger
|
|
98
|
-
The logger with the specified name.
|
|
99
|
-
"""
|
|
100
|
-
if name is None:
|
|
101
|
-
logger = cls._root_logger
|
|
102
|
-
else:
|
|
103
|
-
logger = logging.getLogger(f"FloodAdapt.{name}")
|
|
104
|
-
logger.setLevel(level)
|
|
105
|
-
return logger
|
|
106
|
-
|
|
107
|
-
@classmethod
|
|
108
|
-
def shutdown(cls):
|
|
109
|
-
root_logger = cls.getLogger()
|
|
110
|
-
handlers = root_logger.handlers[:]
|
|
111
|
-
for handler in handlers:
|
|
112
|
-
if isinstance(handler, logging.FileHandler):
|
|
113
|
-
handler.close()
|
|
114
|
-
root_logger.removeHandler(handler)
|
|
115
|
-
logging.shutdown()
|
|
116
|
-
|
|
117
|
-
@classmethod
|
|
118
|
-
@contextmanager
|
|
119
|
-
def to_file(
|
|
120
|
-
cls,
|
|
121
|
-
*,
|
|
122
|
-
file_path: Path,
|
|
123
|
-
loglevel: int = logging.DEBUG,
|
|
124
|
-
formatter: logging.Formatter = _DEFAULT_FORMATTER,
|
|
125
|
-
):
|
|
126
|
-
"""Open a file at filepath to write logs to. Does not affect other loggers.
|
|
127
|
-
|
|
128
|
-
When the context manager exits (via regular execution or an exception), the file is closed and the handler is removed.
|
|
129
|
-
"""
|
|
130
|
-
if file_path is None:
|
|
131
|
-
raise ValueError(
|
|
132
|
-
"file_path must be provided as a key value pair: 'file_path=<file_path>'."
|
|
133
|
-
)
|
|
134
|
-
cls.add_file_handler(file_path, loglevel, formatter)
|
|
135
|
-
try:
|
|
136
|
-
yield
|
|
137
|
-
finally:
|
|
138
|
-
cls.remove_file_handler(file_path)
|
|
139
|
-
|
|
140
|
-
@classmethod
|
|
141
|
-
def _close_file_handlers(cls, logger: logging.Logger, exclude: List[Path]) -> None:
|
|
142
|
-
"""Close and remove file handlers from a logger."""
|
|
143
|
-
for handler in logger.handlers[:]:
|
|
144
|
-
if (
|
|
145
|
-
isinstance(handler, logging.FileHandler)
|
|
146
|
-
and Path(handler.baseFilename) not in exclude
|
|
147
|
-
):
|
|
148
|
-
handler.close()
|
|
149
|
-
logger.removeHandler(handler)
|
|
150
|
-
|
|
151
|
-
@classmethod
|
|
152
|
-
def close_files(cls, exclude: List[Path] = []) -> None:
|
|
153
|
-
"""Close all file handlers except those in the exclude list."""
|
|
154
|
-
cls._close_file_handlers(cls.getLogger(), exclude)
|
|
155
|
-
cls._close_file_handlers(cls.getLogger("hydromt"), exclude)
|
|
156
|
-
|
|
157
|
-
@classmethod
|
|
158
|
-
def deprecation_warning(cls, version: str, reason: str):
|
|
159
|
-
"""Log a deprecation warning with reason and the version that will remove it."""
|
|
160
|
-
warnings.warn(
|
|
161
|
-
f"DeprecationWarning: {reason}. This will be removed in version {version}.",
|
|
162
|
-
DeprecationWarning,
|
|
163
|
-
stacklevel=2,
|
|
164
|
-
)
|
|
165
|
-
|
|
166
|
-
@classmethod
|
|
167
|
-
def configure_warnings(
|
|
168
|
-
cls, action: str = "default", category: Optional[type[Warning]] = None
|
|
169
|
-
):
|
|
170
|
-
"""
|
|
171
|
-
Configure the behavior of Python warnings.
|
|
172
|
-
|
|
173
|
-
Parameters
|
|
174
|
-
----------
|
|
175
|
-
action : str, optional
|
|
176
|
-
The action to take on warnings. Common actions include 'ignore', 'default', 'error', 'always', etc.
|
|
177
|
-
The default is 'default', which shows warnings once per triggering location.
|
|
178
|
-
category : type[Warning], optional
|
|
179
|
-
The category of warnings to configure. If not provided, all warnings are configured.
|
|
180
|
-
categories include DeprecationWarning, UserWarning, RuntimeWarning, etc.
|
|
181
|
-
|
|
182
|
-
"""
|
|
183
|
-
warnings.simplefilter(action=action, category=category)
|
|
1
|
+
import logging
|
|
2
|
+
import warnings
|
|
3
|
+
from contextlib import contextmanager
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import List, Optional
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class FloodAdaptLogging:
|
|
9
|
+
_DEFAULT_FORMATTER = logging.Formatter(
|
|
10
|
+
fmt="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
|
11
|
+
datefmt="%Y-%m-%d %I:%M:%S %p",
|
|
12
|
+
)
|
|
13
|
+
_root_logger = logging.getLogger("FloodAdapt")
|
|
14
|
+
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
file_path: Optional[Path] = None,
|
|
18
|
+
loglevel_console: int = logging.WARNING,
|
|
19
|
+
loglevel_root: int = logging.INFO,
|
|
20
|
+
loglevel_files: int = logging.DEBUG,
|
|
21
|
+
formatter: logging.Formatter = _DEFAULT_FORMATTER,
|
|
22
|
+
ignore_warnings: Optional[list[type[Warning]]] = None,
|
|
23
|
+
) -> None:
|
|
24
|
+
"""Initialize the logging system for the FloodAdapt."""
|
|
25
|
+
self._formatter = formatter
|
|
26
|
+
|
|
27
|
+
self._root_logger.setLevel(loglevel_root)
|
|
28
|
+
if self._root_logger.hasHandlers():
|
|
29
|
+
self._root_logger.handlers.clear()
|
|
30
|
+
|
|
31
|
+
# Add file handler if provided
|
|
32
|
+
if file_path is not None:
|
|
33
|
+
self.add_file_handler(file_path, loglevel_files, formatter)
|
|
34
|
+
|
|
35
|
+
# Add console handler
|
|
36
|
+
console_handler = logging.StreamHandler()
|
|
37
|
+
console_handler.setLevel(loglevel_console)
|
|
38
|
+
console_handler.setFormatter(formatter)
|
|
39
|
+
self._root_logger.addHandler(console_handler)
|
|
40
|
+
|
|
41
|
+
if ignore_warnings:
|
|
42
|
+
for warn_type in ignore_warnings:
|
|
43
|
+
self.configure_warnings("ignore", category=warn_type)
|
|
44
|
+
|
|
45
|
+
@classmethod
|
|
46
|
+
def add_file_handler(
|
|
47
|
+
cls,
|
|
48
|
+
file_path: Path,
|
|
49
|
+
loglevel: int = logging.DEBUG,
|
|
50
|
+
formatter: Optional[logging.Formatter] = None,
|
|
51
|
+
) -> None:
|
|
52
|
+
"""Add a file handler to the logger that directs outputs to a the file."""
|
|
53
|
+
if not file_path:
|
|
54
|
+
raise ValueError("file_path must be provided.")
|
|
55
|
+
file_path = Path(file_path)
|
|
56
|
+
|
|
57
|
+
# check if the path is a only a filename
|
|
58
|
+
if not file_path.parents:
|
|
59
|
+
file_path = Path.cwd() / file_path
|
|
60
|
+
file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
61
|
+
|
|
62
|
+
file_handler = logging.FileHandler(filename=file_path, mode="a")
|
|
63
|
+
file_handler.setLevel(loglevel)
|
|
64
|
+
|
|
65
|
+
formatter = formatter or cls._DEFAULT_FORMATTER
|
|
66
|
+
file_handler.setFormatter(formatter)
|
|
67
|
+
|
|
68
|
+
cls.getLogger().addHandler(file_handler)
|
|
69
|
+
|
|
70
|
+
@classmethod
|
|
71
|
+
def remove_file_handler(cls, file_path: Path) -> None:
|
|
72
|
+
"""Remove a file handler from the logger, which stops sending logs to that file and closes it."""
|
|
73
|
+
for handler in cls.getLogger().handlers:
|
|
74
|
+
if isinstance(handler, logging.FileHandler) and handler.baseFilename == str(
|
|
75
|
+
file_path.resolve()
|
|
76
|
+
):
|
|
77
|
+
handler.close()
|
|
78
|
+
cls.getLogger().removeHandler(handler)
|
|
79
|
+
|
|
80
|
+
@classmethod
|
|
81
|
+
def getLogger(
|
|
82
|
+
cls, name: Optional[str] = None, level: int = logging.INFO
|
|
83
|
+
) -> logging.Logger:
|
|
84
|
+
"""Get a logger with the specified name. If no name is provided, return the root logger.
|
|
85
|
+
|
|
86
|
+
If the logger does not exist, it is created with the specified level.
|
|
87
|
+
|
|
88
|
+
Parameters
|
|
89
|
+
----------
|
|
90
|
+
name : str, optional
|
|
91
|
+
The name of the logger. If not provided, the root logger is returned.
|
|
92
|
+
level : int,
|
|
93
|
+
The level of the logger. The default is logging.INFO.
|
|
94
|
+
|
|
95
|
+
Returns
|
|
96
|
+
-------
|
|
97
|
+
logging.Logger
|
|
98
|
+
The logger with the specified name.
|
|
99
|
+
"""
|
|
100
|
+
if name is None:
|
|
101
|
+
logger = cls._root_logger
|
|
102
|
+
else:
|
|
103
|
+
logger = logging.getLogger(f"FloodAdapt.{name}")
|
|
104
|
+
logger.setLevel(level)
|
|
105
|
+
return logger
|
|
106
|
+
|
|
107
|
+
@classmethod
|
|
108
|
+
def shutdown(cls):
|
|
109
|
+
root_logger = cls.getLogger()
|
|
110
|
+
handlers = root_logger.handlers[:]
|
|
111
|
+
for handler in handlers:
|
|
112
|
+
if isinstance(handler, logging.FileHandler):
|
|
113
|
+
handler.close()
|
|
114
|
+
root_logger.removeHandler(handler)
|
|
115
|
+
logging.shutdown()
|
|
116
|
+
|
|
117
|
+
@classmethod
|
|
118
|
+
@contextmanager
|
|
119
|
+
def to_file(
|
|
120
|
+
cls,
|
|
121
|
+
*,
|
|
122
|
+
file_path: Path,
|
|
123
|
+
loglevel: int = logging.DEBUG,
|
|
124
|
+
formatter: logging.Formatter = _DEFAULT_FORMATTER,
|
|
125
|
+
):
|
|
126
|
+
"""Open a file at filepath to write logs to. Does not affect other loggers.
|
|
127
|
+
|
|
128
|
+
When the context manager exits (via regular execution or an exception), the file is closed and the handler is removed.
|
|
129
|
+
"""
|
|
130
|
+
if file_path is None:
|
|
131
|
+
raise ValueError(
|
|
132
|
+
"file_path must be provided as a key value pair: 'file_path=<file_path>'."
|
|
133
|
+
)
|
|
134
|
+
cls.add_file_handler(file_path, loglevel, formatter)
|
|
135
|
+
try:
|
|
136
|
+
yield
|
|
137
|
+
finally:
|
|
138
|
+
cls.remove_file_handler(file_path)
|
|
139
|
+
|
|
140
|
+
@classmethod
|
|
141
|
+
def _close_file_handlers(cls, logger: logging.Logger, exclude: List[Path]) -> None:
|
|
142
|
+
"""Close and remove file handlers from a logger."""
|
|
143
|
+
for handler in logger.handlers[:]:
|
|
144
|
+
if (
|
|
145
|
+
isinstance(handler, logging.FileHandler)
|
|
146
|
+
and Path(handler.baseFilename) not in exclude
|
|
147
|
+
):
|
|
148
|
+
handler.close()
|
|
149
|
+
logger.removeHandler(handler)
|
|
150
|
+
|
|
151
|
+
@classmethod
|
|
152
|
+
def close_files(cls, exclude: List[Path] = []) -> None:
|
|
153
|
+
"""Close all file handlers except those in the exclude list."""
|
|
154
|
+
cls._close_file_handlers(cls.getLogger(), exclude)
|
|
155
|
+
cls._close_file_handlers(cls.getLogger("hydromt"), exclude)
|
|
156
|
+
|
|
157
|
+
@classmethod
|
|
158
|
+
def deprecation_warning(cls, version: str, reason: str):
|
|
159
|
+
"""Log a deprecation warning with reason and the version that will remove it."""
|
|
160
|
+
warnings.warn(
|
|
161
|
+
f"DeprecationWarning: {reason}. This will be removed in version {version}.",
|
|
162
|
+
DeprecationWarning,
|
|
163
|
+
stacklevel=2,
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
@classmethod
|
|
167
|
+
def configure_warnings(
|
|
168
|
+
cls, action: str = "default", category: Optional[type[Warning]] = None
|
|
169
|
+
):
|
|
170
|
+
"""
|
|
171
|
+
Configure the behavior of Python warnings.
|
|
172
|
+
|
|
173
|
+
Parameters
|
|
174
|
+
----------
|
|
175
|
+
action : str, optional
|
|
176
|
+
The action to take on warnings. Common actions include 'ignore', 'default', 'error', 'always', etc.
|
|
177
|
+
The default is 'default', which shows warnings once per triggering location.
|
|
178
|
+
category : type[Warning], optional
|
|
179
|
+
The category of warnings to configure. If not provided, all warnings are configured.
|
|
180
|
+
categories include DeprecationWarning, UserWarning, RuntimeWarning, etc.
|
|
181
|
+
|
|
182
|
+
"""
|
|
183
|
+
warnings.simplefilter(action=action, category=category)
|
flood_adapt/misc/path_builder.py
CHANGED
|
@@ -1,54 +1,54 @@
|
|
|
1
|
-
from enum import Enum
|
|
2
|
-
from pathlib import Path
|
|
3
|
-
from typing import Optional
|
|
4
|
-
|
|
5
|
-
from flood_adapt.config.config import Settings
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class TopLevelDir(str, Enum):
|
|
9
|
-
"""Top level directories in the database."""
|
|
10
|
-
|
|
11
|
-
input = "input"
|
|
12
|
-
output = "output"
|
|
13
|
-
static = "static"
|
|
14
|
-
temp = "temp"
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class ObjectDir(str, Enum):
|
|
18
|
-
"""The names for object directories at the second level of the database."""
|
|
19
|
-
|
|
20
|
-
site = "site"
|
|
21
|
-
|
|
22
|
-
benefit = "benefits"
|
|
23
|
-
event = "events"
|
|
24
|
-
strategy = "strategies"
|
|
25
|
-
measure = "measures"
|
|
26
|
-
projection = "projections"
|
|
27
|
-
scenario = "scenarios"
|
|
28
|
-
config = "config"
|
|
29
|
-
|
|
30
|
-
# buyout = "measures"
|
|
31
|
-
# elevate = "measures"
|
|
32
|
-
# floodproof = "measures"
|
|
33
|
-
# greening = "measures"
|
|
34
|
-
# floodwall = "measures"
|
|
35
|
-
# pump = "measures"
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def db_path(
|
|
39
|
-
top_level_dir: TopLevelDir = TopLevelDir.input,
|
|
40
|
-
object_dir: Optional[ObjectDir] = None,
|
|
41
|
-
obj_name: Optional[str] = None,
|
|
42
|
-
) -> Path:
|
|
43
|
-
"""Return an path to a database directory from arguments."""
|
|
44
|
-
rel_path = Path(top_level_dir.value)
|
|
45
|
-
if object_dir is not None:
|
|
46
|
-
if isinstance(object_dir, ObjectDir):
|
|
47
|
-
rel_path = rel_path / object_dir.value
|
|
48
|
-
else:
|
|
49
|
-
rel_path = rel_path / str(object_dir)
|
|
50
|
-
|
|
51
|
-
if obj_name is not None:
|
|
52
|
-
rel_path = rel_path / obj_name
|
|
53
|
-
|
|
54
|
-
return Settings().database_path / rel_path
|
|
1
|
+
from enum import Enum
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from flood_adapt.config.config import Settings
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TopLevelDir(str, Enum):
|
|
9
|
+
"""Top level directories in the database."""
|
|
10
|
+
|
|
11
|
+
input = "input"
|
|
12
|
+
output = "output"
|
|
13
|
+
static = "static"
|
|
14
|
+
temp = "temp"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ObjectDir(str, Enum):
|
|
18
|
+
"""The names for object directories at the second level of the database."""
|
|
19
|
+
|
|
20
|
+
site = "site"
|
|
21
|
+
|
|
22
|
+
benefit = "benefits"
|
|
23
|
+
event = "events"
|
|
24
|
+
strategy = "strategies"
|
|
25
|
+
measure = "measures"
|
|
26
|
+
projection = "projections"
|
|
27
|
+
scenario = "scenarios"
|
|
28
|
+
config = "config"
|
|
29
|
+
|
|
30
|
+
# buyout = "measures"
|
|
31
|
+
# elevate = "measures"
|
|
32
|
+
# floodproof = "measures"
|
|
33
|
+
# greening = "measures"
|
|
34
|
+
# floodwall = "measures"
|
|
35
|
+
# pump = "measures"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def db_path(
|
|
39
|
+
top_level_dir: TopLevelDir = TopLevelDir.input,
|
|
40
|
+
object_dir: Optional[ObjectDir] = None,
|
|
41
|
+
obj_name: Optional[str] = None,
|
|
42
|
+
) -> Path:
|
|
43
|
+
"""Return an path to a database directory from arguments."""
|
|
44
|
+
rel_path = Path(top_level_dir.value)
|
|
45
|
+
if object_dir is not None:
|
|
46
|
+
if isinstance(object_dir, ObjectDir):
|
|
47
|
+
rel_path = rel_path / object_dir.value
|
|
48
|
+
else:
|
|
49
|
+
rel_path = rel_path / str(object_dir)
|
|
50
|
+
|
|
51
|
+
if obj_name is not None:
|
|
52
|
+
rel_path = rel_path / obj_name
|
|
53
|
+
|
|
54
|
+
return Settings().database_path / rel_path
|