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.
@@ -31,7 +31,7 @@ __title__ = 'python-weather'
31
31
  __author__ = 'null8626'
32
32
  __license__ = 'MIT'
33
33
  __copyright__ = 'Copyright (c) 2021-2024 null8626'
34
- __version__ = '2.0.4'
34
+ __version__ = '2.0.5'
35
35
  __all__ = (
36
36
  'METRIC',
37
37
  'IMPERIAL',
python_weather/base.py CHANGED
@@ -79,84 +79,71 @@ class CustomizableBase:
79
79
  self.__locale = to
80
80
 
81
81
 
82
- class BaseForecast(CustomizableBase):
83
- __slots__: Tuple[str, ...] = ('__inner',)
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
- def __init__(self, json: dict, unit: _Unit, locale: Locale):
86
- self.__inner = json
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
- return int(self.__inner[f'FeelsLike{self._CustomizableBase__unit.temperature}'])
100
+ humidity: int
101
+ """The humidity value in percent."""
101
102
 
102
- @property
103
- def humidity(self) -> int:
104
- """The humidity value in percent."""
103
+ wind_direction: WindDirection
104
+ """The wind direction."""
105
105
 
106
- return int(self.__inner['humidity'])
106
+ kind: Kind
107
+ """The kind of the forecast."""
107
108
 
108
- @property
109
- def temperature(self) -> int:
110
- """The temperature in either celcius or Fahrenheit."""
109
+ feels_like: int
110
+ """What it felt like, in celcius or fahrenheit."""
111
111
 
112
- return int(self.__inner[f'temp_{self._CustomizableBase__unit.temperature}'])
112
+ temperature: int
113
+ """The temperature in either celcius or Fahrenheit."""
113
114
 
114
- @property
115
- def precipitation(self) -> float:
116
- """The precipitation in either millimeters or inches."""
115
+ precipitation: float
116
+ """The precipitation in either millimeters or inches."""
117
117
 
118
- return float(self.__inner[f'precip{self._CustomizableBase__unit.precipitation}'])
118
+ pressure: float
119
+ """The pressure in either pascal or inches."""
119
120
 
120
- @property
121
- def pressure(self) -> float:
122
- """The pressure in either pascal or inches."""
121
+ visibility: int
122
+ """The visibility distance in either kilometers or miles."""
123
123
 
124
- return float(self.__inner[f'pressure{self._CustomizableBase__unit.pressure}'])
124
+ wind_speed: int
125
+ """The wind speeds in either kilometers/hour or miles/hour."""
125
126
 
126
- @property
127
- def visibility(self) -> int:
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
- self.__inner['weatherDesc'][0]['value']
152
- if self._CustomizableBase__locale == Locale.ENGLISH
153
- else self.__inner[f'lang_{self._CustomizableBase__locale.value}'][0]['value']
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
- return description.strip()
157
-
158
- @property
159
- def kind(self) -> Kind:
160
- """The kind of the forecast."""
161
-
162
- return Kind(int(self.__inner['weatherCode']))
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, ...] = ('__degrees',)
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.__degrees = degrees
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."""
@@ -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, CustomizableBase
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
- def __init__(self, json: dict, unit: _Unit, locale: Locale):
39
- # for inheritance purposes
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
- return int(
55
- self._BaseForecast__inner[f'DewPoint{self._CustomizableBase__unit.temperature}']
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
- @property
90
- def chances_of_fog(self) -> int:
91
- """Chances of a fog in percent."""
61
+ chances_of_high_temperature: int
62
+ """Chances of a high temperature in percent."""
92
63
 
93
- return int(self._BaseForecast__inner['chanceoffog'])
64
+ chances_of_overcast: int
65
+ """Chances of an overcast in percent."""
94
66
 
95
- @property
96
- def chances_of_frost(self) -> int:
97
- """Chances of a frost in percent."""
67
+ chances_of_rain: int
68
+ """Chances of a rain in percent."""
98
69
 
99
- return int(self._BaseForecast__inner['chanceoffrost'])
70
+ chances_of_remaining_dry: int
71
+ """Chances of remaining dry in percent."""
100
72
 
101
- @property
102
- def chances_of_high_temperature(self) -> int:
103
- """Chances of a high temperature in percent."""
73
+ chances_of_snow: int
74
+ """Chances of a snow in percent."""
104
75
 
105
- return int(self._BaseForecast__inner['chanceofhightemp'])
76
+ chances_of_sunshine: int
77
+ """Chances of a sunshine in percent."""
106
78
 
107
- @property
108
- def chances_of_overcast(self) -> int:
109
- """Chances of an overcast in percent."""
79
+ chances_of_thunder: int
80
+ """Chances of a thunder in percent."""
110
81
 
111
- return int(self._BaseForecast__inner['chanceofovercast'])
82
+ chances_of_windy: int
83
+ """Chances of windy in percent."""
112
84
 
113
- @property
114
- def chances_of_rain(self) -> int:
115
- """Chances of a rain in percent."""
85
+ cloud_cover: int
86
+ """The cloud cover value in percent."""
116
87
 
117
- return int(self._BaseForecast__inner['chanceofrain'])
88
+ time: 'time'
89
+ """The local time in hours and minutes."""
118
90
 
119
- @property
120
- def chances_of_remaining_dry(self) -> int:
121
- """Chances of remaining dry in percent."""
91
+ dew_point: int
92
+ """The dew point in either celcius or fahrenheit."""
122
93
 
123
- return int(self._BaseForecast__inner['chanceofremdry'])
94
+ heat_index: HeatIndex
95
+ """The heat index in either celcius or fahrenheit."""
124
96
 
125
- @property
126
- def chances_of_snow(self) -> int:
127
- """Chances of a snow in percent."""
97
+ wind_chill: int
98
+ """The wind chill value in either celcius or fahrenheit."""
128
99
 
129
- return int(self._BaseForecast__inner['chanceofsnow'])
100
+ wind_gust: int
101
+ """The wind gust value in either kilometers/hour or miles/hour."""
130
102
 
131
- @property
132
- def chances_of_sunshine(self) -> int:
133
- """Chances of a sunshine in percent."""
134
-
135
- return int(self._BaseForecast__inner['chanceofsunshine'])
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
- return (
160
- time()
161
- if len(self._BaseForecast__inner['time']) < 3
162
- else datetime.strptime(self._BaseForecast__inner['time'], '%H%M').time()
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
- class DailyForecast(CustomizableBase):
167
- __slots__: Tuple[str, ...] = ('__inner', '__astronomy')
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
- def __repr__(self) -> str:
176
- return f'<{__class__.__name__} date={self.date!r} temperature={self.temperature!r}>'
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
- def __iter__(self) -> Iterable[HourlyForecast]:
179
- return self.hourly_forecasts
156
+ moon_illumination: int
157
+ """The percentage of the moon illuminated."""
180
158
 
181
- def __list__(self) -> List[HourlyForecast]:
182
- return list(iter(self))
159
+ moon_phase: Phase
160
+ """The moon's phase."""
183
161
 
184
- @property
185
- def moon_illumination(self) -> int:
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
- return int(self.__astronomy['moon_illumination'])
165
+ moonset: Optional[time]
166
+ """The local time when the moon sets. This can be ``None``."""
189
167
 
190
- @property
191
- def moon_phase(self) -> Phase:
192
- """The moon's phase."""
168
+ sunrise: Optional[time]
169
+ """The local time when the sun rises. This can be ``None``."""
193
170
 
194
- return Phase(self.__astronomy['moon_phase'])
171
+ sunset: Optional[time]
172
+ """The local time when the sun sets. This can be ``None``."""
195
173
 
196
- @property
197
- def moonrise(self) -> Optional[time]:
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
- try:
201
- return datetime.strptime(self.__astronomy['moonrise'], '%I:%M %p').time()
202
- except ValueError:
203
- ...
177
+ sunlight: float
178
+ """Hours of sunlight."""
204
179
 
205
- @property
206
- def moonset(self) -> Optional[time]:
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
- try:
210
- return datetime.strptime(self.__astronomy['moonset'], '%I:%M %p').time()
211
- except ValueError:
212
- ...
183
+ highest_temperature: int
184
+ """The highest temperature in either celcius or fahrenheit."""
213
185
 
214
- @property
215
- def sunrise(self) -> Optional[time]:
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
- try:
219
- return datetime.strptime(self.__astronomy['sunrise'], '%I:%M %p').time()
220
- except ValueError:
221
- ...
189
+ snowfall: float
190
+ """Total snowfall in either centimeters or inches."""
222
191
 
223
- @property
224
- def sunset(self) -> Optional[time]:
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(self.__astronomy['sunset'], '%I:%M %p').time()
217
+ return datetime.strptime(timestamp, '%I:%M %p').time()
229
218
  except ValueError:
230
219
  ...
231
220
 
232
- @property
233
- def date(self) -> date:
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
- return datetime.strptime(self.__inner['date'], '%Y-%m-%d').date()
224
+ def __len__(self) -> int:
225
+ return len(self.hourly_forecasts)
237
226
 
238
- @property
239
- def lowest_temperature(self) -> int:
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
- @property
245
- def highest_temperature(self) -> int:
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
- return int(self.__inner[f'maxtemp{self._CustomizableBase__unit.temperature}'])
234
+ __slots__: Tuple[str, ...] = (
235
+ 'local_population',
236
+ 'region',
237
+ 'location',
238
+ 'country',
239
+ 'datetime',
240
+ 'coordinates',
241
+ 'daily_forecasts',
242
+ )
249
243
 
250
- @property
251
- def temperature(self) -> int:
252
- """The average temperature in either celcius or fahrenheit."""
244
+ local_population: int
245
+ """The local population count."""
253
246
 
254
- return int(self.__inner[f'avgtemp{self._CustomizableBase__unit.temperature}'])
247
+ region: str
248
+ """The local region's name."""
255
249
 
256
- @property
257
- def sunlight(self) -> float:
258
- """Hours of sunlight."""
250
+ location: str
251
+ """The location's name."""
259
252
 
260
- return float(self.__inner['sunHour'])
253
+ country: str
254
+ """The local country's name."""
261
255
 
262
- @property
263
- def snowfall(self) -> float:
264
- """Total snowfall in either centimeters or inches."""
256
+ datetime: 'datetime'
257
+ """The local date and time of this weather forecast."""
265
258
 
266
- return float(self.__inner['totalSnow_cm']) / self._CustomizableBase__unit.cm_divisor
259
+ coordinates: Tuple[float, float]
260
+ """A tuple of this forecast's latitude and longitude."""
267
261
 
268
- @property
269
- def hourly_forecasts(self) -> Iterable[HourlyForecast]:
270
- """The hourly forecasts of this day."""
262
+ daily_forecasts: List[DailyForecast]
263
+ """Daily weather forecasts in this location."""
271
264
 
272
- return (
273
- HourlyForecast(elem, self._CustomizableBase__unit, self._CustomizableBase__locale)
274
- for elem in self.__inner['hourly']
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
- class Forecast(BaseForecast):
279
- """Represents today's weather forecast, alongside daily and hourly weather forecasts."""
275
+ try:
276
+ req = next(filter(lambda x: x['type'] == 'LatLon', json['request']))
277
+ match = LATLON_REGEX.match(req['query'])
280
278
 
281
- __slots__: Tuple[str, ...] = ('__inner', '__nearest')
279
+ self.coordinates = (float(match[1]), float(match[2]))
280
+ except:
281
+ self.coordinates = (float(nearest['latitude']), float(nearest['longitude']))
282
282
 
283
- def __init__(self, json: dict, unit: _Unit, locale: Locale):
284
- current = json['current_condition'][0]
285
- self.__nearest = json.pop('nearest_area')[0]
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 __iter__(self) -> Iterable[DailyForecast]:
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
- return datetime.strptime(
328
- self._BaseForecast__inner['localObsDateTime'], '%Y-%m-%d %I:%M %p'
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.4
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.8
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,,