forked from alexey-goloburdin/weather
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathweather_api_service.py
98 lines (85 loc) · 3.01 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
from datetime import datetime
from dataclasses import dataclass
from enum import Enum
import json
from json.decoder import JSONDecodeError
import ssl
from typing import Literal, TypeAlias
import urllib.request
from urllib.error import URLError
from coordinates import Coordinates
import config
from exceptions import ApiServiceError
Celsius: TypeAlias = float
class WeatherType(str, Enum):
THUNDERSTORM = "Гроза"
DRIZZLE = "Изморось"
RAIN = "Дождь"
SNOW = "Снег"
CLEAR = "Ясно"
FOG = "Туман"
CLOUDS = "Облачно"
@dataclass(slots=True, frozen=True)
class Weather:
temperature: Celsius
weather_type: WeatherType
sunrise: datetime
sunset: datetime
city: str
def get_weather(coordinates: Coordinates) -> Weather:
"""Requests weather in OpenWeather 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
url = config.OPENWEATHER_URL.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.7, longitude=37.6)))