flood-adapt 1.1.4__py3-none-any.whl → 1.1.5__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 +1 -1
- flood_adapt/database_builder/database_builder.py +19 -19
- flood_adapt/dbs_classes/dbs_scenario.py +2 -1
- flood_adapt/objects/events/events.py +57 -0
- flood_adapt/objects/forcing/forcing.py +46 -1
- flood_adapt/objects/forcing/tide_gauge.py +4 -2
- {flood_adapt-1.1.4.dist-info → flood_adapt-1.1.5.dist-info}/METADATA +1 -1
- {flood_adapt-1.1.4.dist-info → flood_adapt-1.1.5.dist-info}/RECORD +11 -11
- {flood_adapt-1.1.4.dist-info → flood_adapt-1.1.5.dist-info}/LICENSE +0 -0
- {flood_adapt-1.1.4.dist-info → flood_adapt-1.1.5.dist-info}/WHEEL +0 -0
- {flood_adapt-1.1.4.dist-info → flood_adapt-1.1.5.dist-info}/top_level.txt +0 -0
flood_adapt/__init__.py
CHANGED
|
@@ -1527,9 +1527,13 @@ class DatabaseBuilder:
|
|
|
1527
1527
|
)
|
|
1528
1528
|
# Add tide gauge as obs point if within model region
|
|
1529
1529
|
if coord.within(model_region):
|
|
1530
|
+
if self.tide_gauge.name is None:
|
|
1531
|
+
name = "tide_gauge"
|
|
1532
|
+
else:
|
|
1533
|
+
name = self.tide_gauge.name
|
|
1530
1534
|
obs_points.append(
|
|
1531
1535
|
ObsPointModel(
|
|
1532
|
-
name=
|
|
1536
|
+
name=name,
|
|
1533
1537
|
description="Tide gauge observation point",
|
|
1534
1538
|
ID=self.tide_gauge.ID,
|
|
1535
1539
|
lon=self.tide_gauge.lon,
|
|
@@ -1663,7 +1667,7 @@ class DatabaseBuilder:
|
|
|
1663
1667
|
db_file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
1664
1668
|
shutil.copyfile(self.config.tide_gauge.file, db_file_path)
|
|
1665
1669
|
|
|
1666
|
-
rel_db_path = Path(db_file_path.relative_to(self.static_path))
|
|
1670
|
+
rel_db_path = Path(db_file_path.relative_to(self.static_path)).as_posix()
|
|
1667
1671
|
logger.warning(
|
|
1668
1672
|
f"Tide gauge from file {rel_db_path} assumed to be in {self.unit_system.default_length_units}!"
|
|
1669
1673
|
)
|
|
@@ -1795,26 +1799,22 @@ class DatabaseBuilder:
|
|
|
1795
1799
|
if self.sfincs_offshore_model is None:
|
|
1796
1800
|
return None
|
|
1797
1801
|
# Connect boundary points of overland to output points of offshore
|
|
1802
|
+
# First read in the boundary locations from the overland model
|
|
1798
1803
|
fn = Path(self.sfincs_overland_model.root) / "sfincs.bnd"
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
+
lines = []
|
|
1805
|
+
if fn.exists():
|
|
1806
|
+
with open(fn) as f:
|
|
1807
|
+
lines = f.readlines()
|
|
1808
|
+
coords = [(float(line.split()[0]), float(line.split()[1])) for line in lines]
|
|
1809
|
+
x, y = zip(*coords)
|
|
1810
|
+
bnd = gpd.GeoDataFrame(
|
|
1811
|
+
geometry=gpd.points_from_xy(x, y),
|
|
1804
1812
|
crs=self.sfincs_overland_model.config["epsg"],
|
|
1805
1813
|
)
|
|
1806
|
-
|
|
1807
|
-
obs_geo
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
obs_geo["name"] = [f"bnd_pt{num:02d}" for num in range(1, len(obs_geo) + 1)]
|
|
1811
|
-
fn_off = Path(self.sfincs_offshore_model.root) / "sfincs.obs"
|
|
1812
|
-
obs_geo.to_csv(
|
|
1813
|
-
fn_off,
|
|
1814
|
-
sep="\t",
|
|
1815
|
-
index=False,
|
|
1816
|
-
header=False,
|
|
1817
|
-
)
|
|
1814
|
+
# Then transform points to offshore crs and save them as observation points
|
|
1815
|
+
obs_geo = bnd.to_crs(self.sfincs_offshore_model.config["epsg"])
|
|
1816
|
+
self.sfincs_offshore_model.setup_observation_points(obs_geo)
|
|
1817
|
+
self.sfincs_offshore_model.write()
|
|
1818
1818
|
logger.info(
|
|
1819
1819
|
"Output points of the offshore SFINCS model were reconfigured to the boundary points of the overland SFINCS model."
|
|
1820
1820
|
)
|
|
@@ -79,7 +79,8 @@ class DbsScenario(DbsTemplate[Scenario]):
|
|
|
79
79
|
"""
|
|
80
80
|
event_left = self._database.events.get(left.event)
|
|
81
81
|
event_right = self._database.events.get(right.event)
|
|
82
|
-
|
|
82
|
+
# Deep-compare events including forcing data contents
|
|
83
|
+
equal_events = event_left.data_equivalent(event_right)
|
|
83
84
|
|
|
84
85
|
left_projection = self._database.projections.get(left.projection)
|
|
85
86
|
right_projection = self._database.projections.get(right.projection)
|
|
@@ -117,6 +117,63 @@ class Event(Object):
|
|
|
117
117
|
for forcing in self.get_forcings():
|
|
118
118
|
forcing.save_additional(output_dir)
|
|
119
119
|
|
|
120
|
+
def data_equivalent(self, other: "Event") -> bool:
|
|
121
|
+
"""Deep-compare two events, including forcing data contents.
|
|
122
|
+
|
|
123
|
+
Compares core attributes (time, template, mode, rainfall_multiplier) and then
|
|
124
|
+
verifies that each forcing (by type) has the same data fingerprint. For
|
|
125
|
+
path-based forcings, the fingerprint hashes the file bytes; for others,
|
|
126
|
+
a canonical attribute-based hash is used.
|
|
127
|
+
|
|
128
|
+
Parameters
|
|
129
|
+
----------
|
|
130
|
+
other : Event
|
|
131
|
+
The event to compare against.
|
|
132
|
+
|
|
133
|
+
Returns
|
|
134
|
+
-------
|
|
135
|
+
bool
|
|
136
|
+
True when events are equivalent in terms of their hazard inputs.
|
|
137
|
+
"""
|
|
138
|
+
if not isinstance(other, Event):
|
|
139
|
+
return False
|
|
140
|
+
|
|
141
|
+
# Compare high-level attributes first
|
|
142
|
+
if (
|
|
143
|
+
self.template != other.template
|
|
144
|
+
or self.mode != other.mode
|
|
145
|
+
or self.rainfall_multiplier != other.rainfall_multiplier
|
|
146
|
+
or self.time != other.time
|
|
147
|
+
):
|
|
148
|
+
return False
|
|
149
|
+
|
|
150
|
+
# Compare allowed forcing types present in each event
|
|
151
|
+
if set(self.forcings.keys()) != set(other.forcings.keys()):
|
|
152
|
+
return False
|
|
153
|
+
|
|
154
|
+
# Build comparable, sorted fingerprint lists per forcing type
|
|
155
|
+
def fingerprints(evt: "Event") -> dict[ForcingType, list[tuple[str, str]]]:
|
|
156
|
+
d: dict[ForcingType, list[tuple[str, str]]] = {}
|
|
157
|
+
for ftype, flist in evt.forcings.items():
|
|
158
|
+
fps: list[tuple[str, str]] = []
|
|
159
|
+
for f in flist:
|
|
160
|
+
# Include source and the fingerprint to guard against collisions across different sources
|
|
161
|
+
src = f.source.value if hasattr(f, "source") else ""
|
|
162
|
+
fp = f.content_fingerprint() # type: ignore[attr-defined]
|
|
163
|
+
fps.append((src, fp))
|
|
164
|
+
# Sort for order-insensitive comparison
|
|
165
|
+
d[ftype] = sorted(fps, key=lambda t: (t[0], t[1]))
|
|
166
|
+
return d
|
|
167
|
+
|
|
168
|
+
left_fp = fingerprints(self)
|
|
169
|
+
right_fp = fingerprints(other)
|
|
170
|
+
|
|
171
|
+
for ftype in left_fp.keys():
|
|
172
|
+
if left_fp[ftype] != right_fp[ftype]:
|
|
173
|
+
return False
|
|
174
|
+
|
|
175
|
+
return True
|
|
176
|
+
|
|
120
177
|
@classmethod
|
|
121
178
|
def load_file(cls, file_path: Path | str | os.PathLike) -> "Event":
|
|
122
179
|
"""Load object from file.
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import hashlib
|
|
2
|
+
import json
|
|
1
3
|
import os
|
|
2
4
|
from abc import ABC, abstractmethod
|
|
3
5
|
from enum import Enum
|
|
@@ -72,7 +74,7 @@ class IForcing(BaseModel, ABC):
|
|
|
72
74
|
|
|
73
75
|
def save_additional(self, output_dir: Path | str | os.PathLike) -> None:
|
|
74
76
|
"""Save additional data of the forcing."""
|
|
75
|
-
|
|
77
|
+
pass
|
|
76
78
|
|
|
77
79
|
@field_serializer("path", check_fields=False)
|
|
78
80
|
@classmethod
|
|
@@ -80,6 +82,49 @@ class IForcing(BaseModel, ABC):
|
|
|
80
82
|
"""Serialize filepath-like fields by saving only the filename. It is assumed that the file will be saved in the same directory."""
|
|
81
83
|
return value.name
|
|
82
84
|
|
|
85
|
+
def content_fingerprint(self) -> str:
|
|
86
|
+
"""Return a stable fingerprint of the forcing's underlying data.
|
|
87
|
+
|
|
88
|
+
- If a file-backed `path` attribute exists and the file exists, hash its bytes (SHA-256).
|
|
89
|
+
- Otherwise, hash a canonical JSON dump of the model (excluding volatile fields like `path`).
|
|
90
|
+
|
|
91
|
+
Returns
|
|
92
|
+
-------
|
|
93
|
+
str
|
|
94
|
+
A fingerprint string that changes when the forcing's effective data changes.
|
|
95
|
+
"""
|
|
96
|
+
# Prefer hashing the actual file content when available
|
|
97
|
+
try:
|
|
98
|
+
p = getattr(self, "path", None)
|
|
99
|
+
if isinstance(p, Path) and p and p.exists():
|
|
100
|
+
sha = hashlib.sha256()
|
|
101
|
+
with p.open("rb") as f:
|
|
102
|
+
for chunk in iter(lambda: f.read(8192), b""):
|
|
103
|
+
sha.update(chunk)
|
|
104
|
+
# Include filename to disambiguate multi-forcing scenarios with identical content
|
|
105
|
+
return f"FILE:{p.name}:{sha.hexdigest()}"
|
|
106
|
+
except Exception:
|
|
107
|
+
# Fall through to attribute-based hashing if anything goes wrong
|
|
108
|
+
pass
|
|
109
|
+
|
|
110
|
+
# Fallback: hash the model attributes (excluding volatile fields like path)
|
|
111
|
+
data = self.model_dump(exclude_none=True)
|
|
112
|
+
# Remove potentially non-stable/absolute fields
|
|
113
|
+
data.pop("path", None)
|
|
114
|
+
|
|
115
|
+
# Ensure enums are serialized to their values for stable hashing
|
|
116
|
+
if isinstance(data.get("type"), Enum):
|
|
117
|
+
data["type"] = data["type"].value
|
|
118
|
+
if isinstance(data.get("source"), Enum):
|
|
119
|
+
data["source"] = data["source"].value
|
|
120
|
+
|
|
121
|
+
payload = json.dumps(data, sort_keys=True, default=str).encode("utf-8")
|
|
122
|
+
return f"ATTR:{hashlib.sha256(payload).hexdigest()}"
|
|
123
|
+
|
|
124
|
+
def _post_load(self, file_path: Path | str | os.PathLike, **kwargs) -> None:
|
|
125
|
+
"""Post-load hook, called at the end of `load_file`, to perform any additional loading steps after loading from file."""
|
|
126
|
+
return
|
|
127
|
+
|
|
83
128
|
|
|
84
129
|
class IDischarge(IForcing):
|
|
85
130
|
type: ForcingType = ForcingType.DISCHARGE
|
|
@@ -8,6 +8,7 @@ import requests
|
|
|
8
8
|
from noaa_coops.station import COOPSAPIError
|
|
9
9
|
from pydantic import BaseModel, model_validator
|
|
10
10
|
|
|
11
|
+
from flood_adapt.config import Settings
|
|
11
12
|
from flood_adapt.misc.log import FloodAdaptLogging
|
|
12
13
|
from flood_adapt.objects.forcing import unit_system as us
|
|
13
14
|
from flood_adapt.objects.forcing.time_frame import TimeFrame
|
|
@@ -56,7 +57,7 @@ class TideGauge(BaseModel):
|
|
|
56
57
|
source: TideGaugeSource
|
|
57
58
|
reference: str
|
|
58
59
|
ID: Optional[int] = None # Attribute used to download from correct gauge
|
|
59
|
-
file: Optional[
|
|
60
|
+
file: Optional[str] = None # for locally stored data
|
|
60
61
|
lat: Optional[float] = None
|
|
61
62
|
lon: Optional[float] = None
|
|
62
63
|
units: us.UnitTypesLength = (
|
|
@@ -104,7 +105,8 @@ class TideGauge(BaseModel):
|
|
|
104
105
|
"""
|
|
105
106
|
logger.info(f"Retrieving waterlevels for tide gauge {self.ID} for {time}")
|
|
106
107
|
if self.file:
|
|
107
|
-
|
|
108
|
+
abs_path = Settings().database_path / "static" / self.file
|
|
109
|
+
gauge_data = self._read_imported_waterlevels(time=time, path=abs_path)
|
|
108
110
|
else:
|
|
109
111
|
gauge_data = self._download_tide_gauge_data(time=time)
|
|
110
112
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: flood-adapt
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.5
|
|
4
4
|
Summary: A software package support system which can be used to assess the benefits and costs of flood resilience measures
|
|
5
5
|
Author-email: Gundula Winter <Gundula.Winter@deltares.nl>, Panos Athanasiou <Panos.Athanasiou@deltares.nl>, Frederique de Groen <Frederique.deGroen@deltares.nl>, Tim de Wilde <Tim.deWilde@deltares.nl>, Julian Hofer <Julian.Hofer@deltares.nl>, Daley Adrichem <Daley.Adrichem@deltares.nl>, Luuk Blom <Luuk.Blom@deltares.nl>
|
|
6
6
|
License: ====================================================
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
flood_adapt/__init__.py,sha256=
|
|
1
|
+
flood_adapt/__init__.py,sha256=qZBLP5qxMYURIbpEB6pRkz3wIeIVQZ0N9wTSJgxs_BA,779
|
|
2
2
|
flood_adapt/flood_adapt.py,sha256=HVFS4OFhcB0TqHtMw3kbEei0IfJxsciauHfG3XZ38-0,40747
|
|
3
3
|
flood_adapt/adapter/__init__.py,sha256=vnF8NCkEVX-N-gtGS-J_A1H1YYAjihWjJZFyYGwcp8Q,180
|
|
4
4
|
flood_adapt/adapter/fiat_adapter.py,sha256=seDjPoumkhUOd7qer3ni1_Ut3dwyq0-_yhJNaTEFc2E,60284
|
|
@@ -18,7 +18,7 @@ flood_adapt/config/impacts.py,sha256=O7vE7jB3GSXnkqAvv7TqJiJ_j1uJ3mck_KQ-ScsB3bo
|
|
|
18
18
|
flood_adapt/config/sfincs.py,sha256=y8C3PzFwwgMB_sb8rBzgteaQ8fCxep6DnZxuk0q__bc,4825
|
|
19
19
|
flood_adapt/config/site.py,sha256=VR90jCHWcxgoQJptNyXy7LseGjXUDRtdOjNGCddFVzI,4328
|
|
20
20
|
flood_adapt/database_builder/__init__.py,sha256=h4ietZ6sAZa7j2kvSzp5-58BueGrfJsXvq8PFu1RLyI,1112
|
|
21
|
-
flood_adapt/database_builder/database_builder.py,sha256=
|
|
21
|
+
flood_adapt/database_builder/database_builder.py,sha256=nPwkBQpDzl74OrgF3hjQiDJprtxtdJuu0HsY3jNvJiM,110065
|
|
22
22
|
flood_adapt/database_builder/metrics_utils.py,sha256=aU7YfXLmBjFT0fQQQl3o0yIzdFJ6XJGlld0GnkJytGc,66258
|
|
23
23
|
flood_adapt/database_builder/templates/default_units/imperial.toml,sha256=zIjPlxIa2kWLUjSYisd8UolXGo5iKdFoDDz_JkKBXTM,295
|
|
24
24
|
flood_adapt/database_builder/templates/default_units/metric.toml,sha256=tc0XMKs7xGL9noB9lAb0gyQfjYxzokgHa3NqpccxWl0,302
|
|
@@ -61,7 +61,7 @@ flood_adapt/dbs_classes/dbs_benefit.py,sha256=ayEYz8ga49HLdYuUsDWZOuZnpRnBpTuyhv
|
|
|
61
61
|
flood_adapt/dbs_classes/dbs_event.py,sha256=ak3kHan6L1EfC8agDLKiCe8gaY5leOmj_qUBsI61q9A,1869
|
|
62
62
|
flood_adapt/dbs_classes/dbs_measure.py,sha256=vVs-LtnHJN7eSGIFUglJdpbtfq_QI_Ftkv4lh5mfnNM,4085
|
|
63
63
|
flood_adapt/dbs_classes/dbs_projection.py,sha256=lyiU_ctP2ixK28RKnBN6mVJbOuaDsWCj1y6-MHlyi_k,1078
|
|
64
|
-
flood_adapt/dbs_classes/dbs_scenario.py,sha256=
|
|
64
|
+
flood_adapt/dbs_classes/dbs_scenario.py,sha256=bD5VjuojgE_79ZN7bZNpnbpthI9uYUwMSsrPDDcjlvg,4070
|
|
65
65
|
flood_adapt/dbs_classes/dbs_static.py,sha256=Yzs-bsfAq2jkZ_-0_ojuzNf81Wifaxw8a1APNNS0mqM,10565
|
|
66
66
|
flood_adapt/dbs_classes/dbs_strategy.py,sha256=qiEObHZeYL93GmdjSiGQls1ZmxdMZPkRkwzHgmoYwyE,4856
|
|
67
67
|
flood_adapt/dbs_classes/dbs_template.py,sha256=b2x2sWNYTnaWU8Plgp51PFPrZGEv2kRRn9JBAgYhLbI,11578
|
|
@@ -82,20 +82,20 @@ flood_adapt/objects/benefits/benefits.py,sha256=1Di8v2B7YOdMkRlg0A6k6qtMqYE_JaaN
|
|
|
82
82
|
flood_adapt/objects/events/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
83
83
|
flood_adapt/objects/events/event_factory.py,sha256=CYq8itWurILPGNSDtWKWV5FF4UxjrRFiza6w2OQJEdU,4276
|
|
84
84
|
flood_adapt/objects/events/event_set.py,sha256=fpmNbrd3qXWPgyqphv_Rf2iNsZCLvwz6YEbjMV7WIXA,2810
|
|
85
|
-
flood_adapt/objects/events/events.py,sha256=
|
|
85
|
+
flood_adapt/objects/events/events.py,sha256=Kqwyeh9MMp8ex6DBbg-rqBnp6RsrbR1J7bfO9ybevh4,10580
|
|
86
86
|
flood_adapt/objects/events/historical.py,sha256=uIQ7icy9F3pOW0R-fBqjEjU857SGlJO81S104mzvtLY,2081
|
|
87
87
|
flood_adapt/objects/events/hurricane.py,sha256=dOPMa5c4mz1umLne9ydkBqnLTig9D95LmPHSFE5wit8,2401
|
|
88
88
|
flood_adapt/objects/events/synthetic.py,sha256=Q8OHbBumeEwbrzA1imBrxiGiB92RWyigVcGVUbisSh4,1366
|
|
89
89
|
flood_adapt/objects/forcing/__init__.py,sha256=wzPrflMLiEolocs3UcLeg05u5ydMDhF00jEf9zsC76c,2141
|
|
90
90
|
flood_adapt/objects/forcing/csv.py,sha256=AMHlE5K_QiMOqD2pRRbG4ojnZ9VPiQjtk2wMFSouKjk,2027
|
|
91
91
|
flood_adapt/objects/forcing/discharge.py,sha256=GIuKETXizwuaeIbHlu0fELQwC0ttfZSDiUMRm4HEyWY,2057
|
|
92
|
-
flood_adapt/objects/forcing/forcing.py,sha256=
|
|
92
|
+
flood_adapt/objects/forcing/forcing.py,sha256=n2IEk21Ih0GkddH3IqoV8egAYh4UCAVEyz_O0kk2fvE,6386
|
|
93
93
|
flood_adapt/objects/forcing/forcing_factory.py,sha256=lpugKlMt0MN8BxyykottMOuQd_fp1MHrkuuqbHWWdRY,5965
|
|
94
94
|
flood_adapt/objects/forcing/meteo_handler.py,sha256=rTxY5WNobK_Ifzj2eVcoSPGgb3TzuZljSv_dLn5FLo8,3016
|
|
95
95
|
flood_adapt/objects/forcing/netcdf.py,sha256=ZBzFtN5joVs36lVjvYErVaHEylUQ6eKIhR0uk_MD-zM,1388
|
|
96
96
|
flood_adapt/objects/forcing/plotting.py,sha256=Y7f_9bY8d9jbd7BqEAeRmof-aaJhlznM3_wGBOI7g-s,14828
|
|
97
97
|
flood_adapt/objects/forcing/rainfall.py,sha256=e6P3IMzItvnsmXbcMXl1oV-d9LDuh3jTIc_vt6Kz5zo,3282
|
|
98
|
-
flood_adapt/objects/forcing/tide_gauge.py,sha256=
|
|
98
|
+
flood_adapt/objects/forcing/tide_gauge.py,sha256=uPgvlcvDtZFQrtTyXX2d5YmSvCnjYYg0Xsu8NAwQZPQ,7299
|
|
99
99
|
flood_adapt/objects/forcing/time_frame.py,sha256=1X3G0Ax18BHRvAomf-CW_ISRk_3qgAakwgZCIBxIkL4,2855
|
|
100
100
|
flood_adapt/objects/forcing/timeseries.py,sha256=bD27JWzC3owq5ah3zPzJ7xoUzSH_t4J03s_SycYW0mQ,19740
|
|
101
101
|
flood_adapt/objects/forcing/unit_system.py,sha256=7FFOmaxq6EOvXx64QDxlpNU4uMExqridFcdFwyTJ4Lo,16542
|
|
@@ -114,8 +114,8 @@ flood_adapt/objects/strategies/strategies.py,sha256=Jw-WJDCamL9p_7VEir3AdmYPMVAi
|
|
|
114
114
|
flood_adapt/workflows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
115
115
|
flood_adapt/workflows/benefit_runner.py,sha256=eA21TuHdeZ6QYO8ehXri6BHlkyHsVsZphIdIca5g0KA,21824
|
|
116
116
|
flood_adapt/workflows/scenario_runner.py,sha256=9_Y6GmMYhYoTRkBUIlju0eBy6DosGf4Zl2tgu1QEubI,4119
|
|
117
|
-
flood_adapt-1.1.
|
|
118
|
-
flood_adapt-1.1.
|
|
119
|
-
flood_adapt-1.1.
|
|
120
|
-
flood_adapt-1.1.
|
|
121
|
-
flood_adapt-1.1.
|
|
117
|
+
flood_adapt-1.1.5.dist-info/LICENSE,sha256=Ui5E03pQ0EVKxvKA54lTPA1xrtgA2HMGLQai95eOzoE,36321
|
|
118
|
+
flood_adapt-1.1.5.dist-info/METADATA,sha256=yGKj5wuwDfXXwLSnJVfZmywRC4hZAJ_g2NrYeuCvg5I,48806
|
|
119
|
+
flood_adapt-1.1.5.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
|
|
120
|
+
flood_adapt-1.1.5.dist-info/top_level.txt,sha256=JvzMi6cTcQPEThCfpgMEeVny3ghI1urSH0CCgVIqSzw,12
|
|
121
|
+
flood_adapt-1.1.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|