diff --git a/yr_weather/api_types/locationforecast.py b/yr_weather/api_types/locationforecast.py index cdb26c2..5e9b6b4 100644 --- a/yr_weather/api_types/locationforecast.py +++ b/yr_weather/api_types/locationforecast.py @@ -142,7 +142,7 @@ class APIForecastGeometry(TypedDict): class APIForecast(TypedDict): - """APIForecast forecast data""" + """Full API forecast data""" type: str geometry: APIForecastGeometry diff --git a/yr_weather/data/locationforecast.py b/yr_weather/data/locationforecast.py index daad76b..fa5b02d 100644 --- a/yr_weather/data/locationforecast.py +++ b/yr_weather/data/locationforecast.py @@ -2,7 +2,14 @@ from datetime import datetime from typing import Optional, List -from dataclasses import dataclass, field, fields +from dataclasses import dataclass, fields + +from yr_weather.api_types.locationforecast import ( + APIForecast, + APIForecastTime, + APIForecastFutureSummary, + APIForecastFutureDetails, +) class _ForecastData: @@ -129,18 +136,15 @@ class ForecastFuture: The forecast data for this forecast. """ - summary: Optional[ForecastFutureSummary] = None - details: Optional[ForecastFutureDetails] = None - - def __post_init__(self): - if self.summary: - self.summary = ForecastFutureSummary.create(self.summary) - - if self.details: - self.details = ForecastFutureDetails.create(self.details) + def __init__( + self, + summary: Optional[APIForecastFutureSummary] = None, + details: Optional[APIForecastFutureDetails] = None, + ): + self.summary = ForecastFutureSummary.create(summary) if summary else None + self.details = ForecastFutureDetails.create(details) if details else None -@dataclass class ForecastTime: """A class holding data about a forecast for a specific time. @@ -158,21 +162,12 @@ class ForecastTime: A ForecastFuture with data about the forecast the 12 hours. """ - _data: dict - time: str = field(init=False) - details: ForecastTimeDetails = field(init=False) - next_hour: ForecastFuture = field(init=False) - next_6_hours: ForecastFuture = field(init=False) - next_12_hours: ForecastFuture = field(init=False) - - def __post_init__(self) -> None: - self.time = self._data["time"] - self.details = ForecastTimeDetails.create( - self._data["data"]["instant"]["details"] - ) - self.next_hour = ForecastFuture(**self._data["data"]["next_1_hours"]) - self.next_6_hours = ForecastFuture(**self._data["data"]["next_6_hours"]) - self.next_12_hours = ForecastFuture(**self._data["data"]["next_12_hours"]) + def __init__(self, _data: APIForecastTime): + self.time = _data["time"] + self.details = ForecastTimeDetails.create(_data["data"]["instant"]["details"]) + self.next_hour = ForecastFuture(**_data["data"]["next_1_hours"]) + self.next_6_hours = ForecastFuture(**_data["data"]["next_6_hours"]) + self.next_12_hours = ForecastFuture(**_data["data"]["next_12_hours"]) class Forecast: @@ -190,12 +185,12 @@ class Forecast: The units used by this forecast. """ - def __init__(self, forecast_data: dict) -> None: - self.type: str = forecast_data["type"] + def __init__(self, forecast_data: APIForecast) -> None: + self.type = forecast_data["type"] self.geometry = ForecastGeometry.create(forecast_data["geometry"]) meta = forecast_data["properties"]["meta"] - self.updated_at: str = meta["updated_at"] + self.updated_at = meta["updated_at"] self.units = ForecastUnits.create(meta["units"]) # The timeseries used internally is kept as a dict @@ -220,7 +215,7 @@ def now(self) -> ForecastTime: nearest_hour = time.strftime("%Y-%m-%dT%H:%M:%SZ") # Try to get the data for the nearest hour from API data - filtered_time: List[dict] = list( + filtered_time = list( filter(lambda t: t["time"] == nearest_hour, self._timeseries) ) @@ -250,7 +245,7 @@ def get_forecast_time(self, time: datetime) -> Optional[ForecastTime]: time = self._conv_to_nearest_hour(time) formatted_time = time.strftime("%Y-%m-%dT%H:%M:%SZ") - found_time: List[dict] = list( + found_time = list( filter(lambda t: t["time"] == formatted_time, self._timeseries) ) diff --git a/yr_weather/data/sunrise.py b/yr_weather/data/sunrise.py index 29626c1..88ce548 100644 --- a/yr_weather/data/sunrise.py +++ b/yr_weather/data/sunrise.py @@ -1,7 +1,9 @@ """Classes storing data used by yr_weather.sunrise""" from dataclasses import dataclass -from typing import Optional, Literal, List +from typing import Literal, List + +from yr_weather.api_types.sunrise import APISunData, APIMoonData, APIEventData @dataclass @@ -9,22 +11,18 @@ class EventsGeometry: """A dataclass holding coordinates.""" coordinates: List[float] - type: Literal["Point"] + type: str -@dataclass class CommonEventsData: - """A dataclass with common event data for both sun and moon events.""" - - type: Optional[str] = None - copyright: Optional[str] = None - license_url: Optional[str] = None - geometry: Optional[EventsGeometry] = None - interval: Optional[List[str]] = None + """A class with common event data for both sun and moon events.""" - def __post_init__(self): - if self.geometry: - self.geometry = EventsGeometry(**self.geometry) + def __init__(self, data: APIEventData): + self.type = data["type"] + self.copyright = data["copyright"] + self.license_url = data["licenseURL"] + self.geometry = EventsGeometry(**data["geometry"]) + self.interval = data["when"]["interval"] @dataclass @@ -47,14 +45,8 @@ class TimeWithElevation: class SunEvents(CommonEventsData): """A class with sun event data.""" - def __init__(self, data: dict): - super().__init__( - type=data["type"], - copyright=data["copyright"], - license_url=data["licenseURL"], - geometry=data["geometry"], - interval=data["when"]["interval"], - ) + def __init__(self, data: APISunData): + super().__init__(data) props = data["properties"] @@ -68,14 +60,8 @@ def __init__(self, data: dict): class MoonEvents(CommonEventsData): """A class with moon event data.""" - def __init__(self, data: dict): - super().__init__( - type=data["type"], - copyright=data["copyright"], - license_url=data["licenseURL"], - geometry=data["geometry"], - interval=data["when"]["interval"], - ) + def __init__(self, data: APIMoonData): + super().__init__(data) props = data["properties"] diff --git a/yr_weather/locationforecast.py b/yr_weather/locationforecast.py index d274813..dba4a7b 100644 --- a/yr_weather/locationforecast.py +++ b/yr_weather/locationforecast.py @@ -4,6 +4,7 @@ from .client import APIClient from .data.locationforecast import Forecast, ForecastTimeDetails, ForecastUnits +from .api_types.locationforecast import APIForecast class Locationforecast(APIClient): @@ -66,7 +67,7 @@ def get_forecast( self._base_url + f"{forecast_type}?lat={lat}&lon={lon}" ) - weather_data = request.json() + weather_data: APIForecast = request.json() return Forecast(weather_data) @@ -100,7 +101,7 @@ def get_air_temperature( url += f"&altitude={altitude}" request = self.session.get(url) - data = request.json() + data: APIForecast = request.json() forecast = Forecast(data) @@ -136,7 +137,7 @@ def get_instant_data( url += f"&altitude={altitude}" request = self.session.get(url) - data = request.json() + data: APIForecast = request.json() forecast = Forecast(data) @@ -153,7 +154,7 @@ def get_units(self) -> ForecastUnits: request = self.session.get(self._base_url + "complete?lat=0&lon=0") - data = request.json() + data: APIForecast = request.json() forecast = Forecast(data) diff --git a/yr_weather/sunrise.py b/yr_weather/sunrise.py index be87746..62d5bb3 100644 --- a/yr_weather/sunrise.py +++ b/yr_weather/sunrise.py @@ -1,11 +1,12 @@ """A module with classes for the Sunrise API.""" from datetime import datetime -from typing import Optional +from typing import Optional, Union import requests from .client import APIClient from .data.sunrise import SunEvents, MoonEvents +from .api_types.sunrise import APISunData, APIMoonData class Sunrise(APIClient): @@ -16,7 +17,7 @@ def __init__(self, headers, use_cache=True) -> None: self._base_url += "sunrise/3.0/" - def _get_events(self, event_type: str, **kwargs) -> dict: + def _get_events(self, event_type: str, **kwargs) -> Union[APISunData, APIMoonData]: date = kwargs.get("date") lat = kwargs.get("lat") lon = kwargs.get("lon") @@ -88,7 +89,7 @@ def get_sun_events( ------- :class:`.SunEvents` """ - data = self._get_events("sun", date=date, lat=lat, lon=lon, offset=offset) + data: APISunData = self._get_events("sun", date=date, lat=lat, lon=lon, offset=offset) # type: ignore[assignment] return SunEvents(data) @@ -118,7 +119,7 @@ def get_moon_events( ------- :class:`.MoonEvents` """ - data = self._get_events("moon", date=date, lat=lat, lon=lon, offset=offset) + data: APIMoonData = self._get_events("moon", date=date, lat=lat, lon=lon, offset=offset) # type: ignore[assignment] return MoonEvents(data)