From 8369b5acfa01dfd3d7c6d38b31d02978c106bc95 Mon Sep 17 00:00:00 2001 From: zacharyburnett Date: Mon, 13 Jun 2022 13:57:20 -0400 Subject: [PATCH 1/3] add `.status` property to check if storm is currently being updated in real-time --- stormevents/stormevent.py | 18 +++++++++++++++++- tests/test_stormevent.py | 25 +++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/stormevents/stormevent.py b/stormevents/stormevent.py index 6dc538e..78c1b38 100644 --- a/stormevents/stormevent.py +++ b/stormevents/stormevent.py @@ -1,4 +1,6 @@ from datetime import datetime +from datetime import timedelta +from enum import Enum from functools import lru_cache from os import PathLike from typing import List @@ -24,13 +26,17 @@ from stormevents.nhc import VortexTrack from stormevents.nhc.atcf import ATCF_Advisory from stormevents.nhc.atcf import ATCF_FileDeck -from stormevents.nhc.atcf import ATCF_Mode from stormevents.usgs import usgs_flood_storms from stormevents.usgs import USGS_StormEvent from stormevents.utilities import relative_to_time_interval from stormevents.utilities import subset_time_interval +class StormStatus(Enum): + HISTORICAL = "historical" + REALTIME = "realtime" + + class StormEvent: """ The ``StormEvent`` class can be used to retrieve data @@ -250,6 +256,16 @@ def __data_end(self) -> datetime: data_end = VortexTrack.from_storm_name(self.name, self.year).end_date return data_end + @property + def status(self) -> StormStatus: + entry = self.__entry + if pandas.isna(entry["end_date"]) or datetime.today() - entry[ + "end_date" + ] > timedelta(days=1): + return StormStatus.HISTORICAL + else: + return StormStatus.REALTIME + def track( self, start_date: datetime = None, diff --git a/tests/test_stormevent.py b/tests/test_stormevent.py index 07a6bff..342a0a2 100644 --- a/tests/test_stormevent.py +++ b/tests/test_stormevent.py @@ -2,11 +2,14 @@ from datetime import datetime from datetime import timedelta +import pandas import pytest import shapely from shapely.geometry import box +from stormevents.nhc import nhc_storms from stormevents.stormevent import StormEvent +from stormevents.stormevent import StormStatus from tests import check_reference_directory from tests import OUTPUT_DIRECTORY from tests import REFERENCE_DIRECTORY @@ -212,3 +215,25 @@ def test_storm_event_coops_product_within_region(florence2018): assert null_tidal_data["t"].sizes == {} assert east_coast_tidal_data.sizes == {"nos_id": 112, "t": 1} + + +def test_status(): + florence2018 = StormEvent("florence", 2018) + paine2016 = StormEvent.from_nhc_code("EP172016") + henri2021 = StormEvent.from_usgs_id(310) + ida2021 = StormEvent("ida", 2021) + + assert florence2018.status == StormStatus.HISTORICAL + assert paine2016.status == StormStatus.HISTORICAL + assert henri2021.status == StormStatus.HISTORICAL + assert ida2021.status == StormStatus.HISTORICAL + + storms = nhc_storms() + latest_storm_entry = storms.iloc[-1] + latest_storm = StormEvent.from_nhc_code(latest_storm_entry.name) + if pandas.isna( + latest_storm_entry["end_date"] + ) or datetime.today() - latest_storm_entry["end_date"] > timedelta(days=1): + assert latest_storm.status == StormStatus.REALTIME + else: + assert latest_storm.status == StormStatus.HISTORICAL From 739e25fab7e45bd4d8a1e005464c6c7258850d32 Mon Sep 17 00:00:00 2001 From: zacharyburnett Date: Tue, 14 Jun 2022 09:13:02 -0400 Subject: [PATCH 2/3] fix issues with backwards logic --- stormevents/stormevent.py | 9 ++++----- tests/test_stormevent.py | 5 ++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/stormevents/stormevent.py b/stormevents/stormevent.py index 78c1b38..06fc95b 100644 --- a/stormevents/stormevent.py +++ b/stormevents/stormevent.py @@ -259,12 +259,11 @@ def __data_end(self) -> datetime: @property def status(self) -> StormStatus: entry = self.__entry - if pandas.isna(entry["end_date"]) or datetime.today() - entry[ - "end_date" - ] > timedelta(days=1): - return StormStatus.HISTORICAL - else: + age = datetime.today() - entry["end_date"] + if pandas.isna(entry["end_date"]) or age < timedelta(days=1): return StormStatus.REALTIME + else: + return StormStatus.HISTORICAL def track( self, diff --git a/tests/test_stormevent.py b/tests/test_stormevent.py index 342a0a2..3401a48 100644 --- a/tests/test_stormevent.py +++ b/tests/test_stormevent.py @@ -231,9 +231,8 @@ def test_status(): storms = nhc_storms() latest_storm_entry = storms.iloc[-1] latest_storm = StormEvent.from_nhc_code(latest_storm_entry.name) - if pandas.isna( - latest_storm_entry["end_date"] - ) or datetime.today() - latest_storm_entry["end_date"] > timedelta(days=1): + age = datetime.today() - latest_storm_entry["end_date"] + if pandas.isna(latest_storm_entry["end_date"]) or age < timedelta(days=1): assert latest_storm.status == StormStatus.REALTIME else: assert latest_storm.status == StormStatus.HISTORICAL From 0f8276e682cf452b3fcb0c0f1f74f065e1b5b10d Mon Sep 17 00:00:00 2001 From: zacharyburnett Date: Tue, 14 Jun 2022 10:15:01 -0400 Subject: [PATCH 3/3] handle case where the end date of a historical storm is `NaT` --- stormevents/stormevent.py | 5 ++++- tests/test_stormevent.py | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/stormevents/stormevent.py b/stormevents/stormevent.py index 06fc95b..2e90b54 100644 --- a/stormevents/stormevent.py +++ b/stormevents/stormevent.py @@ -261,7 +261,10 @@ def status(self) -> StormStatus: entry = self.__entry age = datetime.today() - entry["end_date"] if pandas.isna(entry["end_date"]) or age < timedelta(days=1): - return StormStatus.REALTIME + if datetime.today() - entry["start_date"] > timedelta(days=30): + return StormStatus.HISTORICAL + else: + return StormStatus.REALTIME else: return StormStatus.HISTORICAL diff --git a/tests/test_stormevent.py b/tests/test_stormevent.py index 3401a48..0f83cbd 100644 --- a/tests/test_stormevent.py +++ b/tests/test_stormevent.py @@ -233,6 +233,9 @@ def test_status(): latest_storm = StormEvent.from_nhc_code(latest_storm_entry.name) age = datetime.today() - latest_storm_entry["end_date"] if pandas.isna(latest_storm_entry["end_date"]) or age < timedelta(days=1): - assert latest_storm.status == StormStatus.REALTIME + if datetime.today() - latest_storm_entry["start_date"] > timedelta(days=30): + assert latest_storm.status == StormStatus.HISTORICAL + else: + assert latest_storm.status == StormStatus.REALTIME else: assert latest_storm.status == StormStatus.HISTORICAL