Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

553 Adding files to Database when importing extrenal files #558

Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
b4c49bd
added dditional_files arg to all save() functions of object models.
LuukBlom Oct 11, 2024
618301b
implement saving additional files for all object_models. TODO add tes…
LuukBlom Oct 11, 2024
377fea3
WIP tests additional files. TODO finish event tests
LuukBlom Oct 14, 2024
15b0e8e
finish tests for events and measures
LuukBlom Oct 14, 2024
ba8f5d7
Merge branch 'main' into 553-new-development-area-shapefile-not-copie…
LuukBlom Oct 14, 2024
613e76a
go through PR and fix mistakes
LuukBlom Oct 15, 2024
50f2408
remove dditional_files argument and make default behaviour to always…
LuukBlom Oct 15, 2024
20f8fd7
Merge branch 'main' into 553-new-development-area-shapefile-not-copie…
LuukBlom Oct 15, 2024
1a03896
Whoops huge commit.
LuukBlom Oct 21, 2024
81396ad
small bug fixes + rename of util func
LuukBlom Oct 21, 2024
8ff7f38
moved code from pathbuilder to interface.database
LuukBlom Oct 22, 2024
287a269
revert pathbuilder change due to circular dependency
LuukBlom Oct 22, 2024
54e3dd0
finish implementation and use of IObject subclasses in other parts of…
LuukBlom Oct 22, 2024
5264ab6
temporary fix for until the hazard refactor to prevent trying to read…
LuukBlom Oct 22, 2024
0741ece
go through PR and fix obvious stuff
LuukBlom Oct 22, 2024
33b7498
corrected small bug when calling the resolve_filepath method
panosatha Oct 29, 2024
658a3e6
fix file handling for events
LuukBlom Oct 30, 2024
1fa9b8d
Merge branch '553-new-development-area-shapefile-not-copied-in-projec…
LuukBlom Oct 30, 2024
3c92acc
remove obsolete api func
LuukBlom Oct 30, 2024
e5f9eb1
Merge branch 'main' into 553-new-development-area-shapefile-not-copie…
LuukBlom Oct 30, 2024
ea23e77
remove duplicate api func
LuukBlom Oct 30, 2024
f0ce9f2
filter invalid datetime from index to stop errors in hydromt-sfincs
LuukBlom Oct 31, 2024
2b6e0a3
move validation of overlapping measures to the save function of dbs_s…
LuukBlom Nov 1, 2024
1b49e25
make sure that shapefiles can correctly be imported to the database
panosatha Nov 1, 2024
900f772
added overlapping measures check to dbs_strategy
LuukBlom Nov 1, 2024
5c00c24
api correction
panosatha Nov 1, 2024
a4c1736
Merge branch '553-new-development-area-shapefile-not-copied-in-projec…
LuukBlom Nov 1, 2024
ac15f72
instead of saving the name, also save the index in the cyc_db as ther…
LuukBlom Nov 1, 2024
a186cd4
hurricanes events expect either a .cyc file in the same dir as the to…
LuukBlom Nov 1, 2024
ca912ca
fixed broken test
LuukBlom Nov 1, 2024
e665c5f
fix copying of objects with additional files
LuukBlom Nov 5, 2024
3ce7dbe
fix exclude pattern
LuukBlom Nov 5, 2024
02f03f4
merge main into 553-new-development-area-shapefile-not-copied-in-proj…
LuukBlom Nov 27, 2024
fcbeaf5
merge main into 553-new-development-area-shapefile-not-copied-in-proj…
LuukBlom Nov 27, 2024
f26d949
Merge branch 'main' into 553-new-development-area-shapefile-not-copie…
LuukBlom Dec 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions flood_adapt/api/measures.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ def create_measure(attrs: dict[str, Any], type: str = None) -> IMeasure:
Dictionary of attributes for the measure.
type : str
Type of measure to create.
database : IDatabase, optional
Database to use for creating the measure, by default None

Returns
-------
Expand All @@ -55,6 +53,8 @@ def create_measure(attrs: dict[str, Any], type: str = None) -> IMeasure:
return Pump.load_dict(attrs)
elif type in ["water_square", "total_storage", "greening"]:
return GreenInfrastructure.load_dict(attrs)
else:
raise ValueError(f"Invalid measure type: {type}")


def save_measure(measure: IMeasure) -> None:
Expand Down
40 changes: 0 additions & 40 deletions flood_adapt/dbs_classes/dbs_event.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import shutil
from pathlib import Path
from typing import Any

Expand Down Expand Up @@ -58,45 +57,6 @@ def list_objects(self) -> dict[str, list[Any]]:
events["objects"] = objects
return events

def copy(self, old_name: str, new_name: str, new_description: str):
"""Copy (duplicate) an existing object, and give it a new name.

Parameters
----------
old_name : str
name of the existing measure
new_name : str
name of the new measure
new_description : str
description of the new measure
"""
# Check if the provided old_name is valid
if old_name not in self.list_objects()["name"]:
raise ValueError(
f"{self._object_class.class_name} '{old_name}' does not exist."
)

# First do a get and change the name and description
copy_object = self.get(old_name)
copy_object.attrs.name = new_name
copy_object.attrs.description = new_description

# After changing the name and description, receate the model to re-trigger the validators
copy_object.attrs = type(copy_object.attrs)(**copy_object.attrs.model_dump())

# Then a save. Checking whether the name is already in use is done in the save function
self.save(copy_object)

# Then save all the accompanied files
src = self.input_path / old_name
dest = self.input_path / new_name

EXCLUDE = [".spw", ".toml"]
for file in src.glob("*"):
if file.suffix in EXCLUDE:
continue
shutil.copy(file, dest / file.name)

def _check_standard_objects(self, name: str) -> bool:
"""Check if an event is a standard event.

Expand Down
23 changes: 21 additions & 2 deletions flood_adapt/dbs_classes/dbs_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,27 @@ def copy(self, old_name: str, new_name: str, new_description: str):
# After changing the name and description, receate the model to re-trigger the validators
copy_object.attrs = type(copy_object.attrs)(**copy_object.attrs.model_dump())

# Then save. Checking whether the name is already in use is done in the save function
self.save(copy_object)
EXCLUDE_SUFFIX = [".spw"]
LuukBlom marked this conversation as resolved.
Show resolved Hide resolved
try:
# Copy the folder
shutil.copytree(
self.input_path / old_name,
self.input_path / new_name,
ignore=shutil.ignore_patterns(*EXCLUDE_SUFFIX),
)

# Rename the toml file to not raise in the name check
os.rename(
self.input_path / new_name / f"{old_name}.toml",
self.input_path / new_name / f"{new_name}.toml",
)

# Check new name is valid and update toml file
self.save(copy_object, overwrite=True)
except:
# If an error occurs, delete the folder and raise the error
shutil.rmtree(self.input_path / new_name, ignore_errors=True)
raise

def save(
self,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def save_additional(self, toml_path: Path | str | os.PathLike) -> None:
self.dir_name, self.attrs.name, self.attrs.polygon_file
)
path = save_file_to_database(src_path, Path(toml_path).parent)

# Update the shapefile path in the object so it is saved in the toml file as well
self.attrs.polygon_file = path.name

Expand Down
91 changes: 91 additions & 0 deletions tests/test_api/test_measures.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import pytest

from flood_adapt.api.measures import (
copy_measure,
create_measure,
delete_measure,
get_measure,
save_measure,
)
from tests.test_object_model.test_measures import (
test_buyout,
test_elevate,
test_floodproof,
test_floodwall,
test_green_infra,
test_pump,
)

__all__ = [
"test_buyout",
"test_elevate",
"test_floodproof",
"test_floodwall",
"test_pump",
"test_green_infra",
]
# dict of measure fixture names and their corresponding measure type
measure_fixtures = {
"test_elevate": "elevate_properties",
"test_buyout": "buyout_properties",
"test_floodproof": "floodproof_properties",
"test_floodwall": "floodwall",
"test_pump": "pump",
"test_green_infra": "greening",
}


@pytest.mark.parametrize("measure_fixture_name", measure_fixtures.keys())
def test_create_measure(measure_fixture_name, request):
measure = request.getfixturevalue(measure_fixture_name)
measure_type = measure_fixtures[measure_fixture_name]

measure = create_measure(attrs=measure.attrs, type=measure_type)
assert measure is not None


@pytest.mark.parametrize("measure_fixture", measure_fixtures.keys())
def test_save_measure(test_db, measure_fixture, request):
measure = request.getfixturevalue(measure_fixture)

save_measure(measure)
assert (test_db.measures.input_path / measure.attrs.name).exists()


@pytest.mark.parametrize("measure_fixture", measure_fixtures.keys())
def test_get_measure(test_db, measure_fixture, request):
measure = request.getfixturevalue(measure_fixture)

save_measure(measure)
assert (test_db.measures.input_path / measure.attrs.name).exists()

loaded_measure = get_measure(measure.attrs.name)
assert loaded_measure == measure


@pytest.mark.parametrize("measure_fixture", measure_fixtures.keys())
def test_delete_measure(test_db, measure_fixture, request):
measure = request.getfixturevalue(measure_fixture)
save_measure(measure)
assert (test_db.measures.input_path / measure.attrs.name).exists()

delete_measure(measure.attrs.name)
assert not (test_db.measures.input_path / measure.attrs.name).exists()


@pytest.mark.parametrize("measure_fixture", measure_fixtures.keys())
def test_copy_measure(test_db, measure_fixture, request):
measure = request.getfixturevalue(measure_fixture)
save_measure(measure)
assert (test_db.measures.input_path / measure.attrs.name).exists()

new_name = f"copy_{measure.attrs.name}"
new_description = f"copy of {measure.attrs.description}"

copy_measure(
old_name=measure.attrs.name, new_name=new_name, new_description=new_description
)
new_measure = get_measure(new_name)

assert (test_db.measures.input_path / new_name).exists()
assert measure == new_measure
34 changes: 21 additions & 13 deletions tests/test_object_model/test_measures.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,30 @@
)


def test_floodwall_read(test_db):
test_toml = test_db.input_path / "measures" / "seawall" / "seawall.toml"
assert test_toml.is_file()
@pytest.fixture
def test_floodwall(test_data_dir):
floodwall_model = {
"name": "test_seawall",
"description": "seawall",
"type": HazardType.floodwall,
"selection_type": SelectionType.polygon,
"elevation": UnitfulLength(value=12, units=UnitTypesLength.feet),
"polygon_file": str(test_data_dir / "polyline.geojson"),
}
return FloodWall(floodwall_model)

floodwall = FloodWall.load_file(test_toml)

assert isinstance(floodwall.attrs.name, str)
assert isinstance(floodwall.attrs.description, str)
assert isinstance(floodwall.attrs.type, HazardType)
assert isinstance(floodwall.attrs.elevation, UnitfulLength)
def test_floodwall_read(test_floodwall):
assert isinstance(test_floodwall.attrs.name, str)
assert isinstance(test_floodwall.attrs.description, str)
assert isinstance(test_floodwall.attrs.type, HazardType)
assert isinstance(test_floodwall.attrs.elevation, UnitfulLength)

assert floodwall.attrs.name == "seawall"
assert floodwall.attrs.description == "seawall"
assert floodwall.attrs.type == "floodwall"
assert floodwall.attrs.elevation.value == 12
assert floodwall.attrs.elevation.units == UnitTypesLength.feet
assert test_floodwall.attrs.name == "test_seawall"
assert test_floodwall.attrs.description == "seawall"
assert test_floodwall.attrs.type == "floodwall"
assert test_floodwall.attrs.elevation.value == 12
assert test_floodwall.attrs.elevation.units == UnitTypesLength.feet


def test_elevate_aggr_area_read(test_db):
Expand Down
Loading