-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrunner.py
More file actions
84 lines (71 loc) · 2.69 KB
/
Copy pathrunner.py
File metadata and controls
84 lines (71 loc) · 2.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
"""Runner module for the sample Python app.
Handles fetching, validation, and display of astronomical data.
"""
import json
import time
from datetime import date
import httpx
from pydantic import ValidationError
from sample_python_app.core import (
FETCH_COUNTER,
FETCH_DURATION,
FETCH_ERRORS,
setup_logger,
weather_settings,
)
from sample_python_app.exceptions import AppError
from sample_python_app.services import (
fetch_astronomical_data_from_api,
fetch_hourly_forecast_from_api,
)
from sample_python_app.ui import display_astronomical_data
logger = setup_logger("normal")
class AstroFetcher:
"""Fetches astronomical data and displays only once per day."""
def __init__(self) -> None:
"""Initialize the AstroFetcher with no last displayed day."""
self._last_displayed_day: str | None = None
def fetch(self, *, exit_on_error: bool = True) -> None:
"""Fetch astronomical data and display if not already displayed today."""
lat = weather_settings.LOCATION.latitude
lon = weather_settings.LOCATION.longitude
logger.info(f"Using latitude={lat} longitude={lon}")
start = time.time()
try:
astro = fetch_astronomical_data_from_api(lat, lon)
forecast = fetch_hourly_forecast_from_api(lat, lon)
FETCH_COUNTER.inc()
except (
httpx.HTTPStatusError,
httpx.RequestError,
ValidationError,
json.JSONDecodeError,
AppError,
) as exc:
self._handle_fetch_error(exc, exit_on_error)
return
finally:
FETCH_DURATION.observe(time.time() - start)
today_str = date.today().isoformat()
if self._last_displayed_day != today_str:
display_astronomical_data(astro, forecast)
self._last_displayed_day = today_str
def reset_display(self):
"""Reset the last displayed day so display will occur again."""
self._last_displayed_day = None
def _handle_fetch_error(self, exc: Exception, exit_on_error: bool) -> None:
FETCH_ERRORS.inc()
if isinstance(exc, httpx.HTTPStatusError):
logger.error("HTTP status error: %s", exc)
elif isinstance(exc, httpx.RequestError):
logger.error("Network error: %s", exc)
elif isinstance(exc, ValidationError):
logger.error("Validation error: %s", exc)
elif isinstance(exc, json.JSONDecodeError):
logger.error("JSON decode error: %s", exc)
else:
logger.exception("Unexpected error")
if exit_on_error:
raise SystemExit(1) from exc
raise AppError(str(exc)) from exc
fetcher = AstroFetcher()