From 09d8e4d07e6ecda23f8e3d5dce7d31227d734d4f Mon Sep 17 00:00:00 2001 From: Ardt Klapwijk Date: Mon, 27 Nov 2023 13:57:56 +0100 Subject: [PATCH 1/7] chore: add enum for analysis --- .../analysis_config_data/enums/analysis_enum.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 ra2ce/analyses/analysis_config_data/enums/analysis_enum.py diff --git a/ra2ce/analyses/analysis_config_data/enums/analysis_enum.py b/ra2ce/analyses/analysis_config_data/enums/analysis_enum.py new file mode 100644 index 000000000..2682a7d71 --- /dev/null +++ b/ra2ce/analyses/analysis_config_data/enums/analysis_enum.py @@ -0,0 +1,17 @@ +from ra2ce.configuration.ra2ce_enum_base import Ra2ceEnumBase + + +class AnalysisEnum(Ra2ceEnumBase): + SINGLE_LINK_REDUNDANCY = 1 + MULTI_LINK_REDUNDANCY = 2 + OPTIMAL_ROUTE_ORIGIN_DESTINATION = 3 + MULTI_LINK_ORIGIN_DESTINATION = 4 + OPTIMAL_ROUTE_ORIGIN_CLOSEST_DESTINATION = 5 + MULTI_LINK_ORIGIN_CLOSEST_DESTINATION = 6 + LOSSES = 7 + SINGLE_LINK_LOSSES = 8 + MULTI_LINK_LOSSES = 9 + MULTI_LINK_ISOLATED_LOCATIONS = 10 + DIRECT = 11 + EFFECTIVENESS_MEASURES = 12 + INVALID = 99 From 67fe509eb4b84dfc64dc97bc3f334dbf5313dea5 Mon Sep 17 00:00:00 2001 From: Ardt Klapwijk Date: Mon, 27 Nov 2023 14:18:48 +0100 Subject: [PATCH 2/7] chore: add enum for analysis --- .../analyses/analysis_config_data/analysis_config_data.py | 3 ++- .../analysis_config_data/analysis_config_data_reader.py | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ra2ce/analyses/analysis_config_data/analysis_config_data.py b/ra2ce/analyses/analysis_config_data/analysis_config_data.py index f433d02da..33364aa60 100644 --- a/ra2ce/analyses/analysis_config_data/analysis_config_data.py +++ b/ra2ce/analyses/analysis_config_data/analysis_config_data.py @@ -27,6 +27,7 @@ from pathlib import Path from typing import Optional +from ra2ce.analyses.analysis_config_data.enums.analysis_enum import AnalysisEnum from ra2ce.analyses.analysis_config_data.enums.weighing_enum import WeighingEnum from ra2ce.common.configuration.config_data_protocol import ConfigDataProtocol from ra2ce.graph.network_config_data.enums.aggregate_wl_enum import AggregateWlEnum @@ -66,7 +67,7 @@ class AnalysisSectionBase: """ name: str = "" - analysis: str = "" # should be enum + analysis: AnalysisEnum = field(default_factory=lambda: AnalysisEnum.INVALID) save_gpkg: bool = False save_csv: bool = False diff --git a/ra2ce/analyses/analysis_config_data/analysis_config_data_reader.py b/ra2ce/analyses/analysis_config_data/analysis_config_data_reader.py index 8c790b7ac..a72c0c83f 100644 --- a/ra2ce/analyses/analysis_config_data/analysis_config_data_reader.py +++ b/ra2ce/analyses/analysis_config_data/analysis_config_data_reader.py @@ -34,6 +34,7 @@ IndirectAnalysisNameList, ProjectSection, ) +from ra2ce.analyses.analysis_config_data.enums.analysis_enum import AnalysisEnum from ra2ce.analyses.analysis_config_data.enums.weighing_enum import WeighingEnum from ra2ce.common.configuration.ini_configuration_reader_protocol import ( ConfigDataReaderProtocol, @@ -97,6 +98,9 @@ def _get_analysis_section_indirect( self, section_name: str ) -> AnalysisSectionIndirect: _section = AnalysisSectionIndirect(**self._parser[section_name]) + _section.analysis = AnalysisEnum.get_enum( + self._parser.get(section_name, "analysis", fallback=None) + ) _section.save_gpkg = self._parser.getboolean( section_name, "save_gpkg", fallback=_section.save_gpkg ) @@ -184,6 +188,9 @@ def _get_analysis_section_indirect( def _get_analysis_section_direct(self, section_name: str) -> AnalysisSectionDirect: _section = AnalysisSectionDirect(**self._parser[section_name]) + _section.analysis = AnalysisEnum.get_enum( + self._parser.get(section_name, "analysis", fallback=None) + ) _section.save_gpkg = self._parser.getboolean( section_name, "save_gpkg", fallback=_section.save_gpkg ) From acf4603a1e06226df598bc9a43866ec31d0db799 Mon Sep 17 00:00:00 2001 From: Ardt Klapwijk Date: Mon, 27 Nov 2023 14:39:01 +0100 Subject: [PATCH 3/7] chore: add enum for analysis --- ra2ce/analyses/analysis_config_data/enums/analysis_enum.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ra2ce/analyses/analysis_config_data/enums/analysis_enum.py b/ra2ce/analyses/analysis_config_data/enums/analysis_enum.py index 2682a7d71..d556b7ad8 100644 --- a/ra2ce/analyses/analysis_config_data/enums/analysis_enum.py +++ b/ra2ce/analyses/analysis_config_data/enums/analysis_enum.py @@ -2,6 +2,7 @@ class AnalysisEnum(Ra2ceEnumBase): + # indirect SINGLE_LINK_REDUNDANCY = 1 MULTI_LINK_REDUNDANCY = 2 OPTIMAL_ROUTE_ORIGIN_DESTINATION = 3 @@ -12,6 +13,8 @@ class AnalysisEnum(Ra2ceEnumBase): SINGLE_LINK_LOSSES = 8 MULTI_LINK_LOSSES = 9 MULTI_LINK_ISOLATED_LOCATIONS = 10 - DIRECT = 11 - EFFECTIVENESS_MEASURES = 12 + # direct + DIRECT = 21 + EFFECTIVENESS_MEASURES = 22 + # invalid INVALID = 99 From fa507a8ec555daa677189b03b646f44ed19054ce Mon Sep 17 00:00:00 2001 From: Ardt Klapwijk Date: Mon, 27 Nov 2023 16:10:17 +0100 Subject: [PATCH 4/7] chore: add enum for analysis --- ra2ce/analyses/analysis_config_wrapper.py | 2 +- ra2ce/analyses/direct/analyses_direct.py | 15 +++++--- ra2ce/analyses/indirect/analyses_indirect.py | 34 +++++++++++++------ ra2ce/configuration/ra2ce_enum_base.py | 9 +++++ .../network_config_data.py | 2 +- .../network_config_data_validator.py | 4 ++- .../test_analysis_config_data.py | 13 ++++--- .../test_analysis_config_data_validator.py | 3 +- tests/analyses/direct/test_analyses_direct.py | 6 +++- .../analyses/test_analysis_config_wrapper.py | 5 +-- tests/runners/test_analysis_runner_factory.py | 7 ++-- tests/runners/test_direct_analysis_runner.py | 9 ++--- .../runners/test_indirect_analysis_runner.py | 4 ++- 13 files changed, 78 insertions(+), 35 deletions(-) diff --git a/ra2ce/analyses/analysis_config_wrapper.py b/ra2ce/analyses/analysis_config_wrapper.py index b9b9c1646..d3f8dff51 100644 --- a/ra2ce/analyses/analysis_config_wrapper.py +++ b/ra2ce/analyses/analysis_config_wrapper.py @@ -48,7 +48,7 @@ def initialize_output_dirs(self) -> None: """ # Create the output folders for a in self.config_data.analyses: - output_path = self.config_data.output_path.joinpath(a.analysis) + output_path = self.config_data.output_path.joinpath(a.analysis.config_value) output_path.mkdir(parents=True, exist_ok=True) @classmethod diff --git a/ra2ce/analyses/direct/analyses_direct.py b/ra2ce/analyses/direct/analyses_direct.py index 77daa54fa..8ae107b99 100644 --- a/ra2ce/analyses/direct/analyses_direct.py +++ b/ra2ce/analyses/direct/analyses_direct.py @@ -31,6 +31,7 @@ AnalysisConfigData, AnalysisSectionDirect, ) +from ra2ce.analyses.analysis_config_data.enums.analysis_enum import AnalysisEnum from ra2ce.analyses.direct.cost_benefit_analysis import EffectivenessMeasures from ra2ce.analyses.direct.damage.manual_damage_functions import ManualDamageFunctions from ra2ce.analyses.direct.damage_calculation import ( @@ -72,18 +73,20 @@ def execute(self): ) starttime = time.time() - if analysis.analysis == "direct": + if analysis.analysis == AnalysisEnum.DIRECT: gdf = self.road_damage( analysis ) # calls the coordinator for road damage calculation - elif analysis.analysis == "effectiveness_measures": + elif analysis.analysis == AnalysisEnum.EFFECTIVENESS_MEASURES: gdf = self.effectiveness_measures(analysis) else: gdf = [] - _output_path = self.config.output_path.joinpath(analysis.analysis) + _output_path = self.config.output_path.joinpath( + analysis.analysis.config_value + ) if analysis.save_gpkg: gpkg_path = _output_path.joinpath( analysis.name.replace(" ", "_") + ".gpkg" @@ -195,7 +198,7 @@ def effectiveness_measures(self, analysis: AnalysisSectionDirect): df_cba, costs_dict = em.cost_benefit_analysis(effectiveness_dict) df_cba.round(2).to_csv( self.config.output_path.joinpath( - analysis.analysis, "cost_benefit_analysis.csv" + analysis.analysis.config_value, "cost_benefit_analysis.csv" ), decimal=",", sep=";", @@ -206,7 +209,9 @@ def effectiveness_measures(self, analysis: AnalysisSectionDirect): df_costs = em.calculate_strategy_costs(df, costs_dict) df_costs = df_costs.astype(float).round(2) df_costs.to_csv( - self.config.output_path.joinpath(analysis.analysis, "output_analysis.csv"), + self.config.output_path.joinpath( + analysis.analysis.config_value, "output_analysis.csv" + ), decimal=",", sep=";", index=False, diff --git a/ra2ce/analyses/indirect/analyses_indirect.py b/ra2ce/analyses/indirect/analyses_indirect.py index ce794e9e8..60ae58c50 100644 --- a/ra2ce/analyses/indirect/analyses_indirect.py +++ b/ra2ce/analyses/indirect/analyses_indirect.py @@ -38,6 +38,7 @@ AnalysisConfigData, AnalysisSectionIndirect, ) +from ra2ce.analyses.analysis_config_data.enums.analysis_enum import AnalysisEnum from ra2ce.analyses.analysis_config_data.enums.weighing_enum import WeighingEnum from ra2ce.analyses.indirect.losses import Losses from ra2ce.analyses.indirect.origin_closest_destination import OriginClosestDestination @@ -947,7 +948,8 @@ def multi_link_isolated_locations( # Save the output results_hz_roads.to_file( self.config.output_path.joinpath( - analysis.analysis, f"flooded_and_isolated_roads_{hazard_name}.gpkg" + analysis.analysis.config_value, + f"flooded_and_isolated_roads_{hazard_name}.gpkg", ) ) @@ -1062,7 +1064,9 @@ def execute(self): starttime = time.time() gdf = pd.DataFrame() opt_routes = None - _output_path = self.config.output_path.joinpath(analysis.analysis) + _output_path = self.config.output_path.joinpath( + analysis.analysis.config_value + ) def _save_gpkg_analysis( base_graph, @@ -1085,13 +1089,13 @@ def _save_gpkg_analysis( ) graph_to_gpkg(base_graph, gpkg_path_edges, gpkg_path_nodes) - if analysis.analysis == "single_link_redundancy": + if analysis.analysis == AnalysisEnum.SINGLE_LINK_REDUNDANCY: g = self.graph_files.base_graph.get_graph() gdf = self.single_link_redundancy(g, analysis) - elif analysis.analysis == "multi_link_redundancy": + elif analysis.analysis == AnalysisEnum.MULTI_LINK_REDUNDANCY: g = self.graph_files.base_graph_hazard.get_graph() gdf = self.multi_link_redundancy(g, analysis) - elif analysis.analysis == "optimal_route_origin_destination": + elif analysis.analysis == AnalysisEnum.OPTIMAL_ROUTE_ORIGIN_DESTINATION: g = self.graph_files.origins_destinations_graph.get_graph() gdf = self.optimal_route_origin_destination(g, analysis) @@ -1119,7 +1123,7 @@ def _save_gpkg_analysis( (analysis.name.replace(" ", "_") + "_link_traffic.csv"), ) route_traffic_df.to_csv(impact_csv_path, index=False) - elif analysis.analysis == "multi_link_origin_destination": + elif analysis.analysis == AnalysisEnum.MULTI_LINK_ORIGIN_DESTINATION: g = self.graph_files.origins_destinations_graph_hazard.get_graph() gdf = self.multi_link_origin_destination(g, analysis) gdf_not_disrupted = self.optimal_route_origin_destination(g, analysis) @@ -1155,11 +1159,17 @@ def _save_gpkg_analysis( (analysis.name.replace(" ", "_") + "_impact_summary.csv"), ) disruption_impact_df.to_csv(impact_csv_path, index=False) - elif analysis.analysis in ["single_link_losses", "multi_link_losses)"]: + elif analysis.analysis in [ + AnalysisEnum.SINGLE_LINK_LOSSES, + AnalysisEnum.MULTI_LINK_LOSSES, + ]: g = self.graph_files.base_graph_hazard.get_graph() gdf = self.single_link_redundancy(g, analysis) gdf = self.single_link_losses(gdf, analysis) - elif analysis.analysis == "optimal_route_origin_closest_destination": + elif ( + analysis.analysis + == AnalysisEnum.OPTIMAL_ROUTE_ORIGIN_CLOSEST_DESTINATION + ): analyzer = OriginClosestDestination( self.config, analysis, self.graph_files, self.hazard_names_df ) @@ -1186,7 +1196,9 @@ def _save_gpkg_analysis( ) del opt_routes["geometry"] opt_routes.to_csv(csv_path, index=False) - elif analysis.analysis == "multi_link_origin_closest_destination": + elif ( + analysis.analysis == AnalysisEnum.MULTI_LINK_ORIGIN_CLOSEST_DESTINATION + ): analyzer = OriginClosestDestination( self.config, analysis, self.graph_files, self.hazard_names_df ) @@ -1268,12 +1280,12 @@ def _save_gpkg_analysis( ), index=False, ) - elif analysis.analysis == "losses": + elif analysis.analysis == AnalysisEnum.LOSSES: gdf_in = self.graph_files.base_graph_hazard.get_graph() losses = Losses(self.config, analysis) df = losses.calculate_losses_from_table() gdf = gdf_in.merge(df, how="left", on="LinkNr") - elif analysis.analysis == "multi_link_isolated_locations": + elif analysis.analysis == AnalysisEnum.MULTI_LINK_ISOLATED_LOCATIONS: g = self.graph_files.base_graph_hazard.get_graph() (gdf, df) = self.multi_link_isolated_locations(g, analysis) diff --git a/ra2ce/configuration/ra2ce_enum_base.py b/ra2ce/configuration/ra2ce_enum_base.py index 4c119d62f..62e53c2aa 100644 --- a/ra2ce/configuration/ra2ce_enum_base.py +++ b/ra2ce/configuration/ra2ce_enum_base.py @@ -53,6 +53,15 @@ def list_valid_options(self) -> list[Ra2ceEnumBase]: """ return [_enum for _enum in type(self)][:-1] + def __str__(self) -> str: + """ + Overwrite the default __str__ + + Returns: + str: Value as in the config + """ + return str(self.config_value) + @property def config_value(self) -> str | None: """ diff --git a/ra2ce/graph/network_config_data/network_config_data.py b/ra2ce/graph/network_config_data/network_config_data.py index 1b4d8f11a..c2a03aab1 100644 --- a/ra2ce/graph/network_config_data/network_config_data.py +++ b/ra2ce/graph/network_config_data/network_config_data.py @@ -48,7 +48,7 @@ class NetworkSection: file_id: str = "" polygon: Optional[Path] = None network_type: NetworkTypeEnum = field(default_factory=lambda: NetworkTypeEnum.NONE) - road_types: list[RoadTypeEnum] = field(default_factory=lambda: list) + road_types: list[RoadTypeEnum] = field(default_factory=list) save_gpkg: bool = False diff --git a/ra2ce/graph/network_config_data/network_config_data_validator.py b/ra2ce/graph/network_config_data/network_config_data_validator.py index ee9ce02c3..c778b3cd2 100644 --- a/ra2ce/graph/network_config_data/network_config_data_validator.py +++ b/ra2ce/graph/network_config_data/network_config_data_validator.py @@ -111,7 +111,9 @@ def _validate_network_section( ) # Validate road types. - if any(not _type.is_valid() for _type in network_section.road_types): + if network_section.road_types and any( + not _type.is_valid() for _type in network_section.road_types + ): _network_report.error( f"Wrong road type(s) configured; has to be one or multiple of: {[_type.config_value for _type in network_section.road_types[0].list_valid_options()]}" ) diff --git a/tests/analyses/analysis_config_data/test_analysis_config_data.py b/tests/analyses/analysis_config_data/test_analysis_config_data.py index 6862dd7ae..557782998 100644 --- a/tests/analyses/analysis_config_data/test_analysis_config_data.py +++ b/tests/analyses/analysis_config_data/test_analysis_config_data.py @@ -8,6 +8,7 @@ IndirectAnalysisNameList, ProjectSection, ) +from ra2ce.analyses.analysis_config_data.enums.analysis_enum import AnalysisEnum from tests import test_results @@ -22,16 +23,20 @@ def test_initialize(self): def valid_config(self) -> AnalysisConfigData: _config = AnalysisConfigData(project=ProjectSection()) for _indirect in IndirectAnalysisNameList: - _config.analyses.append(AnalysisSectionIndirect(analysis=_indirect)) + _config.analyses.append( + AnalysisSectionIndirect(analysis=AnalysisEnum.get_enum(_indirect)) + ) for _direct in DirectAnalysisNameList: - _config.analyses.append(AnalysisSectionDirect(analysis=_direct)) + _config.analyses.append( + AnalysisSectionDirect(analysis=AnalysisEnum.get_enum(_direct)) + ) yield _config def test_indirect(self, valid_config: AnalysisConfigData): # 1. Define test data # 2. Run test - _indirect = [_config.analysis for _config in valid_config.indirect] + _indirect = [_config.analysis.config_value for _config in valid_config.indirect] # 3. Verify expectations assert all(item in _indirect for item in IndirectAnalysisNameList) @@ -40,7 +45,7 @@ def test_direct(self, valid_config: AnalysisConfigData): # 1. Define test data # 2. Run test - _direct = [_config.analysis for _config in valid_config.direct] + _direct = [_config.analysis.config_value for _config in valid_config.direct] # 3. Verify expectations assert all(item in _direct for item in DirectAnalysisNameList) diff --git a/tests/analyses/analysis_config_data/test_analysis_config_data_validator.py b/tests/analyses/analysis_config_data/test_analysis_config_data_validator.py index c5f6b08ed..7f1bf981f 100644 --- a/tests/analyses/analysis_config_data/test_analysis_config_data_validator.py +++ b/tests/analyses/analysis_config_data/test_analysis_config_data_validator.py @@ -6,6 +6,7 @@ from ra2ce.analyses.analysis_config_data.analysis_config_data_validator import ( AnalysisConfigDataValidator, ) +from ra2ce.analyses.analysis_config_data.enums.analysis_enum import AnalysisEnum from ra2ce.common.validation.ra2ce_validator_protocol import Ra2ceIoValidator from ra2ce.common.validation.validation_report import ValidationReport from tests import test_data, test_results @@ -35,7 +36,7 @@ def test_validate_with_required_headers(self): # 2. Run test. _test_config_data = AnalysisConfigData( project=ProjectSection(), - analyses=AnalysisSectionBase(), + analyses=AnalysisSectionBase(analysis=AnalysisEnum.DIRECT), output_path=_output_test_dir, ) _report = self._validate_config(_test_config_data) diff --git a/tests/analyses/direct/test_analyses_direct.py b/tests/analyses/direct/test_analyses_direct.py index a1ce34e78..76539de06 100644 --- a/tests/analyses/direct/test_analyses_direct.py +++ b/tests/analyses/direct/test_analyses_direct.py @@ -2,6 +2,7 @@ AnalysisConfigData, AnalysisSectionDirect, ) +from ra2ce.analyses.analysis_config_data.enums.analysis_enum import AnalysisEnum from ra2ce.analyses.direct.analyses_direct import DirectAnalyses from tests import test_data @@ -17,7 +18,10 @@ def test_execute(self): _config = AnalysisConfigData( analyses=[ AnalysisSectionDirect( - name="DummyExecute", analysis="", save_gpkg=False, save_csv=False + name="DummyExecute", + analysis=AnalysisEnum.INVALID, + save_gpkg=False, + save_csv=False, ) ], output_path=test_data, diff --git a/tests/analyses/test_analysis_config_wrapper.py b/tests/analyses/test_analysis_config_wrapper.py index 16260589e..36f33ee9c 100644 --- a/tests/analyses/test_analysis_config_wrapper.py +++ b/tests/analyses/test_analysis_config_wrapper.py @@ -8,6 +8,7 @@ AnalysisSectionDirect, AnalysisSectionIndirect, ) +from ra2ce.analyses.analysis_config_data.enums.analysis_enum import AnalysisEnum from ra2ce.analyses.analysis_config_wrapper import AnalysisConfigWrapper from ra2ce.graph.network_config_wrapper import NetworkConfigWrapper from tests import test_data, test_results @@ -73,8 +74,8 @@ def test_initialize_output_dirs_with_valid_data( _output_dir = test_results / request.node.name _analysis.config_data = AnalysisConfigData(output_path=_output_dir) _analysis.config_data.analyses = [ - AnalysisSectionDirect(analysis="effectiveness_measures"), - AnalysisSectionIndirect(analysis="single_link_redundancy"), + AnalysisSectionDirect(analysis=AnalysisEnum.EFFECTIVENESS_MEASURES), + AnalysisSectionIndirect(analysis=AnalysisEnum.SINGLE_LINK_REDUNDANCY), ] if _output_dir.exists(): shutil.rmtree(_output_dir) diff --git a/tests/runners/test_analysis_runner_factory.py b/tests/runners/test_analysis_runner_factory.py index 6c79de1df..9eb4464b0 100644 --- a/tests/runners/test_analysis_runner_factory.py +++ b/tests/runners/test_analysis_runner_factory.py @@ -1,10 +1,11 @@ import pytest + from ra2ce.analyses.analysis_config_data.analysis_config_data import ( AnalysisConfigData, AnalysisSectionDirect, AnalysisSectionIndirect, ) - +from ra2ce.analyses.analysis_config_data.enums.analysis_enum import AnalysisEnum from ra2ce.graph.network_config_data.network_config_data import NetworkConfigData from ra2ce.runners.analysis_runner_factory import AnalysisRunnerFactory from ra2ce.runners.analysis_runner_protocol import AnalysisRunner @@ -28,8 +29,8 @@ def test_get_runner_with_many_supported_runners_returns_analysis_runner_instance _config_wrapper = DummyRa2ceInput() _config_wrapper.analysis_config.config_data = AnalysisConfigData( analyses=[ - AnalysisSectionDirect(analysis="effectiveness_measures"), - AnalysisSectionIndirect(analysis="single_link_redundancy"), + AnalysisSectionDirect(analysis=AnalysisEnum.EFFECTIVENESS_MEASURES), + AnalysisSectionIndirect(analysis=AnalysisEnum.SINGLE_LINK_REDUNDANCY), ] ) _config_wrapper.network_config.config_data = NetworkConfigData() diff --git a/tests/runners/test_direct_analysis_runner.py b/tests/runners/test_direct_analysis_runner.py index 29619b968..76385fb30 100644 --- a/tests/runners/test_direct_analysis_runner.py +++ b/tests/runners/test_direct_analysis_runner.py @@ -1,8 +1,9 @@ import pytest + from ra2ce.analyses.analysis_config_data.analysis_config_data import ( AnalysisSectionDirect, ) - +from ra2ce.analyses.analysis_config_data.enums.analysis_enum import AnalysisEnum from ra2ce.configuration.config_wrapper import ConfigWrapper from ra2ce.runners.direct_analysis_runner import DirectAnalysisRunner from tests.runners.dummy_classes import DummyRa2ceInput @@ -22,7 +23,7 @@ def dummy_ra2ce_input(self): def test_given_direct_configuration_can_run(self, dummy_ra2ce_input: ConfigWrapper): # 1. Define test data. dummy_ra2ce_input.analysis_config.config_data.analyses = [ - AnalysisSectionDirect(analysis="effectiveness_measures") + AnalysisSectionDirect(analysis=AnalysisEnum.EFFECTIVENESS_MEASURES) ] dummy_ra2ce_input.network_config.config_data.hazard.hazard_map = "A value" @@ -49,7 +50,7 @@ def test_given_wrong_network_hazard_configuration_cannot_run( ): # 1. Define test data. dummy_ra2ce_input.analysis_config.config_data.analyses = [ - AnalysisSectionDirect(analysis="effectiveness_measures") + AnalysisSectionDirect(analysis=AnalysisEnum.EFFECTIVENESS_MEASURES) ] # 2. Run test. @@ -63,7 +64,7 @@ def test_given_no_network_config_returns_false( ): # 1. Define test data. dummy_ra2ce_input.analysis_config.config_data.analyses = [ - AnalysisSectionDirect(analysis="effectiveness_measures") + AnalysisSectionDirect(analysis=AnalysisEnum.EFFECTIVENESS_MEASURES) ] dummy_ra2ce_input.network_config = None diff --git a/tests/runners/test_indirect_analysis_runner.py b/tests/runners/test_indirect_analysis_runner.py index 205d0d16b..bbc1d877c 100644 --- a/tests/runners/test_indirect_analysis_runner.py +++ b/tests/runners/test_indirect_analysis_runner.py @@ -1,7 +1,9 @@ import pytest + from ra2ce.analyses.analysis_config_data.analysis_config_data import ( AnalysisSectionIndirect, ) +from ra2ce.analyses.analysis_config_data.enums.analysis_enum import AnalysisEnum from ra2ce.configuration.config_wrapper import ConfigWrapper from ra2ce.runners.indirect_analysis_runner import IndirectAnalysisRunner from tests.runners.dummy_classes import DummyRa2ceInput @@ -23,7 +25,7 @@ def test_given_indirect_configuration_can_run( ): # 1. Define test data. dummy_ra2ce_input.analysis_config.config_data.analyses = [ - AnalysisSectionIndirect(analysis="single_link_redundancy") + AnalysisSectionIndirect(analysis=AnalysisEnum.SINGLE_LINK_REDUNDANCY) ] # 2. Run test. From 5d46752cd985f0e83c381576ab110cc6b003f5ae Mon Sep 17 00:00:00 2001 From: Ardt Klapwijk Date: Tue, 28 Nov 2023 08:57:47 +0100 Subject: [PATCH 5/7] chore: split AnalysisEnum in direct and indirect --- .../analysis_config_data.py | 14 ++++++-- .../analysis_config_data_reader.py | 11 +++++-- .../enums/analysis_direct_enum.py | 7 ++++ ...ysis_enum.py => analysis_indirect_enum.py} | 7 +--- ra2ce/analyses/direct/analyses_direct.py | 8 +++-- ra2ce/analyses/indirect/analyses_indirect.py | 33 ++++++++++++------- .../test_analysis_config_data.py | 13 ++++++-- .../test_analysis_config_data_validator.py | 10 +++--- tests/analyses/direct/test_analyses_direct.py | 6 ++-- .../analyses/test_analysis_config_wrapper.py | 13 ++++++-- tests/runners/test_analysis_runner_factory.py | 15 +++++++-- tests/runners/test_direct_analysis_runner.py | 10 +++--- .../runners/test_indirect_analysis_runner.py | 8 +++-- 13 files changed, 108 insertions(+), 47 deletions(-) create mode 100644 ra2ce/analyses/analysis_config_data/enums/analysis_direct_enum.py rename ra2ce/analyses/analysis_config_data/enums/{analysis_enum.py => analysis_indirect_enum.py} (77%) diff --git a/ra2ce/analyses/analysis_config_data/analysis_config_data.py b/ra2ce/analyses/analysis_config_data/analysis_config_data.py index 33364aa60..f6544f4cc 100644 --- a/ra2ce/analyses/analysis_config_data/analysis_config_data.py +++ b/ra2ce/analyses/analysis_config_data/analysis_config_data.py @@ -27,7 +27,12 @@ from pathlib import Path from typing import Optional -from ra2ce.analyses.analysis_config_data.enums.analysis_enum import AnalysisEnum +from ra2ce.analyses.analysis_config_data.enums.analysis_direct_enum import ( + AnalysisDirectEnum, +) +from ra2ce.analyses.analysis_config_data.enums.analysis_indirect_enum import ( + AnalysisIndirectEnum, +) from ra2ce.analyses.analysis_config_data.enums.weighing_enum import WeighingEnum from ra2ce.common.configuration.config_data_protocol import ConfigDataProtocol from ra2ce.graph.network_config_data.enums.aggregate_wl_enum import AggregateWlEnum @@ -67,7 +72,6 @@ class AnalysisSectionBase: """ name: str = "" - analysis: AnalysisEnum = field(default_factory=lambda: AnalysisEnum.INVALID) save_gpkg: bool = False save_csv: bool = False @@ -78,6 +82,9 @@ class AnalysisSectionIndirect(AnalysisSectionBase): Reflects all possible settings that an indirect analysis section might contain. """ + analysis: AnalysisIndirectEnum = field( + default_factory=lambda: AnalysisIndirectEnum.INVALID + ) # general weighing: WeighingEnum = field(default_factory=lambda: WeighingEnum.NONE) loss_per_distance: str = "" @@ -112,6 +119,9 @@ class AnalysisSectionDirect(AnalysisSectionBase): Reflects all possible settings that a direct analysis section might contain. """ + analysis: AnalysisDirectEnum = field( + default_factory=lambda: AnalysisDirectEnum.INVALID + ) # adaptation/effectiveness measures return_period: float = math.nan repair_costs: float = math.nan diff --git a/ra2ce/analyses/analysis_config_data/analysis_config_data_reader.py b/ra2ce/analyses/analysis_config_data/analysis_config_data_reader.py index f5ac11732..2556eb8a4 100644 --- a/ra2ce/analyses/analysis_config_data/analysis_config_data_reader.py +++ b/ra2ce/analyses/analysis_config_data/analysis_config_data_reader.py @@ -34,7 +34,12 @@ IndirectAnalysisNameList, ProjectSection, ) -from ra2ce.analyses.analysis_config_data.enums.analysis_enum import AnalysisEnum +from ra2ce.analyses.analysis_config_data.enums.analysis_direct_enum import ( + AnalysisDirectEnum, +) +from ra2ce.analyses.analysis_config_data.enums.analysis_indirect_enum import ( + AnalysisIndirectEnum, +) from ra2ce.analyses.analysis_config_data.enums.weighing_enum import WeighingEnum from ra2ce.common.configuration.ini_configuration_reader_protocol import ( ConfigDataReaderProtocol, @@ -98,7 +103,7 @@ def _get_analysis_section_indirect( self, section_name: str ) -> AnalysisSectionIndirect: _section = AnalysisSectionIndirect(**self._parser[section_name]) - _section.analysis = AnalysisEnum.get_enum( + _section.analysis = AnalysisIndirectEnum.get_enum( self._parser.get(section_name, "analysis", fallback=None) ) _section.save_gpkg = self._parser.getboolean( @@ -191,7 +196,7 @@ def _get_analysis_section_indirect( def _get_analysis_section_direct(self, section_name: str) -> AnalysisSectionDirect: _section = AnalysisSectionDirect(**self._parser[section_name]) - _section.analysis = AnalysisEnum.get_enum( + _section.analysis = AnalysisDirectEnum.get_enum( self._parser.get(section_name, "analysis", fallback=None) ) _section.save_gpkg = self._parser.getboolean( diff --git a/ra2ce/analyses/analysis_config_data/enums/analysis_direct_enum.py b/ra2ce/analyses/analysis_config_data/enums/analysis_direct_enum.py new file mode 100644 index 000000000..a39ce951e --- /dev/null +++ b/ra2ce/analyses/analysis_config_data/enums/analysis_direct_enum.py @@ -0,0 +1,7 @@ +from ra2ce.configuration.ra2ce_enum_base import Ra2ceEnumBase + + +class AnalysisDirectEnum(Ra2ceEnumBase): + DIRECT = 1 + EFFECTIVENESS_MEASURES = 2 + INVALID = 99 diff --git a/ra2ce/analyses/analysis_config_data/enums/analysis_enum.py b/ra2ce/analyses/analysis_config_data/enums/analysis_indirect_enum.py similarity index 77% rename from ra2ce/analyses/analysis_config_data/enums/analysis_enum.py rename to ra2ce/analyses/analysis_config_data/enums/analysis_indirect_enum.py index d556b7ad8..fa618e3ad 100644 --- a/ra2ce/analyses/analysis_config_data/enums/analysis_enum.py +++ b/ra2ce/analyses/analysis_config_data/enums/analysis_indirect_enum.py @@ -1,8 +1,7 @@ from ra2ce.configuration.ra2ce_enum_base import Ra2ceEnumBase -class AnalysisEnum(Ra2ceEnumBase): - # indirect +class AnalysisIndirectEnum(Ra2ceEnumBase): SINGLE_LINK_REDUNDANCY = 1 MULTI_LINK_REDUNDANCY = 2 OPTIMAL_ROUTE_ORIGIN_DESTINATION = 3 @@ -13,8 +12,4 @@ class AnalysisEnum(Ra2ceEnumBase): SINGLE_LINK_LOSSES = 8 MULTI_LINK_LOSSES = 9 MULTI_LINK_ISOLATED_LOCATIONS = 10 - # direct - DIRECT = 21 - EFFECTIVENESS_MEASURES = 22 - # invalid INVALID = 99 diff --git a/ra2ce/analyses/direct/analyses_direct.py b/ra2ce/analyses/direct/analyses_direct.py index 8ae107b99..b14e790e5 100644 --- a/ra2ce/analyses/direct/analyses_direct.py +++ b/ra2ce/analyses/direct/analyses_direct.py @@ -31,7 +31,9 @@ AnalysisConfigData, AnalysisSectionDirect, ) -from ra2ce.analyses.analysis_config_data.enums.analysis_enum import AnalysisEnum +from ra2ce.analyses.analysis_config_data.enums.analysis_direct_enum import ( + AnalysisDirectEnum, +) from ra2ce.analyses.direct.cost_benefit_analysis import EffectivenessMeasures from ra2ce.analyses.direct.damage.manual_damage_functions import ManualDamageFunctions from ra2ce.analyses.direct.damage_calculation import ( @@ -73,12 +75,12 @@ def execute(self): ) starttime = time.time() - if analysis.analysis == AnalysisEnum.DIRECT: + if analysis.analysis == AnalysisDirectEnum.DIRECT: gdf = self.road_damage( analysis ) # calls the coordinator for road damage calculation - elif analysis.analysis == AnalysisEnum.EFFECTIVENESS_MEASURES: + elif analysis.analysis == AnalysisDirectEnum.EFFECTIVENESS_MEASURES: gdf = self.effectiveness_measures(analysis) else: diff --git a/ra2ce/analyses/indirect/analyses_indirect.py b/ra2ce/analyses/indirect/analyses_indirect.py index 60ae58c50..931ad1a43 100644 --- a/ra2ce/analyses/indirect/analyses_indirect.py +++ b/ra2ce/analyses/indirect/analyses_indirect.py @@ -23,7 +23,6 @@ import logging import time from pathlib import Path -from typing import Any import geopandas as gpd import networkx as nx @@ -38,7 +37,9 @@ AnalysisConfigData, AnalysisSectionIndirect, ) -from ra2ce.analyses.analysis_config_data.enums.analysis_enum import AnalysisEnum +from ra2ce.analyses.analysis_config_data.enums.analysis_indirect_enum import ( + AnalysisIndirectEnum, +) from ra2ce.analyses.analysis_config_data.enums.weighing_enum import WeighingEnum from ra2ce.analyses.indirect.losses import Losses from ra2ce.analyses.indirect.origin_closest_destination import OriginClosestDestination @@ -1089,13 +1090,16 @@ def _save_gpkg_analysis( ) graph_to_gpkg(base_graph, gpkg_path_edges, gpkg_path_nodes) - if analysis.analysis == AnalysisEnum.SINGLE_LINK_REDUNDANCY: + if analysis.analysis == AnalysisIndirectEnum.SINGLE_LINK_REDUNDANCY: g = self.graph_files.base_graph.get_graph() gdf = self.single_link_redundancy(g, analysis) - elif analysis.analysis == AnalysisEnum.MULTI_LINK_REDUNDANCY: + elif analysis.analysis == AnalysisIndirectEnum.MULTI_LINK_REDUNDANCY: g = self.graph_files.base_graph_hazard.get_graph() gdf = self.multi_link_redundancy(g, analysis) - elif analysis.analysis == AnalysisEnum.OPTIMAL_ROUTE_ORIGIN_DESTINATION: + elif ( + analysis.analysis + == AnalysisIndirectEnum.OPTIMAL_ROUTE_ORIGIN_DESTINATION + ): g = self.graph_files.origins_destinations_graph.get_graph() gdf = self.optimal_route_origin_destination(g, analysis) @@ -1123,7 +1127,9 @@ def _save_gpkg_analysis( (analysis.name.replace(" ", "_") + "_link_traffic.csv"), ) route_traffic_df.to_csv(impact_csv_path, index=False) - elif analysis.analysis == AnalysisEnum.MULTI_LINK_ORIGIN_DESTINATION: + elif ( + analysis.analysis == AnalysisIndirectEnum.MULTI_LINK_ORIGIN_DESTINATION + ): g = self.graph_files.origins_destinations_graph_hazard.get_graph() gdf = self.multi_link_origin_destination(g, analysis) gdf_not_disrupted = self.optimal_route_origin_destination(g, analysis) @@ -1160,15 +1166,15 @@ def _save_gpkg_analysis( ) disruption_impact_df.to_csv(impact_csv_path, index=False) elif analysis.analysis in [ - AnalysisEnum.SINGLE_LINK_LOSSES, - AnalysisEnum.MULTI_LINK_LOSSES, + AnalysisIndirectEnum.SINGLE_LINK_LOSSES, + AnalysisIndirectEnum.MULTI_LINK_LOSSES, ]: g = self.graph_files.base_graph_hazard.get_graph() gdf = self.single_link_redundancy(g, analysis) gdf = self.single_link_losses(gdf, analysis) elif ( analysis.analysis - == AnalysisEnum.OPTIMAL_ROUTE_ORIGIN_CLOSEST_DESTINATION + == AnalysisIndirectEnum.OPTIMAL_ROUTE_ORIGIN_CLOSEST_DESTINATION ): analyzer = OriginClosestDestination( self.config, analysis, self.graph_files, self.hazard_names_df @@ -1197,7 +1203,8 @@ def _save_gpkg_analysis( del opt_routes["geometry"] opt_routes.to_csv(csv_path, index=False) elif ( - analysis.analysis == AnalysisEnum.MULTI_LINK_ORIGIN_CLOSEST_DESTINATION + analysis.analysis + == AnalysisIndirectEnum.MULTI_LINK_ORIGIN_CLOSEST_DESTINATION ): analyzer = OriginClosestDestination( self.config, analysis, self.graph_files, self.hazard_names_df @@ -1280,12 +1287,14 @@ def _save_gpkg_analysis( ), index=False, ) - elif analysis.analysis == AnalysisEnum.LOSSES: + elif analysis.analysis == AnalysisIndirectEnum.LOSSES: gdf_in = self.graph_files.base_graph_hazard.get_graph() losses = Losses(self.config, analysis) df = losses.calculate_losses_from_table() gdf = gdf_in.merge(df, how="left", on="LinkNr") - elif analysis.analysis == AnalysisEnum.MULTI_LINK_ISOLATED_LOCATIONS: + elif ( + analysis.analysis == AnalysisIndirectEnum.MULTI_LINK_ISOLATED_LOCATIONS + ): g = self.graph_files.base_graph_hazard.get_graph() (gdf, df) = self.multi_link_isolated_locations(g, analysis) diff --git a/tests/analyses/analysis_config_data/test_analysis_config_data.py b/tests/analyses/analysis_config_data/test_analysis_config_data.py index 557782998..ce1051edc 100644 --- a/tests/analyses/analysis_config_data/test_analysis_config_data.py +++ b/tests/analyses/analysis_config_data/test_analysis_config_data.py @@ -8,7 +8,12 @@ IndirectAnalysisNameList, ProjectSection, ) -from ra2ce.analyses.analysis_config_data.enums.analysis_enum import AnalysisEnum +from ra2ce.analyses.analysis_config_data.enums.analysis_direct_enum import ( + AnalysisDirectEnum, +) +from ra2ce.analyses.analysis_config_data.enums.analysis_indirect_enum import ( + AnalysisIndirectEnum, +) from tests import test_results @@ -24,11 +29,13 @@ def valid_config(self) -> AnalysisConfigData: _config = AnalysisConfigData(project=ProjectSection()) for _indirect in IndirectAnalysisNameList: _config.analyses.append( - AnalysisSectionIndirect(analysis=AnalysisEnum.get_enum(_indirect)) + AnalysisSectionIndirect( + analysis=AnalysisIndirectEnum.get_enum(_indirect) + ) ) for _direct in DirectAnalysisNameList: _config.analyses.append( - AnalysisSectionDirect(analysis=AnalysisEnum.get_enum(_direct)) + AnalysisSectionDirect(analysis=AnalysisDirectEnum.get_enum(_direct)) ) yield _config diff --git a/tests/analyses/analysis_config_data/test_analysis_config_data_validator.py b/tests/analyses/analysis_config_data/test_analysis_config_data_validator.py index 7f1bf981f..8714e2af5 100644 --- a/tests/analyses/analysis_config_data/test_analysis_config_data_validator.py +++ b/tests/analyses/analysis_config_data/test_analysis_config_data_validator.py @@ -1,12 +1,14 @@ from ra2ce.analyses.analysis_config_data.analysis_config_data import ( AnalysisConfigData, - AnalysisSectionBase, + AnalysisSectionDirect, ProjectSection, ) from ra2ce.analyses.analysis_config_data.analysis_config_data_validator import ( AnalysisConfigDataValidator, ) -from ra2ce.analyses.analysis_config_data.enums.analysis_enum import AnalysisEnum +from ra2ce.analyses.analysis_config_data.enums.analysis_direct_enum import ( + AnalysisDirectEnum, +) from ra2ce.common.validation.ra2ce_validator_protocol import Ra2ceIoValidator from ra2ce.common.validation.validation_report import ValidationReport from tests import test_data, test_results @@ -36,7 +38,7 @@ def test_validate_with_required_headers(self): # 2. Run test. _test_config_data = AnalysisConfigData( project=ProjectSection(), - analyses=AnalysisSectionBase(analysis=AnalysisEnum.DIRECT), + analyses=AnalysisSectionDirect(analysis=AnalysisDirectEnum.DIRECT), output_path=_output_test_dir, ) _report = self._validate_config(_test_config_data) @@ -71,7 +73,7 @@ def test_validate_headers_fails_when_invalid_value(self): root_path=test_results, output_path=test_results.joinpath("output"), project=ProjectSection(), - analyses=[AnalysisSectionBase(analysis="invalid_analysis_type")], + analyses=[AnalysisSectionDirect(analysis="invalid_analysis_type")], ) # 2. Run test. diff --git a/tests/analyses/direct/test_analyses_direct.py b/tests/analyses/direct/test_analyses_direct.py index 76539de06..7bce4d7e6 100644 --- a/tests/analyses/direct/test_analyses_direct.py +++ b/tests/analyses/direct/test_analyses_direct.py @@ -2,7 +2,9 @@ AnalysisConfigData, AnalysisSectionDirect, ) -from ra2ce.analyses.analysis_config_data.enums.analysis_enum import AnalysisEnum +from ra2ce.analyses.analysis_config_data.enums.analysis_direct_enum import ( + AnalysisDirectEnum, +) from ra2ce.analyses.direct.analyses_direct import DirectAnalyses from tests import test_data @@ -19,7 +21,7 @@ def test_execute(self): analyses=[ AnalysisSectionDirect( name="DummyExecute", - analysis=AnalysisEnum.INVALID, + analysis=AnalysisDirectEnum.INVALID, save_gpkg=False, save_csv=False, ) diff --git a/tests/analyses/test_analysis_config_wrapper.py b/tests/analyses/test_analysis_config_wrapper.py index 36f33ee9c..a22c8780c 100644 --- a/tests/analyses/test_analysis_config_wrapper.py +++ b/tests/analyses/test_analysis_config_wrapper.py @@ -8,7 +8,12 @@ AnalysisSectionDirect, AnalysisSectionIndirect, ) -from ra2ce.analyses.analysis_config_data.enums.analysis_enum import AnalysisEnum +from ra2ce.analyses.analysis_config_data.enums.analysis_direct_enum import ( + AnalysisDirectEnum, +) +from ra2ce.analyses.analysis_config_data.enums.analysis_indirect_enum import ( + AnalysisIndirectEnum, +) from ra2ce.analyses.analysis_config_wrapper import AnalysisConfigWrapper from ra2ce.graph.network_config_wrapper import NetworkConfigWrapper from tests import test_data, test_results @@ -74,8 +79,10 @@ def test_initialize_output_dirs_with_valid_data( _output_dir = test_results / request.node.name _analysis.config_data = AnalysisConfigData(output_path=_output_dir) _analysis.config_data.analyses = [ - AnalysisSectionDirect(analysis=AnalysisEnum.EFFECTIVENESS_MEASURES), - AnalysisSectionIndirect(analysis=AnalysisEnum.SINGLE_LINK_REDUNDANCY), + AnalysisSectionDirect(analysis=AnalysisDirectEnum.EFFECTIVENESS_MEASURES), + AnalysisSectionIndirect( + analysis=AnalysisIndirectEnum.SINGLE_LINK_REDUNDANCY + ), ] if _output_dir.exists(): shutil.rmtree(_output_dir) diff --git a/tests/runners/test_analysis_runner_factory.py b/tests/runners/test_analysis_runner_factory.py index 9eb4464b0..8cd3076d4 100644 --- a/tests/runners/test_analysis_runner_factory.py +++ b/tests/runners/test_analysis_runner_factory.py @@ -5,7 +5,12 @@ AnalysisSectionDirect, AnalysisSectionIndirect, ) -from ra2ce.analyses.analysis_config_data.enums.analysis_enum import AnalysisEnum +from ra2ce.analyses.analysis_config_data.enums.analysis_direct_enum import ( + AnalysisDirectEnum, +) +from ra2ce.analyses.analysis_config_data.enums.analysis_indirect_enum import ( + AnalysisIndirectEnum, +) from ra2ce.graph.network_config_data.network_config_data import NetworkConfigData from ra2ce.runners.analysis_runner_factory import AnalysisRunnerFactory from ra2ce.runners.analysis_runner_protocol import AnalysisRunner @@ -29,8 +34,12 @@ def test_get_runner_with_many_supported_runners_returns_analysis_runner_instance _config_wrapper = DummyRa2ceInput() _config_wrapper.analysis_config.config_data = AnalysisConfigData( analyses=[ - AnalysisSectionDirect(analysis=AnalysisEnum.EFFECTIVENESS_MEASURES), - AnalysisSectionIndirect(analysis=AnalysisEnum.SINGLE_LINK_REDUNDANCY), + AnalysisSectionDirect( + analysis=AnalysisDirectEnum.EFFECTIVENESS_MEASURES + ), + AnalysisSectionIndirect( + analysis=AnalysisIndirectEnum.SINGLE_LINK_REDUNDANCY + ), ] ) _config_wrapper.network_config.config_data = NetworkConfigData() diff --git a/tests/runners/test_direct_analysis_runner.py b/tests/runners/test_direct_analysis_runner.py index 76385fb30..49e348b2f 100644 --- a/tests/runners/test_direct_analysis_runner.py +++ b/tests/runners/test_direct_analysis_runner.py @@ -3,7 +3,9 @@ from ra2ce.analyses.analysis_config_data.analysis_config_data import ( AnalysisSectionDirect, ) -from ra2ce.analyses.analysis_config_data.enums.analysis_enum import AnalysisEnum +from ra2ce.analyses.analysis_config_data.enums.analysis_direct_enum import ( + AnalysisDirectEnum, +) from ra2ce.configuration.config_wrapper import ConfigWrapper from ra2ce.runners.direct_analysis_runner import DirectAnalysisRunner from tests.runners.dummy_classes import DummyRa2ceInput @@ -23,7 +25,7 @@ def dummy_ra2ce_input(self): def test_given_direct_configuration_can_run(self, dummy_ra2ce_input: ConfigWrapper): # 1. Define test data. dummy_ra2ce_input.analysis_config.config_data.analyses = [ - AnalysisSectionDirect(analysis=AnalysisEnum.EFFECTIVENESS_MEASURES) + AnalysisSectionDirect(analysis=AnalysisDirectEnum.EFFECTIVENESS_MEASURES) ] dummy_ra2ce_input.network_config.config_data.hazard.hazard_map = "A value" @@ -50,7 +52,7 @@ def test_given_wrong_network_hazard_configuration_cannot_run( ): # 1. Define test data. dummy_ra2ce_input.analysis_config.config_data.analyses = [ - AnalysisSectionDirect(analysis=AnalysisEnum.EFFECTIVENESS_MEASURES) + AnalysisSectionDirect(analysis=AnalysisDirectEnum.EFFECTIVENESS_MEASURES) ] # 2. Run test. @@ -64,7 +66,7 @@ def test_given_no_network_config_returns_false( ): # 1. Define test data. dummy_ra2ce_input.analysis_config.config_data.analyses = [ - AnalysisSectionDirect(analysis=AnalysisEnum.EFFECTIVENESS_MEASURES) + AnalysisSectionDirect(analysis=AnalysisDirectEnum.EFFECTIVENESS_MEASURES) ] dummy_ra2ce_input.network_config = None diff --git a/tests/runners/test_indirect_analysis_runner.py b/tests/runners/test_indirect_analysis_runner.py index bbc1d877c..0d8d0fa0f 100644 --- a/tests/runners/test_indirect_analysis_runner.py +++ b/tests/runners/test_indirect_analysis_runner.py @@ -3,7 +3,9 @@ from ra2ce.analyses.analysis_config_data.analysis_config_data import ( AnalysisSectionIndirect, ) -from ra2ce.analyses.analysis_config_data.enums.analysis_enum import AnalysisEnum +from ra2ce.analyses.analysis_config_data.enums.analysis_indirect_enum import ( + AnalysisIndirectEnum, +) from ra2ce.configuration.config_wrapper import ConfigWrapper from ra2ce.runners.indirect_analysis_runner import IndirectAnalysisRunner from tests.runners.dummy_classes import DummyRa2ceInput @@ -25,7 +27,9 @@ def test_given_indirect_configuration_can_run( ): # 1. Define test data. dummy_ra2ce_input.analysis_config.config_data.analyses = [ - AnalysisSectionIndirect(analysis=AnalysisEnum.SINGLE_LINK_REDUNDANCY) + AnalysisSectionIndirect( + analysis=AnalysisIndirectEnum.SINGLE_LINK_REDUNDANCY + ) ] # 2. Run test. From 408849627c548f6a65fdff4547d9ab79c216ad23 Mon Sep 17 00:00:00 2001 From: Ardt Klapwijk Date: Tue, 28 Nov 2023 09:16:44 +0100 Subject: [PATCH 6/7] chore: convert get_valid_options into a @classmethod --- .../analysis_config_data/analysis_config_data.py | 15 ++++----------- .../analysis_config_data_validator.py | 2 +- ra2ce/configuration/ra2ce_enum_base.py | 5 +++-- .../network_config_data_validator.py | 4 ++-- tests/configuration/test_ra2ce_enum_base.py | 4 ++-- 5 files changed, 12 insertions(+), 18 deletions(-) diff --git a/ra2ce/analyses/analysis_config_data/analysis_config_data.py b/ra2ce/analyses/analysis_config_data/analysis_config_data.py index f6544f4cc..c7d525a19 100644 --- a/ra2ce/analyses/analysis_config_data/analysis_config_data.py +++ b/ra2ce/analyses/analysis_config_data/analysis_config_data.py @@ -42,18 +42,11 @@ ) IndirectAnalysisNameList: list[str] = [ - "single_link_redundancy", - "multi_link_redundancy", - "optimal_route_origin_destination", - "multi_link_origin_destination", - "optimal_route_origin_closest_destination", - "multi_link_origin_closest_destination", - "losses", - "single_link_losses", - "multi_link_losses", - "multi_link_isolated_locations", + _enum.config_value for _enum in AnalysisIndirectEnum.list_valid_options() +] +DirectAnalysisNameList: list[str] = [ + _enum.config_value for _enum in AnalysisDirectEnum.list_valid_options() ] -DirectAnalysisNameList: list[str] = ["direct", "effectiveness_measures"] @dataclass diff --git a/ra2ce/analyses/analysis_config_data/analysis_config_data_validator.py b/ra2ce/analyses/analysis_config_data/analysis_config_data_validator.py index e849c106c..de4b3da62 100644 --- a/ra2ce/analyses/analysis_config_data/analysis_config_data_validator.py +++ b/ra2ce/analyses/analysis_config_data/analysis_config_data_validator.py @@ -56,7 +56,7 @@ def _validate_header(self, header: Any) -> ValidationReport: continue if isinstance(value, Ra2ceEnumBase): # enumerations - _expected_values_list = value.list_valid_options() + _expected_values_list = type(value).list_valid_options() else: # other items with limited value options (should become enumerations) if key not in AnalysisNetworkDictValues.keys(): diff --git a/ra2ce/configuration/ra2ce_enum_base.py b/ra2ce/configuration/ra2ce_enum_base.py index 62e53c2aa..dad60a8a8 100644 --- a/ra2ce/configuration/ra2ce_enum_base.py +++ b/ra2ce/configuration/ra2ce_enum_base.py @@ -44,14 +44,15 @@ def is_valid(self) -> bool: return False return True - def list_valid_options(self) -> list[Ra2ceEnumBase]: + @classmethod + def list_valid_options(cls) -> list[Ra2ceEnumBase]: """ List the enum options as allowed in the config. Returns: list[str | None]: Concatenated options, separated by ", " """ - return [_enum for _enum in type(self)][:-1] + return [_enum for _enum in cls][:-1] def __str__(self) -> str: """ diff --git a/ra2ce/graph/network_config_data/network_config_data_validator.py b/ra2ce/graph/network_config_data/network_config_data_validator.py index c778b3cd2..c400065ec 100644 --- a/ra2ce/graph/network_config_data/network_config_data_validator.py +++ b/ra2ce/graph/network_config_data/network_config_data_validator.py @@ -78,7 +78,7 @@ def _wrong_value(self, key: str) -> str: def _wrong_enum(self, key: str, enum: Ra2ceEnumBase) -> str: # Remove last value INVALID - _accepted_values = enum.list_valid_options() + _accepted_values = type(enum).list_valid_options() return ( f"Wrong input to property [ {key} ]; has to be one of: {_accepted_values}." ) @@ -115,7 +115,7 @@ def _validate_network_section( not _type.is_valid() for _type in network_section.road_types ): _network_report.error( - f"Wrong road type(s) configured; has to be one or multiple of: {[_type.config_value for _type in network_section.road_types[0].list_valid_options()]}" + f"Wrong road type(s) configured; has to be one or multiple of: {[_type.config_value for _type in type(network_section.road_types[0]).list_valid_options()]}" ) return _network_report diff --git a/tests/configuration/test_ra2ce_enum_base.py b/tests/configuration/test_ra2ce_enum_base.py index c0ad2339c..c609f01cc 100644 --- a/tests/configuration/test_ra2ce_enum_base.py +++ b/tests/configuration/test_ra2ce_enum_base.py @@ -90,7 +90,7 @@ def test_is_valid(self, enum: Ra2ceEnumBase, expected_value: bool): def test_list_valid_options(self): # 1./2. Define test data / Run test - _options = MockEnum.FIRST.list_valid_options() + _options = MockEnum.list_valid_options() # 3. Verify results assert all( @@ -100,7 +100,7 @@ def test_list_valid_options(self): def test_list_valid_options_without_none(self): # 1./2. Define test data / Run test - _options = MockEnumWithoutNone.FIRST.list_valid_options() + _options = MockEnumWithoutNone.list_valid_options() # 3. Verify results all(_option in _options for _option in [MockEnum.FIRST, MockEnum.SECOND_ITEM]) From a65e54fd5cb59b18500a1fe2e30f052b621d038a Mon Sep 17 00:00:00 2001 From: Ardt Klapwijk Date: Tue, 28 Nov 2023 14:14:47 +0100 Subject: [PATCH 7/7] chore: process review comments --- .../analysis_config_data/analysis_config_data.py | 12 ++++++------ .../analysis_config_data_validator.py | 2 +- .../network_config_data_validator.py | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ra2ce/analyses/analysis_config_data/analysis_config_data.py b/ra2ce/analyses/analysis_config_data/analysis_config_data.py index c7d525a19..0ea14f31c 100644 --- a/ra2ce/analyses/analysis_config_data/analysis_config_data.py +++ b/ra2ce/analyses/analysis_config_data/analysis_config_data.py @@ -41,12 +41,12 @@ OriginsDestinationsSection, ) -IndirectAnalysisNameList: list[str] = [ - _enum.config_value for _enum in AnalysisIndirectEnum.list_valid_options() -] -DirectAnalysisNameList: list[str] = [ - _enum.config_value for _enum in AnalysisDirectEnum.list_valid_options() -] +IndirectAnalysisNameList: list[str] = list( + map(str, AnalysisIndirectEnum.list_valid_options()) +) +DirectAnalysisNameList: list[str] = list( + map(str, AnalysisDirectEnum.list_valid_options()) +) @dataclass diff --git a/ra2ce/analyses/analysis_config_data/analysis_config_data_validator.py b/ra2ce/analyses/analysis_config_data/analysis_config_data_validator.py index de4b3da62..e849c106c 100644 --- a/ra2ce/analyses/analysis_config_data/analysis_config_data_validator.py +++ b/ra2ce/analyses/analysis_config_data/analysis_config_data_validator.py @@ -56,7 +56,7 @@ def _validate_header(self, header: Any) -> ValidationReport: continue if isinstance(value, Ra2ceEnumBase): # enumerations - _expected_values_list = type(value).list_valid_options() + _expected_values_list = value.list_valid_options() else: # other items with limited value options (should become enumerations) if key not in AnalysisNetworkDictValues.keys(): diff --git a/ra2ce/graph/network_config_data/network_config_data_validator.py b/ra2ce/graph/network_config_data/network_config_data_validator.py index c400065ec..c778b3cd2 100644 --- a/ra2ce/graph/network_config_data/network_config_data_validator.py +++ b/ra2ce/graph/network_config_data/network_config_data_validator.py @@ -78,7 +78,7 @@ def _wrong_value(self, key: str) -> str: def _wrong_enum(self, key: str, enum: Ra2ceEnumBase) -> str: # Remove last value INVALID - _accepted_values = type(enum).list_valid_options() + _accepted_values = enum.list_valid_options() return ( f"Wrong input to property [ {key} ]; has to be one of: {_accepted_values}." ) @@ -115,7 +115,7 @@ def _validate_network_section( not _type.is_valid() for _type in network_section.road_types ): _network_report.error( - f"Wrong road type(s) configured; has to be one or multiple of: {[_type.config_value for _type in type(network_section.road_types[0]).list_valid_options()]}" + f"Wrong road type(s) configured; has to be one or multiple of: {[_type.config_value for _type in network_section.road_types[0].list_valid_options()]}" ) return _network_report