-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathweather_api_service.py
120 lines (95 loc) · 3.44 KB
/
weather_api_service.py
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
from datetime import datetime
import json
from json.decoder import JSONDecodeError
import ssl
import urllib.request
from urllib.error import URLError
from enum import Enum
from typing import Literal, NamedTuple, TypeAlias
import config
from coordinates import Coordinates
from exceptions import ApiServiceError
Celsius: TypeAlias = int
class WeatherType(str, Enum):
THUNDERSTORM = "Гроза"
DRIZZLE = "Изморось"
RAIN = "Дождь"
SNOW = "Снег"
CLEAR = "Ясно"
FOG = "Туман"
CLOUDS = "Облачно"
class Weather(NamedTuple):
temperature: Celsius
weather_type: WeatherType
sunrise: datetime
sunset: datetime
city: str
def get_weather(coordinates: Coordinates) -> Weather:
"""Requests weather in OpenWeatherMap API and returns it"""
openweather_response = _get_openweather_response(
longitude=coordinates.longitude, latitude=coordinates.latitude
)
weather = _parse_openweather_response(openweather_response)
return weather
def _get_openweather_response(latitude: float, longitude: float) -> str:
ssl._create_default_https_context = ssl._create_unverified_context
# TODO: Use GPS or Input, add functionality of input name of City if GPS locator coordination doesn't work
# if user set config.USE_GPS == True; then return url with "city api query"
# if config.USE_GPS:
# url = config.OPENWEATHER_URL_TEMPLATE.format(
# latitude=latitude, longitude=longitude
# )
# else:
# url = config.OPENWEATHER_CITY_URL_TEMPLATE.format(
# city="Almaty"
# )
url = config.OPENWEATHER_URL_TEMPLATE.format(
latitude=latitude, longitude=longitude
)
try:
return urllib.request.urlopen(url).read()
except URLError:
raise ApiServiceError
def _parse_openweather_response(openweather_response: str) -> Weather:
try:
openweather_dict = json.loads(openweather_response)
except JSONDecodeError:
raise ApiServiceError
return Weather(
temperature=_parse_temperature(openweather_dict),
weather_type=_parse_weather_type(openweather_dict),
sunrise=_parse_sun_time(openweather_dict, "sunrise"),
sunset=_parse_sun_time(openweather_dict, "sunset"),
city=_parse_city(openweather_dict)
)
def _parse_temperature(openweather_dict: dict) -> Celsius:
return round(openweather_dict["main"]["temp"])
def _parse_weather_type(openweather_dict: dict) -> WeatherType:
try:
weather_type_id = str(openweather_dict["weather"][0]["id"])
except (IndexError, KeyError):
raise ApiServiceError
weather_types = {
"1": WeatherType.THUNDERSTORM,
"3": WeatherType.DRIZZLE,
"5": WeatherType.RAIN,
"6": WeatherType.SNOW,
"7": WeatherType.FOG,
"800": WeatherType.CLEAR,
"80": WeatherType.CLOUDS
}
for _id, _weather_type in weather_types.items():
if weather_type_id.startswith(_id):
return _weather_type
raise ApiServiceError
def _parse_sun_time(
openweather_dict: dict,
time: Literal["sunrise"] | Literal["sunset"]) -> datetime:
return datetime.fromtimestamp(openweather_dict["sys"][time])
def _parse_city(openweather_dict: dict) -> str:
try:
return openweather_dict["name"]
except KeyError:
raise ApiServiceError
if __name__ == "__main__":
print(get_weather(Coordinates(latitude=55.75, longitude=37.65)))