floodmodeller-api 0.5.3.post2__py3-none-any.whl → 0.5.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.
Files changed (29) hide show
  1. floodmodeller_api/dat.py +41 -4
  2. floodmodeller_api/hydrology_plus/hydrology_plus_export.py +1 -2
  3. floodmodeller_api/ied.py +1 -1
  4. floodmodeller_api/test/test_dat.py +16 -1
  5. floodmodeller_api/test/test_data/River_Bridge.dat +1453 -0
  6. floodmodeller_api/test/test_data/River_Bridge.gxy +221 -0
  7. floodmodeller_api/test/test_data/River_Bridge_DAT_expected.json +27273 -0
  8. floodmodeller_api/test/test_data/River_Bridge_no_gxy.dat +1453 -0
  9. floodmodeller_api/test/test_data/River_Bridge_no_gxy_DAT_expected.json +26853 -0
  10. floodmodeller_api/test/test_gxy.py +98 -0
  11. floodmodeller_api/test/test_json.py +37 -2
  12. floodmodeller_api/test/test_unit.py +12 -0
  13. floodmodeller_api/to_from_json.py +16 -2
  14. floodmodeller_api/toolbox/model_build/structure_log/structure_log.py +8 -8
  15. floodmodeller_api/units/_base.py +30 -0
  16. floodmodeller_api/units/boundaries.py +4 -1
  17. floodmodeller_api/units/conduits.py +1 -1
  18. floodmodeller_api/units/losses.py +2 -2
  19. floodmodeller_api/units/sections.py +36 -0
  20. floodmodeller_api/units/structures.py +60 -13
  21. floodmodeller_api/units/unsupported.py +2 -2
  22. floodmodeller_api/validation/validation.py +6 -6
  23. floodmodeller_api/version.py +1 -1
  24. {floodmodeller_api-0.5.3.post2.dist-info → floodmodeller_api-0.5.5.dist-info}/METADATA +1 -1
  25. {floodmodeller_api-0.5.3.post2.dist-info → floodmodeller_api-0.5.5.dist-info}/RECORD +29 -23
  26. {floodmodeller_api-0.5.3.post2.dist-info → floodmodeller_api-0.5.5.dist-info}/WHEEL +0 -0
  27. {floodmodeller_api-0.5.3.post2.dist-info → floodmodeller_api-0.5.5.dist-info}/entry_points.txt +0 -0
  28. {floodmodeller_api-0.5.3.post2.dist-info → floodmodeller_api-0.5.5.dist-info}/licenses/LICENSE.txt +0 -0
  29. {floodmodeller_api-0.5.3.post2.dist-info → floodmodeller_api-0.5.5.dist-info}/top_level.txt +0 -0
floodmodeller_api/dat.py CHANGED
@@ -63,6 +63,8 @@ class DAT(FMFile):
63
63
 
64
64
  self._get_general_parameters()
65
65
  self._get_unit_definitions()
66
+ if self._gxy_data:
67
+ self._get_unit_locations()
66
68
 
67
69
  def update(self) -> None:
68
70
  """Updates the existing DAT based on any altered attributes"""
@@ -529,6 +531,33 @@ class DAT(FMFile):
529
531
  msg = f"Unexpected unit type encountered: {unit_type}"
530
532
  raise Exception(msg)
531
533
 
534
+ def _get_unit_locations(self):
535
+ # use gxy data to assign locations to units.
536
+ gxy_lines = self._gxy_data.splitlines()
537
+ line = 0
538
+ gxy_dict = {}
539
+ while True:
540
+ header = gxy_lines[line][1:-1].split("_", 2)
541
+
542
+ # header format for a unit is [TYPE_SUBTYPE_NAME], so simple check that our header is a unit is check split length is 3
543
+ if len(header) != 3: # noqa: PLR2004
544
+ break
545
+
546
+ x = float(gxy_lines[line + 1][2:].strip())
547
+ y = float(gxy_lines[line + 2][2:].strip())
548
+
549
+ # key should match ._unique_name attributes
550
+ gxy_dict[f"{header[0]}_{header[2]}"] = (x, y)
551
+
552
+ line += 4
553
+
554
+ for unit in self._all_units:
555
+ if unit.unit in ("COMMENT",):
556
+ break
557
+
558
+ if unit.unique_name in gxy_dict:
559
+ unit.set_cached_location_from_gxy(gxy_dict.pop(unit.unique_name))
560
+
532
561
  def _initialize_collections(self) -> None:
533
562
  # Initialize unit collections
534
563
  self.sections: dict[str, units.TSections] = {}
@@ -552,8 +581,11 @@ class DAT(FMFile):
552
581
  else:
553
582
  # Check to see whether unit type has associated subtypes so that unit name can be correctly assigned
554
583
  unit_name = self._get_unit_name(unit_type, unit_data)
555
- # Create instance of unit and add to relevant group
584
+
585
+ # fetch the relevant group that the unit belongs in
556
586
  unit_group = getattr(self, units.SUPPORTED_UNIT_TYPES[unit_type]["group"])
587
+
588
+ # Create instance of unit and add to group
557
589
  self._add_unit_to_group(unit_group, unit_type, unit_name, unit_data)
558
590
 
559
591
  def _get_unit_name(self, unit_type, unit_data):
@@ -571,12 +603,17 @@ class DAT(FMFile):
571
603
  ) -> None:
572
604
  # Raise exception if a duplicate label is encountered
573
605
  if unit_name in unit_group:
574
- msg = f'Duplicate label ({unit_name}) encountered within category: {units.SUPPORTED_UNIT_TYPES[unit_type]["group"]}'
606
+ msg = f"Duplicate label ({unit_name}) encountered within category: {units.SUPPORTED_UNIT_TYPES[unit_type]['group']}"
575
607
  raise Exception(msg)
576
608
  # Changes done to account for unit types with spaces/dashes eg Flat-V Weir
577
609
  unit_type_safe = unit_type.replace(" ", "_").replace("-", "_")
578
- unit_group[unit_name] = getattr(units, unit_type_safe)(unit_data, self._label_len)
579
- self._all_units.append(unit_group[unit_name])
610
+
611
+ # Get class object from unit type and instantiate unit with block data & length.
612
+ unit = getattr(units, unit_type_safe)(unit_data, self._label_len)
613
+
614
+ # Add unit to group, and to all units list.
615
+ unit_group[unit_name] = unit
616
+ self._all_units.append(unit)
580
617
 
581
618
  def _process_unsupported_unit(self, unit_type, unit_data) -> None:
582
619
  # Check to see whether unit type has associated subtypes so that unit name can be correctly assigned
@@ -97,8 +97,7 @@ class HydrologyPlusExport(FMFile):
97
97
  if s == scenario and float(sd) == storm_duration and float(rp) == return_period:
98
98
  return column
99
99
  msg = (
100
- "No matching event was found based on "
101
- f"{return_period=}, {storm_duration=}, {scenario=}"
100
+ f"No matching event was found based on {return_period=}, {storm_duration=}, {scenario=}"
102
101
  )
103
102
  raise ValueError(msg)
104
103
 
floodmodeller_api/ied.py CHANGED
@@ -181,7 +181,7 @@ class IED(FMFile):
181
181
  # Create instance of unit and add to relevant group
182
182
  unit_group = getattr(self, units.SUPPORTED_UNIT_TYPES[block["Type"]]["group"])
183
183
  if unit_name in unit_group:
184
- msg = f'Duplicate label ({unit_name}) encountered within category: {units.SUPPORTED_UNIT_TYPES[block["Type"]]["group"]}'
184
+ msg = f"Duplicate label ({unit_name}) encountered within category: {units.SUPPORTED_UNIT_TYPES[block['Type']]['group']}"
185
185
  raise Exception(msg)
186
186
  unit_group[unit_name] = getattr(units, block["Type"])(unit_data)
187
187
 
@@ -99,15 +99,30 @@ def test_dat_read_doesnt_change_data(test_workspace, tmp_path):
99
99
  if datfile.name.startswith("duplicate_unit_test"):
100
100
  # Skipping as invalid DAT (duplicate units)
101
101
  continue
102
+
102
103
  dat = DAT(datfile)
103
104
  first_output = dat._write()
104
105
  new_path = tmp_path / "tmp.dat"
105
106
  dat.save(new_path)
106
107
  second_dat = DAT(new_path)
107
- assert dat == second_dat, f"dat objects not equal for {datfile=}"
108
+ assert dat == second_dat, f"dat objects not equal for {datfile=}\n{dat.diff(second_dat)}"
108
109
  second_output = second_dat._write()
109
110
  assert first_output == second_output, f"dat outputs not equal for {datfile=}"
110
111
 
112
+ gxy_path = datfile.with_suffix(".gxy")
113
+ if gxy_path.exists():
114
+ second_gxy_path = new_path.with_suffix(".gxy")
115
+ assert second_gxy_path.exists(), f"updated .gxy not found when testing {datfile=}"
116
+
117
+ # note filecmp.cmp() doesnt work here because input/output data has different eol sequences.
118
+ assert (
119
+ gxy_path.read_text() == second_gxy_path.read_text()
120
+ ), f".gxy file content not identical for {datfile=}"
121
+
122
+ new_path.unlink()
123
+ if gxy_path.exists():
124
+ second_gxy_path.unlink()
125
+
111
126
 
112
127
  def test_insert_unit_before(units, dat_ex6):
113
128
  dat_ex6.insert_unit(units[0], add_before=dat_ex6.sections["P4000"])