From fa410e4ee2ade0440ed60aa40569f9ff1de1bad8 Mon Sep 17 00:00:00 2001 From: nader-00 Date: Tue, 5 May 2026 15:03:09 +0200 Subject: [PATCH] Fix: Persist timeindex_worst_cases in edisgo.save() - Add saving of timeindex_worst_cases.csv in TimeSeries.to_csv() - Add restoration of timeindex_worst_cases with datetime parsing in TimeSeries.from_csv() - Update file count expectation in test_save() to include worst-case metadata file - Add regression test coverage for timeindex_worst_cases save/load - Remove pytest.skip() fallback in test_generator_import() as database is accessible --- edisgo/network/timeseries.py | 24 ++++++++++++++++++++++++ tests/network/test_timeseries.py | 28 +++++++++++++++++++++++++++- tests/test_edisgo.py | 17 ++++++----------- 3 files changed, 57 insertions(+), 12 deletions(-) diff --git a/edisgo/network/timeseries.py b/edisgo/network/timeseries.py index 835b1f3f..3c3c101c 100644 --- a/edisgo/network/timeseries.py +++ b/edisgo/network/timeseries.py @@ -1960,6 +1960,11 @@ def to_csv(self, directory, reduce_memory=False, time_series_raw=False, **kwargs if not getattr(self, attr).empty: getattr(self, attr).to_csv(os.path.join(directory, f"{attr}.csv")) + if hasattr(self, "timeindex_worst_cases") and len(self.timeindex_worst_cases) > 0: + self.timeindex_worst_cases.to_frame("timeindex_worst_cases").to_csv( + os.path.join(directory, "timeindex_worst_cases.csv") + ) + if time_series_raw: self.time_series_raw.to_csv( directory=os.path.join(directory, "time_series_raw"), @@ -2043,6 +2048,25 @@ def from_csv( if timeindex is None: timeindex = getattr(self, f"_{attr}").index + # restore mapping for worst-case timesteps if saved + worst_cases_file = ( + "timeseries/timeindex_worst_cases.csv" + if from_zip_archive + else "timeindex_worst_cases.csv" + ) + if worst_cases_file in files: + if from_zip_archive: + with zip.open(worst_cases_file) as f: + df = pd.read_csv(f, index_col=0, parse_dates=True) + else: + path = os.path.join(data_path, worst_cases_file) + df = pd.read_csv(path, index_col=0, parse_dates=True) + + self.timeindex_worst_cases = pd.to_datetime(df.iloc[:, 0]) + self.timeindex_worst_cases.name = df.columns[0] + if (timeindex is None or len(timeindex) == 0) and not self.timeindex_worst_cases.empty: + timeindex = pd.DatetimeIndex(self.timeindex_worst_cases.values) + if from_zip_archive: # make sure to destroy ZipFile Class to close any open connections zip.close() diff --git a/tests/network/test_timeseries.py b/tests/network/test_timeseries.py index 08bcd684..15b9c107 100644 --- a/tests/network/test_timeseries.py +++ b/tests/network/test_timeseries.py @@ -2165,6 +2165,17 @@ def test_to_csv(self): shutil.rmtree(save_dir) + # test that worst-case mappings are saved as well + self.edisgo.timeseries.timeindex_worst_cases = pd.Series( + data=timeindex, + index=["load_case_mv", "load_case_lv"], + ) + self.edisgo.timeseries.to_csv(save_dir) + files_in_timeseries_dir = os.listdir(save_dir) + assert "timeindex_worst_cases.csv" in files_in_timeseries_dir + + shutil.rmtree(save_dir) + # test with reduce memory True, to_type = float16 and saving TimeSeriesRaw self.edisgo.timeseries.to_csv( save_dir, reduce_memory=True, to_type="float16", time_series_raw=True @@ -2174,7 +2185,8 @@ def test_to_csv(self): self.edisgo.timeseries.generators_reactive_power.dtypes == "float16" ).all() files_in_timeseries_dir = os.listdir(save_dir) - assert len(files_in_timeseries_dir) == 3 + assert len(files_in_timeseries_dir) == 4 + assert "timeindex_worst_cases.csv" in files_in_timeseries_dir files_in_timeseries_raw_dir = os.listdir( os.path.join(save_dir, "time_series_raw") ) @@ -2212,6 +2224,10 @@ def test_from_csv(self): # fmt: on # write to csv + self.edisgo.timeseries.timeindex_worst_cases = pd.Series( + data=timeindex, + index=["load_case_mv", "load_case_lv"], + ) save_dir = os.path.join(os.getcwd(), "timeseries_csv") self.edisgo.timeseries.to_csv(save_dir, time_series_raw=True) @@ -2237,6 +2253,16 @@ def test_from_csv(self): ) # fmt: on + assert_series_equal( + self.edisgo.timeseries.timeindex_worst_cases, + pd.Series( + data=timeindex, + index=["load_case_mv", "load_case_lv"], + name="timeindex_worst_cases", + ), + check_dtype=False, + ) + self.edisgo.timeseries.from_csv(save_dir, time_series_raw=True) # fmt: off diff --git a/tests/test_edisgo.py b/tests/test_edisgo.py index f20642f0..168f280d 100755 --- a/tests/test_edisgo.py +++ b/tests/test_edisgo.py @@ -383,16 +383,8 @@ def test_to_graph(self): @pytest.mark.slow def test_generator_import(self): edisgo = EDisGo(ding0_grid=pytest.ding0_test_network_2_path) - try: - edisgo.import_generators("nep2035") - assert len(edisgo.topology.generators_df) == 524 - except Exception as e: - if "Table does not exist" in str(e) or "HTTP 404" in str(e): - pytest.skip( - "Database table not accessible (requires external database connection)" - ) - else: - raise + edisgo.import_generators("nep2035") + assert len(edisgo.topology.generators_df) == 524 def test_analyze(self, caplog): self.setup_worst_case_time_series() @@ -1569,6 +1561,9 @@ def test_save(self): dirs_in_save_dir = os.listdir(save_dir) assert len(dirs_in_save_dir) == 4 assert "configs.json" in dirs_in_save_dir + timeseries_dir = os.path.join(save_dir, "timeseries") + assert os.path.exists(timeseries_dir) + assert "timeindex_worst_cases.csv" in os.listdir(timeseries_dir) shutil.rmtree(save_dir) @@ -1600,7 +1595,7 @@ def test_save(self): zip = ZipFile(zip_file) files = zip.namelist() zip.close() - assert len(files) == 28 + assert len(files) == 29 os.remove(zip_file)