python-weather 2.0.4__py3-none-any.whl → 2.0.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- python_weather/__init__.py +1 -1
- python_weather/base.py +53 -66
- python_weather/client.py +2 -1
- python_weather/enums.py +5 -8
- python_weather/forecast.py +197 -251
- {python_weather-2.0.4.dist-info → python_weather-2.0.5.dist-info}/METADATA +4 -4
- python_weather-2.0.5.dist-info/RECORD +12 -0
- python_weather-2.0.4.dist-info/RECORD +0 -12
- {python_weather-2.0.4.dist-info → python_weather-2.0.5.dist-info}/LICENSE +0 -0
- {python_weather-2.0.4.dist-info → python_weather-2.0.5.dist-info}/WHEEL +0 -0
- {python_weather-2.0.4.dist-info → python_weather-2.0.5.dist-info}/top_level.txt +0 -0
python_weather/__init__.py
CHANGED
python_weather/base.py
CHANGED
|
@@ -79,84 +79,71 @@ class CustomizableBase:
|
|
|
79
79
|
self.__locale = to
|
|
80
80
|
|
|
81
81
|
|
|
82
|
-
class BaseForecast
|
|
83
|
-
__slots__: Tuple[str, ...] = (
|
|
82
|
+
class BaseForecast:
|
|
83
|
+
__slots__: Tuple[str, ...] = (
|
|
84
|
+
'ultraviolet',
|
|
85
|
+
'humidity',
|
|
86
|
+
'wind_direction',
|
|
87
|
+
'kind',
|
|
88
|
+
'feels_like',
|
|
89
|
+
'temperature',
|
|
90
|
+
'precipitation',
|
|
91
|
+
'pressure',
|
|
92
|
+
'visibility',
|
|
93
|
+
'wind_speed',
|
|
94
|
+
'description',
|
|
95
|
+
)
|
|
84
96
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
super().__init__(unit, locale)
|
|
89
|
-
|
|
90
|
-
@property
|
|
91
|
-
def ultraviolet(self) -> UltraViolet:
|
|
92
|
-
"""The ultra-violet (UV) index."""
|
|
93
|
-
|
|
94
|
-
return UltraViolet._new(int(self.__inner['uvIndex']))
|
|
95
|
-
|
|
96
|
-
@property
|
|
97
|
-
def feels_like(self) -> int:
|
|
98
|
-
"""What it felt like, in celcius or fahrenheit."""
|
|
97
|
+
ultraviolet: UltraViolet
|
|
98
|
+
"""The ultra-violet (UV) index."""
|
|
99
99
|
|
|
100
|
-
|
|
100
|
+
humidity: int
|
|
101
|
+
"""The humidity value in percent."""
|
|
101
102
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
"""The humidity value in percent."""
|
|
103
|
+
wind_direction: WindDirection
|
|
104
|
+
"""The wind direction."""
|
|
105
105
|
|
|
106
|
-
|
|
106
|
+
kind: Kind
|
|
107
|
+
"""The kind of the forecast."""
|
|
107
108
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
"""The temperature in either celcius or Fahrenheit."""
|
|
109
|
+
feels_like: int
|
|
110
|
+
"""What it felt like, in celcius or fahrenheit."""
|
|
111
111
|
|
|
112
|
-
|
|
112
|
+
temperature: int
|
|
113
|
+
"""The temperature in either celcius or Fahrenheit."""
|
|
113
114
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
"""The precipitation in either millimeters or inches."""
|
|
115
|
+
precipitation: float
|
|
116
|
+
"""The precipitation in either millimeters or inches."""
|
|
117
117
|
|
|
118
|
-
|
|
118
|
+
pressure: float
|
|
119
|
+
"""The pressure in either pascal or inches."""
|
|
119
120
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
"""The pressure in either pascal or inches."""
|
|
121
|
+
visibility: int
|
|
122
|
+
"""The visibility distance in either kilometers or miles."""
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
wind_speed: int
|
|
125
|
+
"""The wind speeds in either kilometers/hour or miles/hour."""
|
|
125
126
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
"""The visibility distance in either kilometers or miles."""
|
|
129
|
-
|
|
130
|
-
return int(self.__inner[f'visibility{self._CustomizableBase__unit.visibility}'])
|
|
131
|
-
|
|
132
|
-
@property
|
|
133
|
-
def wind_speed(self) -> int:
|
|
134
|
-
"""The wind speeds in either kilometers/hour or miles/hour."""
|
|
135
|
-
|
|
136
|
-
return int(self.__inner[f'windspeed{self._CustomizableBase__unit.velocity}'])
|
|
137
|
-
|
|
138
|
-
@property
|
|
139
|
-
def wind_direction(self) -> WindDirection:
|
|
140
|
-
"""The wind direction."""
|
|
141
|
-
|
|
142
|
-
return WindDirection._new(
|
|
143
|
-
self.__inner['winddir16Point'], int(self.__inner['winddirDegree'])
|
|
144
|
-
)
|
|
145
|
-
|
|
146
|
-
@property
|
|
147
|
-
def description(self) -> str:
|
|
148
|
-
"""The description regarding the forecast. This can be localized in different languages depending on the localization used."""
|
|
127
|
+
description: str
|
|
128
|
+
"""The description regarding the forecast. This can be localized in different languages depending on the localization used."""
|
|
149
129
|
|
|
130
|
+
def __init__(self, json: dict, unit: _Unit, locale: Locale):
|
|
150
131
|
description = (
|
|
151
|
-
|
|
152
|
-
if
|
|
153
|
-
else
|
|
132
|
+
json['weatherDesc'][0]['value']
|
|
133
|
+
if locale is Locale.ENGLISH
|
|
134
|
+
else json[f'lang_{locale.value}'][0]['value']
|
|
154
135
|
)
|
|
155
136
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
137
|
+
self.ultraviolet = UltraViolet._new(int(json['uvIndex']))
|
|
138
|
+
self.humidity = int(json['humidity'])
|
|
139
|
+
self.wind_direction = WindDirection._new(
|
|
140
|
+
json['winddir16Point'], int(json['winddirDegree'])
|
|
141
|
+
)
|
|
142
|
+
self.kind = Kind(int(json['weatherCode']))
|
|
143
|
+
self.feels_like = int(json[f'FeelsLike{unit.temperature}'])
|
|
144
|
+
self.temperature = int(json[f'temp_{unit.temperature}'])
|
|
145
|
+
self.precipitation = float(json[f'precip{unit.precipitation}'])
|
|
146
|
+
self.pressure = float(json[f'pressure{unit.pressure}'])
|
|
147
|
+
self.visibility = int(json[f'visibility{unit.visibility}'])
|
|
148
|
+
self.wind_speed = int(json[f'windspeed{unit.velocity}'])
|
|
149
|
+
self.description = description.strip()
|
python_weather/client.py
CHANGED
|
@@ -62,7 +62,6 @@ class Client(CustomizableBase):
|
|
|
62
62
|
|
|
63
63
|
self.__own_session = session is None
|
|
64
64
|
self.__session = session or ClientSession(
|
|
65
|
-
raise_for_status=True,
|
|
66
65
|
timeout=ClientTimeout(total=5000.0),
|
|
67
66
|
connector=TCPConnector(verify_ssl=False),
|
|
68
67
|
)
|
|
@@ -112,6 +111,8 @@ class Client(CustomizableBase):
|
|
|
112
111
|
async with self.__session.get(
|
|
113
112
|
f'https://{subdomain}wttr.in/{quote_plus(location)}?format=j1'
|
|
114
113
|
) as resp:
|
|
114
|
+
resp.raise_for_status()
|
|
115
|
+
|
|
115
116
|
return Forecast(await resp.json(), unit, locale)
|
|
116
117
|
except Exception as err:
|
|
117
118
|
if delay == 4:
|
python_weather/enums.py
CHANGED
|
@@ -122,7 +122,7 @@ class UltraViolet(BasicEnum, IndexedEnum):
|
|
|
122
122
|
class WindDirection(BasicEnum):
|
|
123
123
|
"""Represents a wind direction."""
|
|
124
124
|
|
|
125
|
-
__slots__: Tuple[str, ...] = ('
|
|
125
|
+
__slots__: Tuple[str, ...] = ('degrees',)
|
|
126
126
|
|
|
127
127
|
NORTH = 'N'
|
|
128
128
|
NORTH_NORTHEAST = 'NNE'
|
|
@@ -141,9 +141,12 @@ class WindDirection(BasicEnum):
|
|
|
141
141
|
NORTHWEST = 'NW'
|
|
142
142
|
NORTH_NORTHWEST = 'NNW'
|
|
143
143
|
|
|
144
|
+
degrees: float
|
|
145
|
+
"""The wind direction's value in degrees."""
|
|
146
|
+
|
|
144
147
|
def _new(value: str, degrees: float) -> 'WindDirection':
|
|
145
148
|
enum = WindDirection(value)
|
|
146
|
-
enum.
|
|
149
|
+
enum.degrees = degrees
|
|
147
150
|
|
|
148
151
|
return enum
|
|
149
152
|
|
|
@@ -186,12 +189,6 @@ class WindDirection(BasicEnum):
|
|
|
186
189
|
def __float__(self) -> float:
|
|
187
190
|
return self.__degrees
|
|
188
191
|
|
|
189
|
-
@property
|
|
190
|
-
def degrees(self) -> int:
|
|
191
|
-
"""The wind direction's value in degrees."""
|
|
192
|
-
|
|
193
|
-
return self.__degrees
|
|
194
|
-
|
|
195
192
|
@property
|
|
196
193
|
def emoji(self) -> str:
|
|
197
194
|
"""The emoji representing this enum."""
|
python_weather/forecast.py
CHANGED
|
@@ -25,7 +25,7 @@ SOFTWARE.
|
|
|
25
25
|
from typing import Iterable, Optional, Tuple, List
|
|
26
26
|
from datetime import datetime, date, time
|
|
27
27
|
|
|
28
|
-
from .base import BaseForecast
|
|
28
|
+
from .base import BaseForecast
|
|
29
29
|
from .enums import Phase, Locale, HeatIndex
|
|
30
30
|
from .constants import _Unit, LATLON_REGEX
|
|
31
31
|
|
|
@@ -33,318 +33,264 @@ from .constants import _Unit, LATLON_REGEX
|
|
|
33
33
|
class HourlyForecast(BaseForecast):
|
|
34
34
|
"""Represents a weather forecast of a specific hour."""
|
|
35
35
|
|
|
36
|
-
__slots__: Tuple[str, ...] = (
|
|
36
|
+
__slots__: Tuple[str, ...] = (
|
|
37
|
+
'chances_of_fog',
|
|
38
|
+
'chances_of_frost',
|
|
39
|
+
'chances_of_high_temperature',
|
|
40
|
+
'chances_of_overcast',
|
|
41
|
+
'chances_of_rain',
|
|
42
|
+
'chances_of_remaining_dry',
|
|
43
|
+
'chances_of_snow',
|
|
44
|
+
'chances_of_sunshine',
|
|
45
|
+
'chances_of_thunder',
|
|
46
|
+
'chances_of_windy',
|
|
47
|
+
'cloud_cover',
|
|
48
|
+
'time',
|
|
49
|
+
'dew_point',
|
|
50
|
+
'heat_index',
|
|
51
|
+
'wind_chill',
|
|
52
|
+
'wind_gust',
|
|
53
|
+
)
|
|
37
54
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if 'temp_C' not in json:
|
|
41
|
-
json['temp_C'] = json.pop('tempC')
|
|
42
|
-
if 'temp_F' not in json:
|
|
43
|
-
json['temp_F'] = json.pop('tempF')
|
|
44
|
-
|
|
45
|
-
super().__init__(json, unit, locale)
|
|
46
|
-
|
|
47
|
-
def __repr__(self) -> str:
|
|
48
|
-
return f'<{__class__.__name__} time={self.time!r} temperature={self.temperature!r} description={self.description!r} kind={self.kind!r}>'
|
|
49
|
-
|
|
50
|
-
@property
|
|
51
|
-
def dew_point(self) -> int:
|
|
52
|
-
"""The dew point in either celcius or fahrenheit."""
|
|
55
|
+
chances_of_fog: int
|
|
56
|
+
"""Chances of a fog in percent."""
|
|
53
57
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
-
@property
|
|
59
|
-
def heat_index(self) -> HeatIndex:
|
|
60
|
-
"""The heat index in either celcius or fahrenheit."""
|
|
61
|
-
|
|
62
|
-
celcius_index = int(self._BaseForecast__inner['HeatIndexC'])
|
|
63
|
-
|
|
64
|
-
return HeatIndex._new(
|
|
65
|
-
celcius_index,
|
|
66
|
-
int(
|
|
67
|
-
self._BaseForecast__inner[
|
|
68
|
-
f'HeatIndex{self._CustomizableBase__unit.temperature}'
|
|
69
|
-
]
|
|
70
|
-
),
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
@property
|
|
74
|
-
def wind_chill(self) -> int:
|
|
75
|
-
"""The wind chill value in either celcius or fahrenheit."""
|
|
76
|
-
|
|
77
|
-
return int(
|
|
78
|
-
self._BaseForecast__inner[f'WindChill{self._CustomizableBase__unit.temperature}']
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
@property
|
|
82
|
-
def wind_gust(self) -> int:
|
|
83
|
-
"""The wind gust value in either kilometers/hour or miles/hour."""
|
|
84
|
-
|
|
85
|
-
return int(
|
|
86
|
-
self._BaseForecast__inner[f'WindGust{self._CustomizableBase__unit.velocity}']
|
|
87
|
-
)
|
|
58
|
+
chances_of_frost: int
|
|
59
|
+
"""Chances of a frost in percent."""
|
|
88
60
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
"""Chances of a fog in percent."""
|
|
61
|
+
chances_of_high_temperature: int
|
|
62
|
+
"""Chances of a high temperature in percent."""
|
|
92
63
|
|
|
93
|
-
|
|
64
|
+
chances_of_overcast: int
|
|
65
|
+
"""Chances of an overcast in percent."""
|
|
94
66
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
"""Chances of a frost in percent."""
|
|
67
|
+
chances_of_rain: int
|
|
68
|
+
"""Chances of a rain in percent."""
|
|
98
69
|
|
|
99
|
-
|
|
70
|
+
chances_of_remaining_dry: int
|
|
71
|
+
"""Chances of remaining dry in percent."""
|
|
100
72
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
"""Chances of a high temperature in percent."""
|
|
73
|
+
chances_of_snow: int
|
|
74
|
+
"""Chances of a snow in percent."""
|
|
104
75
|
|
|
105
|
-
|
|
76
|
+
chances_of_sunshine: int
|
|
77
|
+
"""Chances of a sunshine in percent."""
|
|
106
78
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
"""Chances of an overcast in percent."""
|
|
79
|
+
chances_of_thunder: int
|
|
80
|
+
"""Chances of a thunder in percent."""
|
|
110
81
|
|
|
111
|
-
|
|
82
|
+
chances_of_windy: int
|
|
83
|
+
"""Chances of windy in percent."""
|
|
112
84
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
"""Chances of a rain in percent."""
|
|
85
|
+
cloud_cover: int
|
|
86
|
+
"""The cloud cover value in percent."""
|
|
116
87
|
|
|
117
|
-
|
|
88
|
+
time: 'time'
|
|
89
|
+
"""The local time in hours and minutes."""
|
|
118
90
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
"""Chances of remaining dry in percent."""
|
|
91
|
+
dew_point: int
|
|
92
|
+
"""The dew point in either celcius or fahrenheit."""
|
|
122
93
|
|
|
123
|
-
|
|
94
|
+
heat_index: HeatIndex
|
|
95
|
+
"""The heat index in either celcius or fahrenheit."""
|
|
124
96
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
"""Chances of a snow in percent."""
|
|
97
|
+
wind_chill: int
|
|
98
|
+
"""The wind chill value in either celcius or fahrenheit."""
|
|
128
99
|
|
|
129
|
-
|
|
100
|
+
wind_gust: int
|
|
101
|
+
"""The wind gust value in either kilometers/hour or miles/hour."""
|
|
130
102
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
@property
|
|
138
|
-
def chances_of_thunder(self) -> int:
|
|
139
|
-
"""Chances of a thunder in percent."""
|
|
140
|
-
|
|
141
|
-
return int(self._BaseForecast__inner['chanceofthunder'])
|
|
142
|
-
|
|
143
|
-
@property
|
|
144
|
-
def chances_of_windy(self) -> int:
|
|
145
|
-
"""Chances of windy in percent."""
|
|
146
|
-
|
|
147
|
-
return int(self._BaseForecast__inner['chanceofwindy'])
|
|
148
|
-
|
|
149
|
-
@property
|
|
150
|
-
def cloud_cover(self) -> int:
|
|
151
|
-
"""The cloud cover value in percent."""
|
|
152
|
-
|
|
153
|
-
return int(self._BaseForecast__inner['cloudcover'])
|
|
154
|
-
|
|
155
|
-
@property
|
|
156
|
-
def time(self) -> time:
|
|
157
|
-
"""The local time in hours and minutes."""
|
|
103
|
+
def __init__(self, json: dict, unit: _Unit, locale: Locale):
|
|
104
|
+
# for inheritance purposes
|
|
105
|
+
if 'temp_C' not in json:
|
|
106
|
+
json['temp_C'] = json.pop('tempC')
|
|
107
|
+
if 'temp_F' not in json:
|
|
108
|
+
json['temp_F'] = json.pop('tempF')
|
|
158
109
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
110
|
+
celcius_index = int(json['HeatIndexC'])
|
|
111
|
+
t = json['time']
|
|
112
|
+
|
|
113
|
+
self.chances_of_fog = int(json['chanceoffog'])
|
|
114
|
+
self.chances_of_frost = int(json['chanceoffrost'])
|
|
115
|
+
self.chances_of_high_temperature = int(json['chanceofhightemp'])
|
|
116
|
+
self.chances_of_overcast = int(json['chanceofovercast'])
|
|
117
|
+
self.chances_of_rain = int(json['chanceofrain'])
|
|
118
|
+
self.chances_of_remaining_dry = int(json['chanceofremdry'])
|
|
119
|
+
self.chances_of_snow = int(json['chanceofsnow'])
|
|
120
|
+
self.chances_of_sunshine = int(json['chanceofsunshine'])
|
|
121
|
+
self.chances_of_thunder = int(json['chanceofthunder'])
|
|
122
|
+
self.chances_of_windy = int(json['chanceofwindy'])
|
|
123
|
+
self.cloud_cover = int(json['cloudcover'])
|
|
124
|
+
self.time = time() if len(t) < 3 else datetime.strptime(t, '%H%M').time()
|
|
125
|
+
self.dew_point = int(json[f'DewPoint{unit.temperature}'])
|
|
126
|
+
self.heat_index = HeatIndex._new(
|
|
127
|
+
celcius_index,
|
|
128
|
+
int(json[f'HeatIndex{unit.temperature}']),
|
|
163
129
|
)
|
|
130
|
+
self.wind_chill = int(json[f'WindChill{unit.temperature}'])
|
|
131
|
+
self.wind_gust = int(json[f'WindGust{unit.velocity}'])
|
|
164
132
|
|
|
133
|
+
super().__init__(json, unit, locale)
|
|
165
134
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
def __init__(self, json: dict, unit: _Unit, locale: Locale):
|
|
170
|
-
self.__astronomy = json.pop('astronomy')[0]
|
|
171
|
-
self.__inner = json
|
|
135
|
+
def __repr__(self) -> str:
|
|
136
|
+
return f'<{__class__.__name__} time={self.time!r} temperature={self.temperature!r} description={self.description!r} kind={self.kind!r}>'
|
|
172
137
|
|
|
173
|
-
super().__init__(unit, locale)
|
|
174
138
|
|
|
175
|
-
|
|
176
|
-
|
|
139
|
+
class DailyForecast:
|
|
140
|
+
__slots__: Tuple[str, ...] = (
|
|
141
|
+
'moon_illumination',
|
|
142
|
+
'moon_phase',
|
|
143
|
+
'moonrise',
|
|
144
|
+
'moonset',
|
|
145
|
+
'sunrise',
|
|
146
|
+
'sunset',
|
|
147
|
+
'date',
|
|
148
|
+
'sunlight',
|
|
149
|
+
'lowest_temperature',
|
|
150
|
+
'highest_temperature',
|
|
151
|
+
'temperature',
|
|
152
|
+
'snowfall',
|
|
153
|
+
'hourly_forecasts',
|
|
154
|
+
)
|
|
177
155
|
|
|
178
|
-
|
|
179
|
-
|
|
156
|
+
moon_illumination: int
|
|
157
|
+
"""The percentage of the moon illuminated."""
|
|
180
158
|
|
|
181
|
-
|
|
182
|
-
|
|
159
|
+
moon_phase: Phase
|
|
160
|
+
"""The moon's phase."""
|
|
183
161
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
"""The percentage of the moon illuminated."""
|
|
162
|
+
moonrise: Optional[time]
|
|
163
|
+
"""The local time when the moon rises. This can be ``None``."""
|
|
187
164
|
|
|
188
|
-
|
|
165
|
+
moonset: Optional[time]
|
|
166
|
+
"""The local time when the moon sets. This can be ``None``."""
|
|
189
167
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
"""The moon's phase."""
|
|
168
|
+
sunrise: Optional[time]
|
|
169
|
+
"""The local time when the sun rises. This can be ``None``."""
|
|
193
170
|
|
|
194
|
-
|
|
171
|
+
sunset: Optional[time]
|
|
172
|
+
"""The local time when the sun sets. This can be ``None``."""
|
|
195
173
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
"""The local time when the moon rises. This can be ``None``."""
|
|
174
|
+
date: 'date'
|
|
175
|
+
"""The local date of this forecast."""
|
|
199
176
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
except ValueError:
|
|
203
|
-
...
|
|
177
|
+
sunlight: float
|
|
178
|
+
"""Hours of sunlight."""
|
|
204
179
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
"""The local time when the moon sets. This can be ``None``."""
|
|
180
|
+
lowest_temperature: int
|
|
181
|
+
"""The lowest temperature in either celcius or fahrenheit."""
|
|
208
182
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
except ValueError:
|
|
212
|
-
...
|
|
183
|
+
highest_temperature: int
|
|
184
|
+
"""The highest temperature in either celcius or fahrenheit."""
|
|
213
185
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
"""The local time when the sun rises. This can be ``None``."""
|
|
186
|
+
temperature: int
|
|
187
|
+
"""The average temperature in either celcius or fahrenheit."""
|
|
217
188
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
except ValueError:
|
|
221
|
-
...
|
|
189
|
+
snowfall: float
|
|
190
|
+
"""Total snowfall in either centimeters or inches."""
|
|
222
191
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
"""The local time when the sun sets. This can be ``None``."""
|
|
192
|
+
hourly_forecasts: List[HourlyForecast]
|
|
193
|
+
"""The hourly forecasts of this day."""
|
|
226
194
|
|
|
195
|
+
def __init__(self, json: dict, unit: _Unit, locale: Locale):
|
|
196
|
+
astronomy = json['astronomy'][0]
|
|
197
|
+
|
|
198
|
+
self.moon_illumination = int(astronomy['moon_illumination'])
|
|
199
|
+
self.moon_phase = Phase(astronomy['moon_phase'])
|
|
200
|
+
self.moonrise = __class__.__parse_time(astronomy['moonrise'])
|
|
201
|
+
self.moonset = __class__.__parse_time(astronomy['moonset'])
|
|
202
|
+
self.sunrise = __class__.__parse_time(astronomy['sunrise'])
|
|
203
|
+
self.sunset = __class__.__parse_time(astronomy['sunset'])
|
|
204
|
+
self.date = datetime.strptime(json['date'], '%Y-%m-%d').date()
|
|
205
|
+
self.sunlight = float(json['sunHour'])
|
|
206
|
+
self.lowest_temperature = int(json[f'mintemp{unit.temperature}'])
|
|
207
|
+
self.highest_temperature = int(json[f'maxtemp{unit.temperature}'])
|
|
208
|
+
self.temperature = int(json[f'avgtemp{unit.temperature}'])
|
|
209
|
+
self.snowfall = float(json['totalSnow_cm']) / unit.cm_divisor
|
|
210
|
+
self.hourly_forecasts = [
|
|
211
|
+
HourlyForecast(elem, unit, locale) for elem in json['hourly']
|
|
212
|
+
]
|
|
213
|
+
|
|
214
|
+
@staticmethod
|
|
215
|
+
def __parse_time(timestamp: str) -> Optional[time]:
|
|
227
216
|
try:
|
|
228
|
-
return datetime.strptime(
|
|
217
|
+
return datetime.strptime(timestamp, '%I:%M %p').time()
|
|
229
218
|
except ValueError:
|
|
230
219
|
...
|
|
231
220
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
"""The local date of this forecast."""
|
|
221
|
+
def __repr__(self) -> str:
|
|
222
|
+
return f'<{__class__.__name__} date={self.date!r} temperature={self.temperature!r}>'
|
|
235
223
|
|
|
236
|
-
|
|
224
|
+
def __len__(self) -> int:
|
|
225
|
+
return len(self.hourly_forecasts)
|
|
237
226
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
"""The lowest temperature in either celcius or fahrenheit."""
|
|
227
|
+
def __iter__(self) -> Iterable[HourlyForecast]:
|
|
228
|
+
return iter(self.hourly_forecasts)
|
|
241
229
|
|
|
242
|
-
return int(self.__inner[f'mintemp{self._CustomizableBase__unit.temperature}'])
|
|
243
230
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
"""The highest temperature in either celcius or fahrenheit."""
|
|
231
|
+
class Forecast(BaseForecast):
|
|
232
|
+
"""Represents today's weather forecast, alongside daily and hourly weather forecasts."""
|
|
247
233
|
|
|
248
|
-
|
|
234
|
+
__slots__: Tuple[str, ...] = (
|
|
235
|
+
'local_population',
|
|
236
|
+
'region',
|
|
237
|
+
'location',
|
|
238
|
+
'country',
|
|
239
|
+
'datetime',
|
|
240
|
+
'coordinates',
|
|
241
|
+
'daily_forecasts',
|
|
242
|
+
)
|
|
249
243
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
"""The average temperature in either celcius or fahrenheit."""
|
|
244
|
+
local_population: int
|
|
245
|
+
"""The local population count."""
|
|
253
246
|
|
|
254
|
-
|
|
247
|
+
region: str
|
|
248
|
+
"""The local region's name."""
|
|
255
249
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
"""Hours of sunlight."""
|
|
250
|
+
location: str
|
|
251
|
+
"""The location's name."""
|
|
259
252
|
|
|
260
|
-
|
|
253
|
+
country: str
|
|
254
|
+
"""The local country's name."""
|
|
261
255
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
"""Total snowfall in either centimeters or inches."""
|
|
256
|
+
datetime: 'datetime'
|
|
257
|
+
"""The local date and time of this weather forecast."""
|
|
265
258
|
|
|
266
|
-
|
|
259
|
+
coordinates: Tuple[float, float]
|
|
260
|
+
"""A tuple of this forecast's latitude and longitude."""
|
|
267
261
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
"""The hourly forecasts of this day."""
|
|
262
|
+
daily_forecasts: List[DailyForecast]
|
|
263
|
+
"""Daily weather forecasts in this location."""
|
|
271
264
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
)
|
|
265
|
+
def __init__(self, json: dict, unit: _Unit, locale: Locale):
|
|
266
|
+
current = json['current_condition'][0]
|
|
267
|
+
nearest = json['nearest_area'][0]
|
|
276
268
|
|
|
269
|
+
self.local_population = int(nearest['population'])
|
|
270
|
+
self.region = nearest['region'][0]['value']
|
|
271
|
+
self.location = nearest['areaName'][0]['value']
|
|
272
|
+
self.country = nearest['country'][0]['value']
|
|
273
|
+
self.datetime = datetime.strptime(current['localObsDateTime'], '%Y-%m-%d %I:%M %p')
|
|
277
274
|
|
|
278
|
-
|
|
279
|
-
|
|
275
|
+
try:
|
|
276
|
+
req = next(filter(lambda x: x['type'] == 'LatLon', json['request']))
|
|
277
|
+
match = LATLON_REGEX.match(req['query'])
|
|
280
278
|
|
|
281
|
-
|
|
279
|
+
self.coordinates = (float(match[1]), float(match[2]))
|
|
280
|
+
except:
|
|
281
|
+
self.coordinates = (float(nearest['latitude']), float(nearest['longitude']))
|
|
282
282
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
self.__inner = json
|
|
283
|
+
self.daily_forecasts = [
|
|
284
|
+
DailyForecast(elem, unit, locale) for elem in json['weather']
|
|
285
|
+
]
|
|
287
286
|
|
|
288
287
|
super().__init__(current, unit, locale)
|
|
289
288
|
|
|
290
289
|
def __repr__(self) -> str:
|
|
291
290
|
return f'<{__class__.__name__} location={self.location!r} datetime={self.datetime!r} temperature={self.temperature!r}>'
|
|
292
291
|
|
|
293
|
-
def
|
|
294
|
-
return self.daily_forecasts
|
|
295
|
-
|
|
296
|
-
def __list__(self) -> List[DailyForecast]:
|
|
297
|
-
return list(iter(self))
|
|
298
|
-
|
|
299
|
-
@property
|
|
300
|
-
def local_population(self) -> int:
|
|
301
|
-
"""The local population count."""
|
|
302
|
-
|
|
303
|
-
return int(self.__nearest['population'])
|
|
304
|
-
|
|
305
|
-
@property
|
|
306
|
-
def region(self) -> str:
|
|
307
|
-
"""The local region's name."""
|
|
308
|
-
|
|
309
|
-
return self.__nearest['region'][0]['value']
|
|
310
|
-
|
|
311
|
-
@property
|
|
312
|
-
def location(self) -> str:
|
|
313
|
-
"""The location's name."""
|
|
314
|
-
|
|
315
|
-
return self.__nearest['areaName'][0]['value']
|
|
316
|
-
|
|
317
|
-
@property
|
|
318
|
-
def country(self) -> str:
|
|
319
|
-
"""The local country's name."""
|
|
320
|
-
|
|
321
|
-
return self.__nearest['country'][0]['value']
|
|
322
|
-
|
|
323
|
-
@property
|
|
324
|
-
def datetime(self) -> datetime:
|
|
325
|
-
"""The local date and time of this weather forecast."""
|
|
292
|
+
def __len__(self) -> int:
|
|
293
|
+
return len(self.daily_forecasts)
|
|
326
294
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
)
|
|
330
|
-
|
|
331
|
-
@property
|
|
332
|
-
def daily_forecasts(self) -> Iterable[DailyForecast]:
|
|
333
|
-
"""Daily weather forecasts in this location."""
|
|
334
|
-
|
|
335
|
-
return (
|
|
336
|
-
DailyForecast(elem, self._CustomizableBase__unit, self._CustomizableBase__locale)
|
|
337
|
-
for elem in self.__inner['weather']
|
|
338
|
-
)
|
|
339
|
-
|
|
340
|
-
@property
|
|
341
|
-
def coordinates(self) -> Tuple[float, float]:
|
|
342
|
-
"""A tuple of this forecast's latitude and longitude."""
|
|
343
|
-
|
|
344
|
-
try:
|
|
345
|
-
req = next(filter(lambda x: x['type'] == 'LatLon', self.__inner['request']))
|
|
346
|
-
match = LATLON_REGEX.match(req['query'])
|
|
347
|
-
|
|
348
|
-
return float(match[1]), float(match[2])
|
|
349
|
-
except:
|
|
350
|
-
return float(self.__nearest['latitude']), float(self.__nearest['longitude'])
|
|
295
|
+
def __iter__(self) -> Iterable[DailyForecast]:
|
|
296
|
+
return iter(self.daily_forecasts)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python-weather
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.5
|
|
4
4
|
Summary: A free and asynchronous weather API wrapper made in Python, for Python.
|
|
5
5
|
Author: null8626
|
|
6
6
|
License: MIT
|
|
@@ -11,12 +11,11 @@ Project-URL: Donate via GitHub Sponsors, https://github.com/sponsors/null8626
|
|
|
11
11
|
Project-URL: Donate via Ko-fi, https://ko-fi.com/null8626
|
|
12
12
|
Keywords: weather,forecast,weather-api,weather-forecast
|
|
13
13
|
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
-
Classifier: Framework :: aiohttp
|
|
15
|
-
Classifier: Framework :: AsyncIO
|
|
16
14
|
Classifier: Intended Audience :: Education
|
|
17
15
|
Classifier: Intended Audience :: Developers
|
|
18
16
|
Classifier: Intended Audience :: Information Technology
|
|
19
17
|
Classifier: Natural Language :: English
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
20
19
|
Classifier: Topic :: Education
|
|
21
20
|
Classifier: Topic :: Internet
|
|
22
21
|
Classifier: Topic :: Scientific/Engineering
|
|
@@ -32,10 +31,11 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
32
31
|
Classifier: Programming Language :: Python :: 3.10
|
|
33
32
|
Classifier: Programming Language :: Python :: 3.11
|
|
34
33
|
Classifier: Programming Language :: Python :: 3.12
|
|
34
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
35
35
|
Requires-Python: >=3.8
|
|
36
36
|
Description-Content-Type: text/markdown
|
|
37
37
|
License-File: LICENSE
|
|
38
|
-
Requires-Dist: aiohttp >=3.10.
|
|
38
|
+
Requires-Dist: aiohttp >=3.10.10
|
|
39
39
|
|
|
40
40
|
# [python-weather][pypi-url] [![pypi][pypi-image]][pypi-url] [![downloads][downloads-image]][pypi-url] [![codacy-badge][codacy-url]][codacy-image] [![ko-fi][ko-fi-brief-image]][ko-fi-url]
|
|
41
41
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
python_weather/__init__.py,sha256=Bmexsn_sEwoirakPu6MHXTuFq1AAdSw-mAC18EPntTM,1586
|
|
2
|
+
python_weather/base.py,sha256=rNxoxmiEbsAlQs2DXB0gpMP0Ug8L0vaqxXA69ez-9Mg,4661
|
|
3
|
+
python_weather/client.py,sha256=IlrI7BjDrRmb9hGlBoYwmJDNvXZt8HmbPexUDgvKhRo,5032
|
|
4
|
+
python_weather/constants.py,sha256=NzfQkxmAPEYAbUHMBUEi9-4XOq0z8FYj1_G_1z5Of-4,2015
|
|
5
|
+
python_weather/enums.py,sha256=I8d8DDAhg3RBvCtiCiTCa0WBz7738ZgBFzoH_iqxqp4,10594
|
|
6
|
+
python_weather/errors.py,sha256=sbCEmzXvC_jxyCVJ8aBVOwIMU3FSM4d0Myu2rYUWaI8,1574
|
|
7
|
+
python_weather/forecast.py,sha256=gNdvMisnjIiNyQQfgImltDPhgB6900PTeCl87hZ_gkI,9124
|
|
8
|
+
python_weather-2.0.5.dist-info/LICENSE,sha256=OhQiuzPzGigVn4yKdwlDJMfyglio438lXJU5ny4WCGk,1080
|
|
9
|
+
python_weather-2.0.5.dist-info/METADATA,sha256=wFMEnFpLJ3OhaEhyg5I5-VlGY-v-SVLdWZQ10yvW0PA,4130
|
|
10
|
+
python_weather-2.0.5.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
|
11
|
+
python_weather-2.0.5.dist-info/top_level.txt,sha256=NDqLSO3dHB1tjjiNJfEg-a9_eoOmawAZynZsy9Yu48w,15
|
|
12
|
+
python_weather-2.0.5.dist-info/RECORD,,
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
python_weather/__init__.py,sha256=FbHn9_8A63GXbpFmiyPalMPynvtcurGVX8zZk96VNZs,1586
|
|
2
|
-
python_weather/base.py,sha256=esxcbl0nf7ExIczzG0cpvTKAFFKEKRtprj5sU_6wBqQ,5031
|
|
3
|
-
python_weather/client.py,sha256=k9PXBUhQIGOLluNasoOpMhvKMblOfGqZOnGE1lDU_Is,5026
|
|
4
|
-
python_weather/constants.py,sha256=NzfQkxmAPEYAbUHMBUEi9-4XOq0z8FYj1_G_1z5Of-4,2015
|
|
5
|
-
python_weather/enums.py,sha256=e5O1rbyQD42vv4ATDJP4z32UPbPn5UVytNdtycYhBOE,10650
|
|
6
|
-
python_weather/errors.py,sha256=sbCEmzXvC_jxyCVJ8aBVOwIMU3FSM4d0Myu2rYUWaI8,1574
|
|
7
|
-
python_weather/forecast.py,sha256=iFoGBhrVELHzbsuJsHcH9xM5FHcbQF8JiRhR74b4yfo,10101
|
|
8
|
-
python_weather-2.0.4.dist-info/LICENSE,sha256=OhQiuzPzGigVn4yKdwlDJMfyglio438lXJU5ny4WCGk,1080
|
|
9
|
-
python_weather-2.0.4.dist-info/METADATA,sha256=1IgvugBGriUP0sYZIePFw1Mo4WgnGvOBYbq_Kl6iUjQ,4097
|
|
10
|
-
python_weather-2.0.4.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
|
11
|
-
python_weather-2.0.4.dist-info/top_level.txt,sha256=NDqLSO3dHB1tjjiNJfEg-a9_eoOmawAZynZsy9Yu48w,15
|
|
12
|
-
python_weather-2.0.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|