Skip to content

Commit

Permalink
refactor: Use API types when processing data
Browse files Browse the repository at this point in the history
  • Loading branch information
ZeroWave022 committed Oct 10, 2023
1 parent 81283a5 commit a9f3c80
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 69 deletions.
2 changes: 1 addition & 1 deletion yr_weather/api_types/locationforecast.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ class APIForecastGeometry(TypedDict):


class APIForecast(TypedDict):
"""APIForecast forecast data"""
"""Full API forecast data"""

type: str
geometry: APIForecastGeometry
Expand Down
57 changes: 26 additions & 31 deletions yr_weather/data/locationforecast.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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.
Expand All @@ -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:
Expand All @@ -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
Expand All @@ -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)
)

Expand Down Expand Up @@ -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)
)

Expand Down
44 changes: 15 additions & 29 deletions yr_weather/data/sunrise.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,28 @@
"""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
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
Expand All @@ -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"]

Expand All @@ -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"]

Expand Down
9 changes: 5 additions & 4 deletions yr_weather/locationforecast.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from .client import APIClient

from .data.locationforecast import Forecast, ForecastTimeDetails, ForecastUnits
from .api_types.locationforecast import APIForecast


class Locationforecast(APIClient):
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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)

Expand All @@ -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)

Expand Down
9 changes: 5 additions & 4 deletions yr_weather/sunrise.py
Original file line number Diff line number Diff line change
@@ -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):
Expand All @@ -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")
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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)

Expand Down

0 comments on commit a9f3c80

Please sign in to comment.