python-weather 2.1.2__tar.gz → 2.2.0__tar.gz
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-2.1.2/python_weather.egg-info → python_weather-2.2.0}/PKG-INFO +3 -3
- {python_weather-2.1.2 → python_weather-2.2.0}/pyproject.toml +3 -3
- {python_weather-2.1.2 → python_weather-2.2.0}/python_weather/base.py +2 -55
- {python_weather-2.1.2 → python_weather-2.2.0}/python_weather/client.py +64 -13
- {python_weather-2.1.2 → python_weather-2.2.0}/python_weather/constants.py +3 -0
- {python_weather-2.1.2 → python_weather-2.2.0}/python_weather/enums.py +24 -8
- {python_weather-2.1.2 → python_weather-2.2.0}/python_weather/errors.py +1 -0
- {python_weather-2.1.2 → python_weather-2.2.0}/python_weather/forecast.py +7 -0
- {python_weather-2.1.2 → python_weather-2.2.0}/python_weather/version.py +1 -1
- {python_weather-2.1.2 → python_weather-2.2.0/python_weather.egg-info}/PKG-INFO +3 -3
- python_weather-2.2.0/python_weather.egg-info/requires.txt +1 -0
- python_weather-2.1.2/python_weather.egg-info/requires.txt +0 -1
- {python_weather-2.1.2 → python_weather-2.2.0}/LICENSE +0 -0
- {python_weather-2.1.2 → python_weather-2.2.0}/MANIFEST.in +0 -0
- {python_weather-2.1.2 → python_weather-2.2.0}/README.md +0 -0
- {python_weather-2.1.2 → python_weather-2.2.0}/python_weather/__init__.py +0 -0
- {python_weather-2.1.2 → python_weather-2.2.0}/python_weather.egg-info/SOURCES.txt +0 -0
- {python_weather-2.1.2 → python_weather-2.2.0}/python_weather.egg-info/dependency_links.txt +0 -0
- {python_weather-2.1.2 → python_weather-2.2.0}/python_weather.egg-info/top_level.txt +0 -0
- {python_weather-2.1.2 → python_weather-2.2.0}/setup.cfg +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-weather
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: A free and asynchronous weather API wrapper made in Python, for Python.
|
|
5
5
|
Author: null8626
|
|
6
|
-
License: MIT
|
|
6
|
+
License-Expression: MIT
|
|
7
7
|
Project-URL: Documentation, https://python-weather.readthedocs.io/en/latest/
|
|
8
8
|
Project-URL: Repository, https://github.com/null8626/python-weather
|
|
9
9
|
Project-URL: Changelog, https://python-weather.readthedocs.io/en/latest/changelog.html
|
|
@@ -33,7 +33,7 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
33
33
|
Requires-Python: >=3.10
|
|
34
34
|
Description-Content-Type: text/markdown
|
|
35
35
|
License-File: LICENSE
|
|
36
|
-
Requires-Dist: aiohttp>=3.13.
|
|
36
|
+
Requires-Dist: aiohttp>=3.13.5
|
|
37
37
|
Dynamic: license-file
|
|
38
38
|
|
|
39
39
|
# [python-weather][pypi-url] [![pypi][pypi-image]][pypi-url] [![pypi downloads][pypi-downloads-image]][pypi-url] [![codacy-badge][codacy-image]][codacy-url] [![codecov-badge][codecov-image]][codecov-url] [![ko-fi][ko-fi-brief-image]][ko-fi-url]
|
|
@@ -3,13 +3,13 @@ requires = ["setuptools"]
|
|
|
3
3
|
|
|
4
4
|
[project]
|
|
5
5
|
name = "python-weather"
|
|
6
|
-
version = "2.
|
|
6
|
+
version = "2.2.0"
|
|
7
7
|
description = "A free and asynchronous weather API wrapper made in Python, for Python."
|
|
8
8
|
readme = "README.md"
|
|
9
|
-
license =
|
|
9
|
+
license = "MIT"
|
|
10
10
|
authors = [{ name = "null8626" }]
|
|
11
11
|
keywords = ["weather", "forecast", "weather-forecast"]
|
|
12
|
-
dependencies = ["aiohttp>=3.13.
|
|
12
|
+
dependencies = ["aiohttp>=3.13.5"]
|
|
13
13
|
classifiers = [
|
|
14
14
|
"Development Status :: 5 - Production/Stable",
|
|
15
15
|
"Intended Audience :: Education",
|
|
@@ -3,64 +3,11 @@
|
|
|
3
3
|
|
|
4
4
|
from .enums import WindDirection, Kind, Locale, UltraViolet
|
|
5
5
|
from .constants import _Unit
|
|
6
|
-
from .errors import Error
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class CustomizableBase:
|
|
10
|
-
__slots__: tuple[str, ...] = '_unit', '_locale'
|
|
11
|
-
|
|
12
|
-
_unit: _Unit
|
|
13
|
-
_locale: Locale
|
|
14
|
-
|
|
15
|
-
def __init__(self, unit: _Unit, locale: Locale):
|
|
16
|
-
self.unit = unit
|
|
17
|
-
self.locale = locale
|
|
18
|
-
|
|
19
|
-
@property
|
|
20
|
-
def unit(self) -> _Unit:
|
|
21
|
-
"""The measuring unit used."""
|
|
22
|
-
|
|
23
|
-
return self._unit
|
|
24
|
-
|
|
25
|
-
@unit.setter
|
|
26
|
-
def unit(self, to: _Unit) -> None:
|
|
27
|
-
"""
|
|
28
|
-
Sets the default measuring unit used.
|
|
29
|
-
|
|
30
|
-
:param to: The new default measuring unit to be used.
|
|
31
|
-
|
|
32
|
-
:exception Error: ``to`` is not either :data:`~.constants.METRIC` or :data:`~.constants.IMPERIAL`.
|
|
33
|
-
"""
|
|
34
|
-
|
|
35
|
-
if not isinstance(to, _Unit):
|
|
36
|
-
raise Error('Invalid measuring unit specified!')
|
|
37
|
-
|
|
38
|
-
self._unit = to
|
|
39
|
-
|
|
40
|
-
@property
|
|
41
|
-
def locale(self) -> Locale:
|
|
42
|
-
"""The localization used."""
|
|
43
|
-
|
|
44
|
-
return self._locale
|
|
45
|
-
|
|
46
|
-
@locale.setter
|
|
47
|
-
def locale(self, to: Locale) -> None:
|
|
48
|
-
"""
|
|
49
|
-
Sets the default localization used.
|
|
50
|
-
|
|
51
|
-
:param to: The new :class:`.Locale` to be used.
|
|
52
|
-
:type to: :class:`.Locale`
|
|
53
|
-
|
|
54
|
-
:exception Error: ``to`` is not a part of the :class:`.Locale` enum.
|
|
55
|
-
"""
|
|
56
|
-
|
|
57
|
-
if not isinstance(to, Locale):
|
|
58
|
-
raise Error(f'Expected {to!r} to be a Locale enum')
|
|
59
|
-
|
|
60
|
-
self._locale = to
|
|
61
6
|
|
|
62
7
|
|
|
63
8
|
class BaseForecast:
|
|
9
|
+
"""A base weather forecast."""
|
|
10
|
+
|
|
64
11
|
__slots__: tuple[str, ...] = (
|
|
65
12
|
'cloud_cover',
|
|
66
13
|
'ultraviolet',
|
|
@@ -7,13 +7,12 @@ from asyncio import sleep
|
|
|
7
7
|
|
|
8
8
|
from .errors import Error, RequestError
|
|
9
9
|
from .constants import _Unit, METRIC
|
|
10
|
-
from .base import CustomizableBase
|
|
11
10
|
from .forecast import Forecast
|
|
12
11
|
from .version import VERSION
|
|
13
12
|
from .enums import Locale
|
|
14
13
|
|
|
15
14
|
|
|
16
|
-
class Client
|
|
15
|
+
class Client:
|
|
17
16
|
"""
|
|
18
17
|
Interact with the API's endpoints.
|
|
19
18
|
|
|
@@ -45,11 +44,19 @@ class Client(CustomizableBase):
|
|
|
45
44
|
:exception Error: ``unit`` is not :data:`~.constants.METRIC` or :data:`~.constants.IMPERIAL` or ``locale`` is not a part of the :class:`.Locale` enum.
|
|
46
45
|
"""
|
|
47
46
|
|
|
48
|
-
__slots__: tuple[str, ...] =
|
|
47
|
+
__slots__: tuple[str, ...] = (
|
|
48
|
+
'__own_session',
|
|
49
|
+
'__session',
|
|
50
|
+
'_max_retries',
|
|
51
|
+
'_unit',
|
|
52
|
+
'_locale',
|
|
53
|
+
)
|
|
49
54
|
|
|
50
55
|
__own_session: bool
|
|
51
56
|
__session: ClientSession
|
|
52
57
|
_max_retries: int
|
|
58
|
+
_unit: _Unit
|
|
59
|
+
_locale: Locale
|
|
53
60
|
|
|
54
61
|
def __init__(
|
|
55
62
|
self,
|
|
@@ -59,18 +66,58 @@ class Client(CustomizableBase):
|
|
|
59
66
|
session: ClientSession | None = None,
|
|
60
67
|
max_retries: int | None = None,
|
|
61
68
|
):
|
|
62
|
-
super().__init__(unit, locale)
|
|
63
|
-
|
|
64
69
|
self.__own_session = session is None
|
|
65
70
|
self.__session = session or ClientSession(
|
|
66
71
|
timeout=ClientTimeout(total=5000.0),
|
|
67
72
|
connector=TCPConnector(ssl=False),
|
|
68
73
|
)
|
|
69
74
|
self._max_retries = max_retries or 3
|
|
75
|
+
self.unit = unit
|
|
76
|
+
self.locale = locale
|
|
70
77
|
|
|
71
78
|
def __repr__(self) -> str:
|
|
79
|
+
"""The client's debug string representation."""
|
|
72
80
|
return f'<{__class__.__module__}.{__class__.__name__} {self.__session!r}>'
|
|
73
81
|
|
|
82
|
+
@property
|
|
83
|
+
def unit(self) -> _Unit:
|
|
84
|
+
"""The measuring unit used."""
|
|
85
|
+
return self._unit
|
|
86
|
+
|
|
87
|
+
@unit.setter
|
|
88
|
+
def unit(self, to: _Unit) -> None:
|
|
89
|
+
"""
|
|
90
|
+
Sets the default measuring unit used.
|
|
91
|
+
|
|
92
|
+
:param to: The new default measuring unit to be used.
|
|
93
|
+
|
|
94
|
+
:exception Error: ``to`` is not either :data:`~.constants.METRIC` or :data:`~.constants.IMPERIAL`.
|
|
95
|
+
"""
|
|
96
|
+
if not isinstance(to, _Unit):
|
|
97
|
+
raise Error('Invalid measuring unit specified!')
|
|
98
|
+
|
|
99
|
+
self._unit = to
|
|
100
|
+
|
|
101
|
+
@property
|
|
102
|
+
def locale(self) -> Locale:
|
|
103
|
+
"""The localization used."""
|
|
104
|
+
return self._locale
|
|
105
|
+
|
|
106
|
+
@locale.setter
|
|
107
|
+
def locale(self, to: Locale) -> None:
|
|
108
|
+
"""
|
|
109
|
+
Sets the default localization used.
|
|
110
|
+
|
|
111
|
+
:param to: The new :class:`.Locale` to be used.
|
|
112
|
+
:type to: :class:`.Locale`
|
|
113
|
+
|
|
114
|
+
:exception Error: ``to`` is not a part of the :class:`.Locale` enum.
|
|
115
|
+
"""
|
|
116
|
+
if not isinstance(to, Locale):
|
|
117
|
+
raise Error(f'Expected {to!r} to be a Locale enum')
|
|
118
|
+
|
|
119
|
+
self._locale = to
|
|
120
|
+
|
|
74
121
|
async def get(
|
|
75
122
|
self,
|
|
76
123
|
location: str,
|
|
@@ -94,19 +141,20 @@ class Client(CustomizableBase):
|
|
|
94
141
|
:param locale: Overrides the locale used.
|
|
95
142
|
:type locale: :class:`.Locale` | :py:obj:`None`
|
|
96
143
|
|
|
97
|
-
:exception TypeError:
|
|
144
|
+
:exception TypeError: The specified location is not a string.
|
|
145
|
+
:exception ValueError: The specified location is empty.
|
|
98
146
|
:exception Error: The client is already closed.
|
|
99
147
|
:exception RequestError: The client received a non-favorable response from the API.
|
|
100
148
|
|
|
101
149
|
:returns: The requested weather forecast.
|
|
102
150
|
:rtype: Forecast
|
|
103
151
|
"""
|
|
104
|
-
|
|
105
152
|
if self.__session.closed:
|
|
106
153
|
raise Error('Client session is already closed.')
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
154
|
+
elif not isinstance(location, str):
|
|
155
|
+
raise TypeError('The specified location must be a string.')
|
|
156
|
+
elif not location:
|
|
157
|
+
raise ValueError('The specified location must not be empty.')
|
|
110
158
|
|
|
111
159
|
if not isinstance(unit, _Unit):
|
|
112
160
|
unit = self._unit
|
|
@@ -134,7 +182,9 @@ class Client(CustomizableBase):
|
|
|
134
182
|
|
|
135
183
|
resp.raise_for_status()
|
|
136
184
|
|
|
137
|
-
return Forecast(
|
|
185
|
+
return Forecast(
|
|
186
|
+
await resp.json(content_type='application/text'), unit, locale
|
|
187
|
+
)
|
|
138
188
|
except ClientResponseError:
|
|
139
189
|
if attempts == self._max_retries:
|
|
140
190
|
raise RequestError(status, reason) from None
|
|
@@ -144,7 +194,7 @@ class Client(CustomizableBase):
|
|
|
144
194
|
|
|
145
195
|
async def close(self) -> None:
|
|
146
196
|
"""
|
|
147
|
-
Closes the
|
|
197
|
+
Closes the client.
|
|
148
198
|
|
|
149
199
|
Example:
|
|
150
200
|
|
|
@@ -152,12 +202,13 @@ class Client(CustomizableBase):
|
|
|
152
202
|
|
|
153
203
|
await client.close()
|
|
154
204
|
"""
|
|
155
|
-
|
|
156
205
|
if self.__own_session and not self.__session.closed:
|
|
157
206
|
await self.__session.close()
|
|
158
207
|
|
|
159
208
|
async def __aenter__(self) -> 'Client':
|
|
209
|
+
"""Starts using the client. This method is no-op and just returns itself."""
|
|
160
210
|
return self
|
|
161
211
|
|
|
162
212
|
async def __aexit__(self, *_, **__) -> None:
|
|
213
|
+
"""Closes the client."""
|
|
163
214
|
await self.close()
|
|
@@ -5,6 +5,8 @@ import re
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class _Unit:
|
|
8
|
+
"""A supported measurement unit."""
|
|
9
|
+
|
|
8
10
|
__slots__: tuple[str, ...] = (
|
|
9
11
|
'temperature',
|
|
10
12
|
'velocity',
|
|
@@ -38,6 +40,7 @@ class _Unit:
|
|
|
38
40
|
self.cm_divisor = cm_divisor
|
|
39
41
|
|
|
40
42
|
def __repr__(self) -> str:
|
|
43
|
+
"""The unit's debug string representation."""
|
|
41
44
|
return f'<Unit [{self.temperature}, {self.velocity}]>'
|
|
42
45
|
|
|
43
46
|
|
|
@@ -7,12 +7,16 @@ from .constants import KIND_EMOJIS, WIND_DIRECTION_EMOJIS
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class BasicEnum(Enum):
|
|
10
|
+
"""An ordinary enum."""
|
|
11
|
+
|
|
10
12
|
__slots__: tuple[str, ...] = ()
|
|
11
13
|
|
|
12
14
|
def __repr__(self) -> str:
|
|
15
|
+
"""The enum's debug string representation."""
|
|
13
16
|
return f'{self.__class__.__name__}.{self.name}'
|
|
14
17
|
|
|
15
18
|
def __str__(self) -> str:
|
|
19
|
+
"""The enum's friendly name."""
|
|
16
20
|
return self.name.replace('_', ' ').title()
|
|
17
21
|
|
|
18
22
|
@property
|
|
@@ -21,36 +25,46 @@ class BasicEnum(Enum):
|
|
|
21
25
|
|
|
22
26
|
|
|
23
27
|
class IndexedEnum(Enum):
|
|
28
|
+
"""An enum that carries an index value."""
|
|
29
|
+
|
|
24
30
|
__slots__: tuple[str, ...] = ('index',)
|
|
25
31
|
|
|
26
32
|
index: int
|
|
27
33
|
"""The index value."""
|
|
28
34
|
|
|
29
35
|
def __lt__(self, other: 'IndexedEnum | float | int') -> bool:
|
|
36
|
+
"""Checks if the enum's index value is less than the other."""
|
|
30
37
|
return float(self.index) < float(other)
|
|
31
38
|
|
|
32
39
|
def __le__(self, other: 'IndexedEnum | float | int') -> bool:
|
|
40
|
+
"""Checks if the enum's index value is less than or equal to the other."""
|
|
33
41
|
return float(self.index) <= float(other)
|
|
34
42
|
|
|
35
43
|
def __eq__(self, other: object) -> bool:
|
|
44
|
+
"""Checks if the enum's index value is equal to the other."""
|
|
36
45
|
if other_float := getattr(other, '__float__', None):
|
|
37
46
|
return float(self.index) == other_float()
|
|
38
47
|
|
|
39
48
|
return False # pragma: nocover
|
|
40
49
|
|
|
41
50
|
def __gt__(self, other: 'IndexedEnum | float | int') -> bool:
|
|
51
|
+
"""Checks if the enum's index value is greater than the other."""
|
|
42
52
|
return float(self.index) > float(other)
|
|
43
53
|
|
|
44
54
|
def __ge__(self, other: 'IndexedEnum | float | int') -> bool:
|
|
55
|
+
"""Checks if the enum's index value is greater than or equal to the other."""
|
|
45
56
|
return float(self.index) >= float(other)
|
|
46
57
|
|
|
47
58
|
def __hash__(self) -> int:
|
|
59
|
+
"""The enum's index value."""
|
|
48
60
|
return self.index
|
|
49
61
|
|
|
50
62
|
def __int__(self) -> int:
|
|
63
|
+
"""The enum's index value."""
|
|
51
64
|
return self.index
|
|
52
65
|
|
|
53
66
|
def __float__(self) -> float:
|
|
67
|
+
"""The floating point representation of the enum's index value."""
|
|
54
68
|
return float(self.index)
|
|
55
69
|
|
|
56
70
|
|
|
@@ -140,7 +154,7 @@ class WindDirection(BasicEnum):
|
|
|
140
154
|
NORTH_NORTHWEST = 'NNW'
|
|
141
155
|
|
|
142
156
|
degrees: float
|
|
143
|
-
"""The wind direction's
|
|
157
|
+
"""The wind direction's angle in degrees."""
|
|
144
158
|
|
|
145
159
|
@staticmethod
|
|
146
160
|
def _new(value: str, degrees: float) -> 'WindDirection':
|
|
@@ -150,25 +164,27 @@ class WindDirection(BasicEnum):
|
|
|
150
164
|
return enum
|
|
151
165
|
|
|
152
166
|
def __contains__(self, other: 'WindDirection | float | int') -> bool:
|
|
167
|
+
"""Checks if the other's angle is within the enum's wind direction."""
|
|
153
168
|
members = list(self.__class__)
|
|
154
169
|
|
|
155
170
|
return self is members[int(((float(other) % 360) + 11.25) // 22.5) % len(members)]
|
|
156
171
|
|
|
157
172
|
def __int__(self) -> int:
|
|
173
|
+
"""The integer representation of the wind direction's angle."""
|
|
158
174
|
return int(self.degrees)
|
|
159
175
|
|
|
160
176
|
def __float__(self) -> float:
|
|
177
|
+
"""The wind direction's angle."""
|
|
161
178
|
return self.degrees
|
|
162
179
|
|
|
163
180
|
@property
|
|
164
181
|
def emoji(self) -> str:
|
|
165
|
-
"""
|
|
166
|
-
|
|
182
|
+
"""The wind direction's emoji representation."""
|
|
167
183
|
return WIND_DIRECTION_EMOJIS[int(((self.degrees + 22.5) % 360) // 45)]
|
|
168
184
|
|
|
169
185
|
|
|
170
186
|
class Locale(Enum):
|
|
171
|
-
"""
|
|
187
|
+
"""A supported locale."""
|
|
172
188
|
|
|
173
189
|
__slots__: tuple[str, ...] = ()
|
|
174
190
|
|
|
@@ -246,9 +262,11 @@ class Locale(Enum):
|
|
|
246
262
|
ZULU = 'zu'
|
|
247
263
|
|
|
248
264
|
def __repr__(self) -> str:
|
|
265
|
+
"""The locale's debug string representation."""
|
|
249
266
|
return f'{__class__.__name__}.{self.name}'
|
|
250
267
|
|
|
251
268
|
def __str__(self) -> str:
|
|
269
|
+
"""The locale's friendly name."""
|
|
252
270
|
arr = self.name.title().split('_')
|
|
253
271
|
|
|
254
272
|
return f'{" ".join(arr[:-1])} ({arr[-1]})' if len(arr) != 1 else arr[0]
|
|
@@ -307,8 +325,7 @@ class Kind(BasicEnum):
|
|
|
307
325
|
|
|
308
326
|
@property
|
|
309
327
|
def emoji(self) -> str:
|
|
310
|
-
"""
|
|
311
|
-
|
|
328
|
+
"""The weather forecast kind's emoji representation."""
|
|
312
329
|
return KIND_EMOJIS[self._index]
|
|
313
330
|
|
|
314
331
|
|
|
@@ -328,6 +345,5 @@ class Phase(BasicEnum):
|
|
|
328
345
|
|
|
329
346
|
@property
|
|
330
347
|
def emoji(self) -> str:
|
|
331
|
-
"""
|
|
332
|
-
|
|
348
|
+
"""The moon phase's emoji representation."""
|
|
333
349
|
return chr(0x1F311 + self._index)
|
|
@@ -26,4 +26,5 @@ class RequestError(Error):
|
|
|
26
26
|
super().__init__(f'{status}: {reason}')
|
|
27
27
|
|
|
28
28
|
def __repr__(self) -> str: # pragma: nocover
|
|
29
|
+
"""The error's debug string representation."""
|
|
29
30
|
return f'<{__class__.__module__}.{__class__.__name__} status={self.status} reason={self.reason!r}>'
|
|
@@ -113,6 +113,7 @@ class HourlyForecast(BaseForecast):
|
|
|
113
113
|
super().__init__(json, unit, locale)
|
|
114
114
|
|
|
115
115
|
def __repr__(self) -> str:
|
|
116
|
+
"""The forecast's debug string representation."""
|
|
116
117
|
return f'<{__class__.__module__}.{__class__.__name__} time={self.time!r} temperature={self.temperature} kind={self.kind!r}>'
|
|
117
118
|
|
|
118
119
|
|
|
@@ -201,12 +202,15 @@ class DailyForecast:
|
|
|
201
202
|
...
|
|
202
203
|
|
|
203
204
|
def __repr__(self) -> str:
|
|
205
|
+
"""The forecast's debug string representation."""
|
|
204
206
|
return f'<{__class__.__module__}.{__class__.__name__} date={self.date!r} temperature={self.temperature}>'
|
|
205
207
|
|
|
206
208
|
def __len__(self) -> int:
|
|
209
|
+
"""The amount of hourly forecasts."""
|
|
207
210
|
return len(self.hourly_forecasts)
|
|
208
211
|
|
|
209
212
|
def __iter__(self) -> Iterator[HourlyForecast]:
|
|
213
|
+
"""Iterates through the hourly forecasts."""
|
|
210
214
|
return iter(self.hourly_forecasts)
|
|
211
215
|
|
|
212
216
|
|
|
@@ -272,10 +276,13 @@ class Forecast(BaseForecast):
|
|
|
272
276
|
super().__init__(current, unit, locale)
|
|
273
277
|
|
|
274
278
|
def __repr__(self) -> str:
|
|
279
|
+
"""The forecast's debug string representation."""
|
|
275
280
|
return f'<{__class__.__module__}.{__class__.__name__} location={self.location!r} datetime={self.datetime!r} temperature={self.temperature}>'
|
|
276
281
|
|
|
277
282
|
def __len__(self) -> int:
|
|
283
|
+
"""The amount of daily forecasts."""
|
|
278
284
|
return len(self.daily_forecasts)
|
|
279
285
|
|
|
280
286
|
def __iter__(self) -> Iterator[DailyForecast]:
|
|
287
|
+
"""Iterates through the daily forecasts."""
|
|
281
288
|
return iter(self.daily_forecasts)
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-weather
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: A free and asynchronous weather API wrapper made in Python, for Python.
|
|
5
5
|
Author: null8626
|
|
6
|
-
License: MIT
|
|
6
|
+
License-Expression: MIT
|
|
7
7
|
Project-URL: Documentation, https://python-weather.readthedocs.io/en/latest/
|
|
8
8
|
Project-URL: Repository, https://github.com/null8626/python-weather
|
|
9
9
|
Project-URL: Changelog, https://python-weather.readthedocs.io/en/latest/changelog.html
|
|
@@ -33,7 +33,7 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
33
33
|
Requires-Python: >=3.10
|
|
34
34
|
Description-Content-Type: text/markdown
|
|
35
35
|
License-File: LICENSE
|
|
36
|
-
Requires-Dist: aiohttp>=3.13.
|
|
36
|
+
Requires-Dist: aiohttp>=3.13.5
|
|
37
37
|
Dynamic: license-file
|
|
38
38
|
|
|
39
39
|
# [python-weather][pypi-url] [![pypi][pypi-image]][pypi-url] [![pypi downloads][pypi-downloads-image]][pypi-url] [![codacy-badge][codacy-image]][codacy-url] [![codecov-badge][codecov-image]][codecov-url] [![ko-fi][ko-fi-brief-image]][ko-fi-url]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
aiohttp>=3.13.5
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
aiohttp>=3.13.3
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|