diff --git a/CHANGELOG.md b/CHANGELOG.md index f092957..bd488ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). + Update versioneer + Add pythons 3.9, 3.10, 3.11, 3.12 to tests and setup.py. + Remove support for python < 3.8 ++ Remove deprecated `new_old` and `future_old` functions. ++ Add `__str__` functions to `Timestep`, `Element`, `Day`, `Site` ++ Add element to `Forecast` to track if forecast is daily or 3 hourly ++ Change `id` variable in `Forecast`, `Observation`, `Site` to `location_id`. ++ Change `id` variable in `Element` to `field_code`. ## [0.9.8] - 2020-07-03 + Remove f-string in test - + ## [0.9.7] - 2020-07-03 + Bugfix for `get_observation_sites` @@ -141,4 +146,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [0.1] - 2014-07-16 -+ Initial commit and license. + + Initial commit and license. diff --git a/README.md b/README.md index 897c34f..25e83d8 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ conn = datapoint.connection(api_key="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee") site = conn.get_nearest_forecast_site(51.500728, -0.124626) # Get a forecast for my nearest site with 3 hourly timesteps -forecast = conn.get_forecast_for_site(site.id, "3hourly") +forecast = conn.get_forecast_for_site(site.location_id, "3hourly") # Get the current timestep from the forecast current_timestep = forecast.now() diff --git a/datapoint/Day.py b/datapoint/Day.py index 1f56146..c15c2a9 100644 --- a/datapoint/Day.py +++ b/datapoint/Day.py @@ -1,6 +1,21 @@ class Day(): - def __init__(self, api_key=""): - self.api_key = api_key - + def __init__(self): self.date = None self.timesteps = [] + + def __str__(self): + day_str = '' + + date_part = 'Date: ' + str(self.date) + '\n\n' + day_str += date_part + + day_str += 'Timesteps: \n\n' + try: + for timestep in self.timesteps: + day_str += str(timestep) + day_str += '\n' + + except TypeError: + day_str += 'No timesteps' + + return day_str diff --git a/datapoint/Element.py b/datapoint/Element.py index cb597dc..71ec77b 100644 --- a/datapoint/Element.py +++ b/datapoint/Element.py @@ -1,9 +1,12 @@ class Element(): - def __init__(self, id=None, value=None, units=None): + def __init__(self, field_code=None, value=None, units=None): - self.id = id + self.field_code = field_code self.value = value self.units = units # For elements which can also have a text value self.text = None + + def __str__(self): + return str(self.value) + ' ' + str(self.units) diff --git a/datapoint/Forecast.py b/datapoint/Forecast.py index 8caf051..8e4ef8f 100644 --- a/datapoint/Forecast.py +++ b/datapoint/Forecast.py @@ -1,17 +1,17 @@ import datetime from datapoint.exceptions import APIException -class Forecast(): - def __init__(self, api_key=""): - self.api_key = api_key +class Forecast(): + def __init__(self, frequency=""): + self.frequency = frequency self.data_date = None self.continent = None self.country = None self.name = None self.longitude = None self.latitude = None - self.id = None + self.location_id = None self.elevation = None self.days = [] @@ -67,7 +67,8 @@ def at_datetime(self, target): for day in self.days: for timestep in day.timesteps: - # Calculate the difference between the target time and the timestep. + # Calculate the difference between the target time and the + # timestep. td = target - timestep.date # Find the timestep which is further from the target than the @@ -75,11 +76,11 @@ def at_datetime(self, target): if abs(td.total_seconds()) > abs(prev_td.total_seconds()): # We are further from the target return prev_ts - elif abs(td.total_seconds()) < 5400 and num_timesteps == 8: + if abs(td.total_seconds()) < 5400 and num_timesteps == 8: # if we are past the final timestep, and it is a 3 hourly # forecast, check that we are within 90 minutes of it return timestep - elif abs(td.total_seconds()) < 21600 and num_timesteps == 2: + if abs(td.total_seconds()) < 21600 and num_timesteps == 2: # if we are past the final timestep, and it is a daily # forecast, check that we are within 6 hours of it return timestep @@ -94,68 +95,7 @@ def now(self): d = datetime.datetime.now(tz=self.days[0].date.tzinfo) return self.at_datetime(d) - def now_old(self): - """ - Function to return just the current timestep from this forecast - """ - - # From the comments in issue 19: forecast.days[0] is dated for the - # previous day shortly after midnight - - now = None - # Set the time now to be in the same time zone as the first timestep in - # the forecast. This shouldn't cause problems with daylight savings as - # the change is far enough after midnight. - d = datetime.datetime.now(tz=self.days[0].date.tzinfo) - # d is something like datetime.datetime(2019, 1, 19, 17, 5, 28, 337439) - # d.replace(...) is datetime.datetime(2019, 1, 19, 0, 0) - # for_total_seconds is then: datetime.timedelta(seconds=61528, - # microseconds=337439) - # In this example, this is (17*60*60) + (5*60) + 28 = 61528 - # this is the number of seconds through the day - for_total_seconds = d - \ - d.replace(hour=0, minute=0, second=0, microsecond=0) - - # In the example time, - # for_total_seconds.total_seconds() = 61528 + 0.337439 - # This is the number of seconds after midnight - # msm is then the number of minutes after midnight - msm = for_total_seconds.total_seconds() / 60 - - # If the date now and the date in the forecast are the same, proceed - if self.days[0].date.strftime("%Y-%m-%dZ") == d.strftime("%Y-%m-%dZ"): - # We have determined that the date in the forecast and the date now - # are the same. - # - # Now, test if timestep.name is larger than the number of minutes - # since midnight for each timestep. - # The timestep we keep is the one with the largest timestep.name - # which is less than the number of minutes since midnight - for timestep in self.days[0].timesteps: - if timestep.name > msm: - - # break here stops the for loop - break - # now is assigned to the last timestep that did not break the - # loop - now = timestep - return now - # Bodge to get around problems near midnight: - # Previous method does not account for the end of the month. The test - # trying to be evaluated is that the absolute difference between the - # last timestep of the first day and the current time is less than 4 - # hours. 4 hours is because the final timestep of the previous day is - # for 21:00 - elif abs(self.days[0].timesteps[-1].date - d).total_seconds() < 14400: - # This is verbose to check that the returned data makes sense - timestep_to_return = self.days[0].timesteps[-1] - - return timestep_to_return - else: - return False - - - def future(self,in_days=0,in_hours=0,in_minutes=0,in_seconds=0): + def future(self, in_days=0, in_hours=0, in_minutes=0, in_seconds=0): """Return the closest timestep to a date in a given amount of time""" d = datetime.datetime.now(tz=self.days[0].date.tzinfo) @@ -163,44 +103,3 @@ def future(self,in_days=0,in_hours=0,in_minutes=0,in_seconds=0): minutes=in_minutes, seconds=in_seconds) return self.at_datetime(target) - - def future_old(self,in_days=None,in_hours=None,in_minutes=None,in_seconds=None): - """ - Function to return a future timestep - """ - future = None - - # Initialize variables to 0 - dd, hh, mm, ss = [0 for i in range(4)] - if (in_days != None): - dd = dd + in_days - if (in_hours != None): - hh = hh + in_hours - if (in_minutes != None): - mm = mm + in_minutes - if (in_seconds != None): - ss = ss + in_seconds - - # Set the hours, minutes and seconds from now (minus the days) - dnow = datetime.datetime.utcnow() # Now - d = dnow + \ - datetime.timedelta(hours=hh, minutes=mm, seconds = ss) - # Time from midnight - for_total_seconds = d - \ - d.replace(hour=0, minute=0, second=0, microsecond=0) - - # Convert into minutes since midnight - try: - msm = for_total_seconds.total_seconds()/60. - except: - # For versions before 2.7 - msm = self.timedelta_total_seconds(for_total_seconds)/60. - - if (dd= msm: - future = timestep - return future - else: - print('ERROR: requested date is outside the forecast range selected,' + str(len(self.days))) - return False diff --git a/datapoint/Manager.py b/datapoint/Manager.py index 700902a..18bcc64 100644 --- a/datapoint/Manager.py +++ b/datapoint/Manager.py @@ -247,7 +247,7 @@ def get_forecast_sites(self): for jsoned in data['Locations']['Location']: site = Site() site.name = jsoned['name'] - site.id = jsoned['id'] + site.location_id = jsoned['id'] site.latitude = jsoned['latitude'] site.longitude = jsoned['longitude'] @@ -304,7 +304,7 @@ def get_nearest_forecast_site(self, latitude, longitude): float(longitude), float(latitude)) - if ((distance == None) or (new_distance < distance)): + if ((distance is None) or (new_distance < distance)): distance = new_distance nearest = site @@ -325,15 +325,15 @@ def get_forecast_for_site(self, site_id, frequency="daily"): A frequency of "3hourly" will return 8 timesteps: 0, 180, 360 ... 1260 (minutes since midnight UTC) """ - data = self.__call_api(site_id, {"res":frequency}) + data = self.__call_api(site_id, {"res": frequency}) params = data['SiteRep']['Wx']['Param'] - forecast = Forecast() + forecast = Forecast(frequency=frequency) # If the 'Location' key is missing, there is no data for the site, # raise an error. if 'Location' not in data['SiteRep']['DV']: err_string = ('DataPoint has not returned any data for the' - 'requested site.' ) + 'requested site.') raise APIException(err_string) # Check if the other keys we need are in the data returned from the @@ -359,7 +359,7 @@ def get_forecast_for_site(self, site_id, frequency="daily"): forecast.latitude = data['SiteRep']['DV']['Location']['lat'] if 'i' in data['SiteRep']['DV']['Location']: - forecast.id = data['SiteRep']['DV']['Location']['i'] + forecast.location_id = data['SiteRep']['DV']['Location']['i'] if 'elevation' in data['SiteRep']['DV']['Location']: forecast.elevation = data['SiteRep']['DV']['Location']['elevation'] @@ -456,7 +456,6 @@ def get_forecast_for_site(self, site_id, frequency="daily"): return forecast - def get_observation_sites(self): """ This function returns a list of Site objects for which observations are available. @@ -468,7 +467,7 @@ def get_observation_sites(self): for jsoned in data['Locations']['Location']: site = Site() site.name = jsoned['name'] - site.id = jsoned['id'] + site.location_id = jsoned['id'] site.latitude = jsoned['latitude'] site.longitude = jsoned['longitude'] @@ -528,7 +527,7 @@ def get_observations_for_site(self, site_id, frequency='hourly'): Returns hourly observations for the previous 24 hours """ - data = self.__call_api(site_id,{"res":frequency}, OBSERVATION_URL) + data = self.__call_api(site_id,{"res": frequency}, OBSERVATION_URL) params = data['SiteRep']['Wx']['Param'] observation = Observation() @@ -554,7 +553,7 @@ def get_observations_for_site(self, site_id, frequency='hourly'): observation.latitude = data['SiteRep']['DV']['Location']['lat'] if 'i' in data['SiteRep']['DV']['Location']: - observation.id = data['SiteRep']['DV']['Location']['i'] + observation.location_id = data['SiteRep']['DV']['Location']['i'] if 'elevation' in data['SiteRep']['DV']['Location']: observation.elevation = data['SiteRep']['DV']['Location']['elevation'] diff --git a/datapoint/Observation.py b/datapoint/Observation.py index eb6771d..93e12a1 100644 --- a/datapoint/Observation.py +++ b/datapoint/Observation.py @@ -1,23 +1,20 @@ -import datetime - class Observation(): - def __init__(self, api_key=""): - self.api_key = api_key - + def __init__(self): self.data_date = None self.continent = None self.country = None self.name = None self.longitude = None self.latitude = None - self.id = None + self.location_id = None self.elevation = None # Stores a list of observations in days self.days = [] def now(self): """ - Return the final timestep available. This is the most recent observation. + Return the final timestep available. This is the most recent + observation. """ return self.days[-1].timesteps[-1] diff --git a/datapoint/Site.py b/datapoint/Site.py index 13b8cdc..331c402 100644 --- a/datapoint/Site.py +++ b/datapoint/Site.py @@ -1,12 +1,18 @@ class Site(): - def __init__(self, api_key=""): - self.api_key = api_key - + def __init__(self): self.name = None - self.id = None + self.location_id = None self.elevation = None self.latitude = None self.longitude = None self.nationalPark = None self.region = None self.unitaryAuthArea = None + + def __str__(self): + site_string = '' + for attr, value in self.__dict__.items(): + to_append = attr + ': ' + str(value) + '\n' + site_string += to_append + + return site_string diff --git a/datapoint/Timestep.py b/datapoint/Timestep.py index 0a92663..2cb415b 100644 --- a/datapoint/Timestep.py +++ b/datapoint/Timestep.py @@ -1,9 +1,7 @@ from .Element import Element class Timestep(): - def __init__(self, api_key=""): - self.api_key = api_key - + def __init__(self): self.name = None self.date = None self.weather = None @@ -29,3 +27,10 @@ def elements(self): elements = [el[1] for el in self.__dict__.items() if isinstance(el[1], Element)] return elements + + def __str__(self): + timestep_string = '' + for attr, value in self.__dict__.items(): + to_append = attr + ': ' + str(value) + '\n' + timestep_string += to_append + return timestep_string diff --git a/datapoint/regions/RegionManager.py b/datapoint/regions/RegionManager.py index 510b12a..54cffc4 100644 --- a/datapoint/regions/RegionManager.py +++ b/datapoint/regions/RegionManager.py @@ -50,7 +50,7 @@ def get_all_regions(self): regions = [] for location in response['Locations']['Location']: region = Site() - region.id = location['@id'] + region.location_id = location['@id'] region.region = location['@name'] region.name = REGION_NAMES[location['@name']] regions.append(region) diff --git a/docs/getting-started.rst b/docs/getting-started.rst index a965c88..c20f7bd 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -55,7 +55,7 @@ Let’s call another of the Manager Object’s methods to give us a :: - forecast = conn.get_forecast_for_site(site.id, "3hourly") + forecast = conn.get_forecast_for_site(site.location_id, "3hourly") We’ve given this method two parameters, the site ID for the forecast we want and also a forecast type of “3hourly”. We’ll discuss the forecast types later on. diff --git a/examples/current_weather/current_weather.py b/examples/current_weather/current_weather.py index dab6de3..6de1117 100644 --- a/examples/current_weather/current_weather.py +++ b/examples/current_weather/current_weather.py @@ -15,7 +15,7 @@ print(site.name) # Get a forecast for the nearest site -forecast = conn.get_forecast_for_site(site.id, "3hourly") +forecast = conn.get_forecast_for_site(site.location_id, "3hourly") # Get the current timestep using now() and print out some info now = forecast.now() diff --git a/examples/postcodes_to_lat_lng/postcodes_to_lat_lng.py b/examples/postcodes_to_lat_lng/postcodes_to_lat_lng.py index 9b35731..6decab7 100644 --- a/examples/postcodes_to_lat_lng/postcodes_to_lat_lng.py +++ b/examples/postcodes_to_lat_lng/postcodes_to_lat_lng.py @@ -21,7 +21,7 @@ print(site.name) # Get a forecast for the nearest site -forecast = conn.get_forecast_for_site(site.id, "3hourly") +forecast = conn.get_forecast_for_site(site.location_id, "3hourly") # Get the current timestep using now() and print out some info now = forecast.now() diff --git a/examples/simple_forecast/simple_forecast.py b/examples/simple_forecast/simple_forecast.py index c534620..83daf2f 100755 --- a/examples/simple_forecast/simple_forecast.py +++ b/examples/simple_forecast/simple_forecast.py @@ -15,7 +15,7 @@ print(site.name) # Get a forecast for the nearest site -forecast = conn.get_forecast_for_site(site.id, "3hourly") +forecast = conn.get_forecast_for_site(site.location_id, "3hourly") # Loop through days and print date for day in forecast.days: diff --git a/examples/text_forecast/text_forecast.py b/examples/text_forecast/text_forecast.py index 18bfd1f..c7becb3 100644 --- a/examples/text_forecast/text_forecast.py +++ b/examples/text_forecast/text_forecast.py @@ -11,11 +11,11 @@ # Get all regions and print out their details regions = conn.regions.get_all_regions() for region in regions: - print((region.name, region.id, region.region)) + print((region.name, region.location_id, region.region)) # Get all forecasts for a specific region my_region = regions[0] -forecast = conn.regions.get_raw_forecast(my_region.id)['RegionalFcst'] +forecast = conn.regions.get_raw_forecast(my_region.location_id)['RegionalFcst'] # Print the forecast details print('Forecast for {} (issued at {}):'.format(my_region.name, forecast['issuedAt'])) diff --git a/examples/tube_bike/tube_bike.py b/examples/tube_bike/tube_bike.py index f6241bf..15d5d54 100644 --- a/examples/tube_bike/tube_bike.py +++ b/examples/tube_bike/tube_bike.py @@ -16,8 +16,8 @@ work = conn.get_nearest_forecast_site(51.5031650, -0.1123050) # Get a forecast for my house and work -my_house_forecast = conn.get_forecast_for_site(my_house.id, "3hourly") -work_forecast = conn.get_forecast_for_site(work.id, "3hourly") +my_house_forecast = conn.get_forecast_for_site(my_house.location_id, "3hourly") +work_forecast = conn.get_forecast_for_site(work.location_id, "3hourly") # Get the current timestep for both locations my_house_now = my_house_forecast.now() diff --git a/examples/umbrella/umbrella.py b/examples/umbrella/umbrella.py index bbeadf7..19c0fbe 100755 --- a/examples/umbrella/umbrella.py +++ b/examples/umbrella/umbrella.py @@ -17,7 +17,7 @@ print(site.name) # Get a forecast for the nearest site -forecast = conn.get_forecast_for_site(site.id, "3hourly") +forecast = conn.get_forecast_for_site(site.location_id, "3hourly") # Loop through all the timesteps in day 0 (today) for timestep in forecast.days[0].timesteps: diff --git a/examples/washing/washing.py b/examples/washing/washing.py index 764bcbc..88e1cef 100644 --- a/examples/washing/washing.py +++ b/examples/washing/washing.py @@ -28,7 +28,7 @@ # Get a forecast for the nearest site -forecast = conn.get_forecast_for_site(site.id, "daily") +forecast = conn.get_forecast_for_site(site.location_id, "daily") # Loop through days for day in forecast.days: diff --git a/requirements.txt b/requirements.txt index f75fe08..af8a0b0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -requests==2.23.0 -appdirs==1.4.3 +requests==2.24.0 +appdirs==1.4.4 pytz==2020.1 requests-mock==1.8.0 diff --git a/tests/integration/test_datapoint.py b/tests/integration/test_datapoint.py index c72a713..d305621 100644 --- a/tests/integration/test_datapoint.py +++ b/tests/integration/test_datapoint.py @@ -42,10 +42,10 @@ def test_wavertree_hourly(self, mock_request): MockDateTime.now = classmethod(lambda cls, **kwargs: datetime(2020, 4, 25, 12, tzinfo=timezone.utc)) mock_request.get('/public/data/val/wxfcs/all/json/354107?res=3hourly', text=self.wavertree_hourly) - forecast = self.conn.get_forecast_for_site(self.wavertree.id, "3hourly") + forecast = self.conn.get_forecast_for_site(self.wavertree.location_id, "3hourly") now = forecast.now() - self.assertEqual(self.wavertree.id, '354107') + self.assertEqual(self.wavertree.location_id, '354107') self.assertEqual(self.wavertree.name, 'Wavertree') self.assertEqual(now.date.strftime(DATETIME_FORMAT), '2020-04-25 12:00:00+0000') @@ -84,10 +84,10 @@ def test_wavertree_daily(self, mock_request): MockDateTime.now = classmethod(lambda cls, **kwargs: datetime(2020, 4, 25, 12, tzinfo=timezone.utc)) mock_request.get('/public/data/val/wxfcs/all/json/354107?res=daily', text=self.wavertree_daily) - forecast = self.conn.get_forecast_for_site(self.wavertree.id, "daily") + forecast = self.conn.get_forecast_for_site(self.wavertree.location_id, "daily") now = forecast.now() - self.assertEqual(self.wavertree.id, '354107') + self.assertEqual(self.wavertree.location_id, '354107') self.assertEqual(self.wavertree.name, 'Wavertree') self.assertEqual(now.date.strftime(DATETIME_FORMAT), '2020-04-25 12:00:00+0000') @@ -125,10 +125,10 @@ def test_kingslynn_hourly(self, mock_request): MockDateTime.now = classmethod(lambda cls, **kwargs: datetime(2020, 4, 25, 12, tzinfo=timezone.utc)) mock_request.get('/public/data/val/wxfcs/all/json/322380?res=3hourly', text=self.kingslynn_hourly) - forecast = self.conn.get_forecast_for_site(self.kingslynn.id, "3hourly") + forecast = self.conn.get_forecast_for_site(self.kingslynn.location_id, "3hourly") now = forecast.now() - self.assertEqual(self.kingslynn.id, '322380') + self.assertEqual(self.kingslynn.location_id, '322380') self.assertEqual(self.kingslynn.name, "King's Lynn") self.assertEqual(now.date.strftime(DATETIME_FORMAT), '2020-04-25 12:00:00+0000') diff --git a/tests/integration/test_manager.py b/tests/integration/test_manager.py index 2356e9f..d258ea9 100644 --- a/tests/integration/test_manager.py +++ b/tests/integration/test_manager.py @@ -20,7 +20,7 @@ def test_get_forecast_sites(self): def test_get_daily_forecast(self): site = self.manager.get_nearest_forecast_site(latitude=51.500728, longitude=-0.124626) - forecast = self.manager.get_forecast_for_site(site.id, 'daily') + forecast = self.manager.get_forecast_for_site(site.location_id, 'daily') self.assertIsInstance(forecast, datapoint.Forecast.Forecast) self.assertEqual(forecast.continent.upper(), 'EUROPE') self.assertEqual(forecast.country.upper(), 'ENGLAND') @@ -80,7 +80,7 @@ def test_get_daily_forecast(self): def test_get_3hour_forecast(self): site = self.manager.get_nearest_forecast_site(latitude=51.500728, longitude=-0.124626) - forecast = self.manager.get_forecast_for_site(site.id, '3hourly') + forecast = self.manager.get_forecast_for_site(site.location_id, '3hourly') self.assertIsInstance(forecast, datapoint.Forecast.Forecast) self.assertEqual(forecast.continent.upper(), 'EUROPE') self.assertEqual(forecast.country.upper(), 'ENGLAND') diff --git a/tests/integration/test_regions.py b/tests/integration/test_regions.py index d7a2572..ee52a4e 100644 --- a/tests/integration/test_regions.py +++ b/tests/integration/test_regions.py @@ -24,14 +24,14 @@ def test_get_all_regions(self): all_regions = self.regions.get_all_regions() sample_region = next( region for region in all_regions - if region.id == '515') + if region.location_id == '515') self.assertEqual(sample_region.name, 'UK') self.assertEqual(sample_region.region, 'uk') def test_get_raw_forecast(self): sample_region = self.regions.get_all_regions()[0] response = self.regions.get_raw_forecast( - sample_region.id)['RegionalFcst'] + sample_region.location_id)['RegionalFcst'] self.assertEqual(response['regionId'], sample_region.region) # Based on what Datapoint serves at time of writing... diff --git a/tests/unit/test_forecast.py b/tests/unit/test_forecast.py index f76b029..d84a09c 100644 --- a/tests/unit/test_forecast.py +++ b/tests/unit/test_forecast.py @@ -6,33 +6,107 @@ class TestForecast(unittest.TestCase): def setUp(self): - self.forecast = datapoint.Forecast.Forecast() + self.forecast_3hrly = datapoint.Forecast.Forecast(frequency='3hourly') - def test_forecast_now_works(self): test_day_0 = datapoint.Day.Day() - test_day_0.date = datetime.datetime.now(datetime.timezone.utc) + test_day_0.date = datetime.datetime(2020, 3, 3, tzinfo=datetime.timezone.utc) - test_timestep_0 = datapoint.Timestep.Timestep() - test_timestep_0.name = 0 - test_timestep_0.date = datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(hours=2) + for i in range(5): + ts = datapoint.Timestep.Timestep() + ts.name = 9+(3*i) + ts.date = datetime.datetime(2020, 3, 3, 9+(3*i), tzinfo=datetime.timezone.utc) + test_day_0.timesteps.append(ts) - test_timestep_1 = datapoint.Timestep.Timestep() - test_timestep_1.name = 1 - test_timestep_1.date = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(hours=4) + test_day_1 = datapoint.Day.Day() + test_day_1.date = datetime.datetime(2020, 3, 4, tzinfo=datetime.timezone.utc) - test_day_0.timesteps.append(test_timestep_0) - test_day_0.timesteps.append(test_timestep_1) + for i in range(8): + ts = datapoint.Timestep.Timestep() + ts.name = 3*i + ts.date = datetime.datetime(2020, 3, 4, 3*i, tzinfo=datetime.timezone.utc) + test_day_1.timesteps.append(ts) - self.forecast.days.append(test_day_0) + self.forecast_3hrly.days.append(test_day_0) + self.forecast_3hrly.days.append(test_day_1) - test_day_1 = datapoint.Day.Day() - for i in range(8): + test_day_0 = datapoint.Day.Day() + test_day_0.date = datetime.datetime(2020, 3, 3, tzinfo=datetime.timezone.utc) + + for i in range(2): ts = datapoint.Timestep.Timestep() - ts.name = i * 180 - ts.date = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(days=1, hours=i*3) + ts.name = 2*i + ts.date = datetime.datetime(2020, 3, 3, 2*i, tzinfo=datetime.timezone.utc) + test_day_0.timesteps.append(ts) + test_day_1 = datapoint.Day.Day() + test_day_1.date = datetime.datetime(2020, 3, 4, tzinfo=datetime.timezone.utc) + + for i in range(2): + ts = datapoint.Timestep.Timestep() + ts.name = 2*i + ts.date = datetime.datetime(2020, 3, 4, 2*i, tzinfo=datetime.timezone.utc) test_day_1.timesteps.append(ts) - self.forecast.days.append(test_day_1) - # What is being asserted here? - assert self.forecast.now() + self.forecast_daily = datapoint.Forecast.Forecast(frequency='daily') + + self.forecast_daily.days.append(test_day_0) + self.forecast_daily.days.append(test_day_1) + + def test_at_datetime_1_5_hours_before_after(self): + + target_before = datetime.datetime(2020, 3, 3, 7, 0, + tzinfo=datetime.timezone.utc) + + target_after = datetime.datetime(2020, 3, 4, 23, 0, + tzinfo=datetime.timezone.utc) + + self.assertRaises(datapoint.exceptions.APIException, + self.forecast_3hrly.at_datetime, target_before) + + self.assertRaises(datapoint.exceptions.APIException, + self.forecast_3hrly.at_datetime, target_after) + + def test_at_datetime_6_hours_before_after(self): + + # Generate 2 timesteps These are set at 00:00 and 12:00 + + target_before = datetime.datetime(2020, 3, 2, 15, 0, + tzinfo=datetime.timezone.utc) + + target_after = datetime.datetime(2020, 3, 6, 7, 0, + tzinfo=datetime.timezone.utc) + + self.assertRaises(datapoint.exceptions.APIException, + self.forecast_daily.at_datetime, target_before) + + self.assertRaises(datapoint.exceptions.APIException, + self.forecast_daily.at_datetime, target_after) + + def test_normal_time(self): + target = datetime.datetime(2020, 3, 3, 10, 0, + tzinfo=datetime.timezone.utc) + + nearest = self.forecast_3hrly.at_datetime(target) + expected = datetime.datetime(2020, 3, 3, 9, + tzinfo=datetime.timezone.utc) + self.assertEqual(nearest.date, expected) + + target = datetime.datetime(2020, 3, 3, 11, 0, + tzinfo=datetime.timezone.utc) + + nearest = self.forecast_3hrly.at_datetime(target) + expected = datetime.datetime(2020, 3, 3, 12, + tzinfo=datetime.timezone.utc) + self.assertEqual(nearest.date, expected) + + + def test_forecase_midnight(self): + target = datetime.datetime(2020, 3, 4, 0, 15, + tzinfo=datetime.timezone.utc) + + nearest = self.forecast_3hrly.at_datetime(target) + expected = datetime.datetime(2020, 3, 4, 0, + tzinfo=datetime.timezone.utc) + self.assertEqual(nearest.date, expected) + +