From 634a4e4f81f88c0e99d7501930fe32e2a559e6a2 Mon Sep 17 00:00:00 2001 From: Greg Lucas Date: Mon, 27 Jan 2025 21:57:19 -0700 Subject: [PATCH] TST/MNT: Add tests for refresh data download util Add tests to make sure the downloads are triggered appropriately. Change the condition to only refresh if the data being requested is before the current time AND after the last date in the file. Co-authored-by: Manan Singh --- CHANGELOG.md | 3 +++ pymsis/utils.py | 17 +++++++++++++ pyproject.toml | 4 +++ tests/test_utils.py | 62 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 86 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f6fdcf..49a4813 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file. ## [v0.13.0] unreleased +- **CHANGED** Refresh the default CelesTrak space-weather cache only when a + requested time is outside the available data range. Custom space-weather + files are never refreshed automatically. - **FIXED** MSIS 2.0 and 2.1 support parameter directories longer than 128 characters, avoiding premature process termination in deeply nested installs. - **ADDED** `interpolate_indices` option. diff --git a/pymsis/utils.py b/pymsis/utils.py index 88541b1..9e6b7ee 100644 --- a/pymsis/utils.py +++ b/pymsis/utils.py @@ -306,6 +306,23 @@ def get_f107_ap( _SPACE_WEATHER.data = _load_f107_ap_data() data = _SPACE_WEATHER.data + # Each ap value covers the three-hour interval beginning at its + # timestamp. Refresh only when the requested data is outside the file. + data_end = data["dates"][-1] + np.timedelta64(3, "h") + needs_refresh = _SPACE_WEATHER.path == _F107_AP_DEFAULT_FILE and np.any( + dates >= data_end + ) + if needs_refresh: + try: + download_f107_ap() + except OSError: + # Leave the old file and cache intact. The range check below + # reports the normal unavailable-data error for the request. + pass + if _SPACE_WEATHER.data is None: + _SPACE_WEATHER.data = _load_f107_ap_data() + data = _SPACE_WEATHER.data + data_start = data["dates"][0] data_end = data["dates"][-1] # atleast_1d keeps output shapes consistent for scalar and array inputs diff --git a/pyproject.toml b/pyproject.toml index 202e615..e33ff99 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,6 +74,10 @@ testpaths = [ addopts = [ "--import-mode=importlib", ] +filterwarnings = [ +# Ignore warnings loading from file specifically + 'ignore:Downloading ap and F10.7 data from file:UserWarning', +] [tool.cibuildwheel] environment.PIP_ONLY_BINARY = "numpy" diff --git a/tests/test_utils.py b/tests/test_utils.py index 980cebd..bf1a45c 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -154,6 +154,68 @@ def test_download_refreshes_cache(monkeypatch, tmp_path, local_path): assert_array_equal(utils.get_f107_ap("2000-07-01T12:00")[0], [159.6]) +def test_historical_request_does_not_refresh(monkeypatch, tmp_path, local_path): + target = tmp_path / "weather.csv" + target.write_text(local_path.read_text().replace("159.6", "199.6")) + monkeypatch.setattr(utils._SPACE_WEATHER, "path", target) + monkeypatch.setattr(utils, "_F107_AP_DEFAULT_FILE", target) + + with patch.object(utils, "download_f107_ap") as download: + assert_array_equal(utils.get_f107_ap("2000-07-01T12:00")[0], [199.6]) + download.assert_not_called() + + +def test_out_of_range_request_refreshes(monkeypatch, tmp_path, local_path): + target = tmp_path / "weather.csv" + lines = local_path.read_text().splitlines() + target.write_text("\n".join(lines[:100]) + "\n") + monkeypatch.setattr(utils._SPACE_WEATHER, "path", target) + monkeypatch.setattr(utils, "_F107_AP_DEFAULT_FILE", target) + + def refresh_from_fixture(): + target.write_bytes(local_path.read_bytes()) + utils._SPACE_WEATHER.data = None + + with patch.object( + utils, "download_f107_ap", side_effect=refresh_from_fixture + ) as download: + assert_array_equal(utils.get_f107_ap("2000-07-01T12:00")[0], [159.6]) + download.assert_called_once_with() + + +def test_custom_file_is_not_refreshed(monkeypatch, tmp_path, local_path): + target = tmp_path / "weather.csv" + lines = local_path.read_text().splitlines() + target.write_text("\n".join(lines[:100]) + "\n") + utils.use_space_weather_file(target) + + with ( + patch.object(utils, "download_f107_ap") as download, + pytest.raises(ValueError, match="not available"), + ): + utils.get_f107_ap("2000-07-01T12:00") + download.assert_not_called() + + +def test_out_of_range_request_raises_when_refresh_fails( + monkeypatch, tmp_path, local_path +): + target = tmp_path / "weather.csv" + lines = local_path.read_text().splitlines() + target.write_text("\n".join(lines[:100]) + "\n") + monkeypatch.setattr(utils._SPACE_WEATHER, "path", target) + monkeypatch.setattr(utils, "_F107_AP_DEFAULT_FILE", target) + + with ( + patch.object( + utils, "download_f107_ap", side_effect=OSError("offline") + ) as download, + pytest.raises(ValueError, match="not available"), + ): + utils.get_f107_ap("2000-07-01T12:00") + download.assert_called_once_with() + + @pytest.mark.parametrize( ("dates", "expected_f107", "expected_f107a", "expected_ap"), [