python-weather 1.1.1__tar.gz → 2.0.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-1.1.1 → python-weather-2.0.0}/MANIFEST.in +4 -1
- {python-weather-1.1.1/python_weather.egg-info → python-weather-2.0.0}/PKG-INFO +12 -15
- {python-weather-1.1.1 → python-weather-2.0.0}/README.md +7 -11
- {python-weather-1.1.1 → python-weather-2.0.0}/pyproject.toml +5 -4
- python-weather-2.0.0/python_weather/__init__.py +14 -0
- python-weather-2.0.0/python_weather/base.py +140 -0
- python-weather-2.0.0/python_weather/client.py +109 -0
- python-weather-2.0.0/python_weather/constants.py +34 -0
- {python-weather-1.1.1 → python-weather-2.0.0}/python_weather/enums.py +78 -166
- python-weather-2.0.0/python_weather/errors.py +4 -0
- python-weather-2.0.0/python_weather/forecast.py +315 -0
- {python-weather-1.1.1 → python-weather-2.0.0/python_weather.egg-info}/PKG-INFO +12 -15
- python-weather-1.1.1/python_weather/__init__.py +0 -37
- python-weather-1.1.1/python_weather/base.py +0 -178
- python-weather-1.1.1/python_weather/client.py +0 -163
- python-weather-1.1.1/python_weather/constants.py +0 -57
- python-weather-1.1.1/python_weather/errors.py +0 -28
- python-weather-1.1.1/python_weather/forecast.py +0 -419
- {python-weather-1.1.1 → python-weather-2.0.0}/LICENSE +0 -0
- {python-weather-1.1.1 → python-weather-2.0.0}/python_weather.egg-info/SOURCES.txt +0 -0
- {python-weather-1.1.1 → python-weather-2.0.0}/python_weather.egg-info/dependency_links.txt +0 -0
- {python-weather-1.1.1 → python-weather-2.0.0}/python_weather.egg-info/requires.txt +0 -0
- {python-weather-1.1.1 → python-weather-2.0.0}/python_weather.egg-info/top_level.txt +0 -0
- {python-weather-1.1.1 → python-weather-2.0.0}/setup.cfg +0 -0
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python-weather
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.0
|
|
4
4
|
Summary: A free and asynchronous weather API wrapper made in Python, for Python.
|
|
5
5
|
Author: null8626
|
|
6
6
|
License: MIT
|
|
7
|
-
Project-URL:
|
|
8
|
-
Project-URL:
|
|
7
|
+
Project-URL: Changelog, https://python-weather.readthedocs.io/en/latest/changelog.html
|
|
8
|
+
Project-URL: Homepage, https://python-weather.readthedocs.io/en/latest/
|
|
9
|
+
Project-URL: Documentation, https://python-weather.readthedocs.io/en/latest/
|
|
10
|
+
Project-URL: Repository, https://github.com/null8626/python-weather
|
|
9
11
|
Keywords: weather,forecast,weather-api,weather-forecast
|
|
10
12
|
Classifier: Development Status :: 5 - Production/Stable
|
|
11
13
|
Classifier: Framework :: aiohttp
|
|
@@ -23,7 +25,6 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
23
25
|
Classifier: Programming Language :: Python
|
|
24
26
|
Classifier: Programming Language :: Python :: 3
|
|
25
27
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
26
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
27
28
|
Classifier: Programming Language :: Python :: 3.8
|
|
28
29
|
Classifier: Programming Language :: Python :: 3.9
|
|
29
30
|
Classifier: Programming Language :: Python :: 3.10
|
|
@@ -34,17 +35,11 @@ Description-Content-Type: text/markdown
|
|
|
34
35
|
License-File: LICENSE
|
|
35
36
|
Requires-Dist: aiohttp==3.9.3
|
|
36
37
|
|
|
37
|
-
# [python-weather][pypi-url] [![pypi][pypi-image]][pypi-url] [![downloads][downloads-image]][pypi-url]
|
|
38
|
+
# [python-weather][pypi-url] [![pypi][pypi-image]][pypi-url] [![downloads][downloads-image]][pypi-url]
|
|
38
39
|
|
|
39
40
|
[pypi-image]: https://img.shields.io/pypi/v/python-weather.svg?style=flat-square
|
|
40
41
|
[pypi-url]: https://pypi.org/project/python-weather/
|
|
41
42
|
[downloads-image]: https://img.shields.io/pypi/dm/python-weather?style=flat-square
|
|
42
|
-
[ci-image]: https://github.com/null8626/python-weather/workflows/CI/badge.svg
|
|
43
|
-
[ci-url]: https://github.com/null8626/python-weather/actions/workflows/CI.yml
|
|
44
|
-
[github-license-image]: https://img.shields.io/github/license/null8626/python-weather?style=flat-square
|
|
45
|
-
[github-license-url]: https://github.com/null8626/python-weather/blob/main/LICENSE
|
|
46
|
-
[blazingly-fast-image]: https://img.shields.io/badge/speed-BLAZINGLY%20FAST!!!%20%F0%9F%94%A5%F0%9F%9A%80%F0%9F%92%AA%F0%9F%98%8E-brightgreen.svg?style=flat-square
|
|
47
|
-
[blazingly-fast-url]: https://twitter.com/acdlite/status/974390255393505280
|
|
48
43
|
|
|
49
44
|
A free and asynchronous weather Python API wrapper made in Python, for Python.
|
|
50
45
|
|
|
@@ -56,6 +51,8 @@ $ pip install python-weather
|
|
|
56
51
|
|
|
57
52
|
## Example
|
|
58
53
|
|
|
54
|
+
For more information, please read the [documentation](https://python-weather.readthedocs.io/en/latest/).
|
|
55
|
+
|
|
59
56
|
```py
|
|
60
57
|
# import the module
|
|
61
58
|
import python_weather
|
|
@@ -70,14 +67,14 @@ async def getweather():
|
|
|
70
67
|
weather = await client.get('New York')
|
|
71
68
|
|
|
72
69
|
# returns the current day's forecast temperature (int)
|
|
73
|
-
print(weather.
|
|
70
|
+
print(weather.temperature)
|
|
74
71
|
|
|
75
72
|
# get the weather forecast for a few days
|
|
76
|
-
for
|
|
77
|
-
print(
|
|
73
|
+
for daily in weather.daily_forecasts:
|
|
74
|
+
print(daily)
|
|
78
75
|
|
|
79
76
|
# hourly forecasts
|
|
80
|
-
for hourly in
|
|
77
|
+
for hourly in daily.hourly_forecasts:
|
|
81
78
|
print(f' --> {hourly!r}')
|
|
82
79
|
|
|
83
80
|
if __name__ == '__main__':
|
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
# [python-weather][pypi-url] [![pypi][pypi-image]][pypi-url] [![downloads][downloads-image]][pypi-url]
|
|
1
|
+
# [python-weather][pypi-url] [![pypi][pypi-image]][pypi-url] [![downloads][downloads-image]][pypi-url]
|
|
2
2
|
|
|
3
3
|
[pypi-image]: https://img.shields.io/pypi/v/python-weather.svg?style=flat-square
|
|
4
4
|
[pypi-url]: https://pypi.org/project/python-weather/
|
|
5
5
|
[downloads-image]: https://img.shields.io/pypi/dm/python-weather?style=flat-square
|
|
6
|
-
[ci-image]: https://github.com/null8626/python-weather/workflows/CI/badge.svg
|
|
7
|
-
[ci-url]: https://github.com/null8626/python-weather/actions/workflows/CI.yml
|
|
8
|
-
[github-license-image]: https://img.shields.io/github/license/null8626/python-weather?style=flat-square
|
|
9
|
-
[github-license-url]: https://github.com/null8626/python-weather/blob/main/LICENSE
|
|
10
|
-
[blazingly-fast-image]: https://img.shields.io/badge/speed-BLAZINGLY%20FAST!!!%20%F0%9F%94%A5%F0%9F%9A%80%F0%9F%92%AA%F0%9F%98%8E-brightgreen.svg?style=flat-square
|
|
11
|
-
[blazingly-fast-url]: https://twitter.com/acdlite/status/974390255393505280
|
|
12
6
|
|
|
13
7
|
A free and asynchronous weather Python API wrapper made in Python, for Python.
|
|
14
8
|
|
|
@@ -20,6 +14,8 @@ $ pip install python-weather
|
|
|
20
14
|
|
|
21
15
|
## Example
|
|
22
16
|
|
|
17
|
+
For more information, please read the [documentation](https://python-weather.readthedocs.io/en/latest/).
|
|
18
|
+
|
|
23
19
|
```py
|
|
24
20
|
# import the module
|
|
25
21
|
import python_weather
|
|
@@ -34,14 +30,14 @@ async def getweather():
|
|
|
34
30
|
weather = await client.get('New York')
|
|
35
31
|
|
|
36
32
|
# returns the current day's forecast temperature (int)
|
|
37
|
-
print(weather.
|
|
33
|
+
print(weather.temperature)
|
|
38
34
|
|
|
39
35
|
# get the weather forecast for a few days
|
|
40
|
-
for
|
|
41
|
-
print(
|
|
36
|
+
for daily in weather.daily_forecasts:
|
|
37
|
+
print(daily)
|
|
42
38
|
|
|
43
39
|
# hourly forecasts
|
|
44
|
-
for hourly in
|
|
40
|
+
for hourly in daily.hourly_forecasts:
|
|
45
41
|
print(f' --> {hourly!r}')
|
|
46
42
|
|
|
47
43
|
if __name__ == '__main__':
|
|
@@ -3,7 +3,7 @@ requires = ["setuptools"]
|
|
|
3
3
|
|
|
4
4
|
[project]
|
|
5
5
|
name = "python-weather"
|
|
6
|
-
version = "
|
|
6
|
+
version = "2.0.0"
|
|
7
7
|
description = "A free and asynchronous weather API wrapper made in Python, for Python."
|
|
8
8
|
readme = "README.md"
|
|
9
9
|
license = { text = "MIT" }
|
|
@@ -27,7 +27,6 @@ classifiers = [
|
|
|
27
27
|
"Programming Language :: Python",
|
|
28
28
|
"Programming Language :: Python :: 3",
|
|
29
29
|
"Programming Language :: Python :: 3 :: Only",
|
|
30
|
-
"Programming Language :: Python :: 3.7",
|
|
31
30
|
"Programming Language :: Python :: 3.8",
|
|
32
31
|
"Programming Language :: Python :: 3.9",
|
|
33
32
|
"Programming Language :: Python :: 3.10",
|
|
@@ -37,5 +36,7 @@ classifiers = [
|
|
|
37
36
|
requires-python = ">=3.8"
|
|
38
37
|
|
|
39
38
|
[project.urls]
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
Changelog = "https://python-weather.readthedocs.io/en/latest/changelog.html"
|
|
40
|
+
Homepage = "https://python-weather.readthedocs.io/en/latest/"
|
|
41
|
+
Documentation = "https://python-weather.readthedocs.io/en/latest/"
|
|
42
|
+
Repository = "https://github.com/null8626/python-weather"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""
|
|
2
|
+
python-weather
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from .enums import HeatIndex, Kind, Locale, Phase, UltraViolet, WindDirection
|
|
6
|
+
from .constants import METRIC, IMPERIAL
|
|
7
|
+
from .client import Client
|
|
8
|
+
from .errors import Error
|
|
9
|
+
|
|
10
|
+
__version__ = '2.0.0'
|
|
11
|
+
__all__ = (
|
|
12
|
+
'METRIC', 'IMPERIAL', 'Client', 'Error', 'HeatIndex', 'Kind', 'Locale',
|
|
13
|
+
'Phase', 'UltraViolet', 'WindDirection'
|
|
14
|
+
)
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
from enum import auto, Enum
|
|
2
|
+
|
|
3
|
+
from .enums import WindDirection, Kind, Locale, UltraViolet
|
|
4
|
+
from .constants import _Unit
|
|
5
|
+
|
|
6
|
+
class CustomizableBase:
|
|
7
|
+
__slots__ = ('__unit', '__locale')
|
|
8
|
+
|
|
9
|
+
def __init__(self, unit: _Unit, locale: Locale):
|
|
10
|
+
self.unit = unit
|
|
11
|
+
self.locale = locale
|
|
12
|
+
|
|
13
|
+
@property
|
|
14
|
+
def unit(self) -> auto:
|
|
15
|
+
"""The measuring unit used to display information in this object."""
|
|
16
|
+
|
|
17
|
+
return self.__unit
|
|
18
|
+
|
|
19
|
+
@unit.setter
|
|
20
|
+
def unit(self, to: _Unit):
|
|
21
|
+
"""
|
|
22
|
+
Sets the default measuring unit used to display information in this object.
|
|
23
|
+
|
|
24
|
+
:param to: The new default measuring unit to be used to display information in this object. Must be either ``METRIC`` or ``IMPERIAL``.
|
|
25
|
+
:exception Error: If the ``to`` argument is not either ``METRIC`` or ``IMPERIAL``.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
if not isinstance(to, _Unit):
|
|
29
|
+
raise Error('Invalid measuring unit specified!')
|
|
30
|
+
|
|
31
|
+
self.__unit = to
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def locale(self) -> Locale:
|
|
35
|
+
"""The localization used to display information in this object."""
|
|
36
|
+
|
|
37
|
+
return self.__locale
|
|
38
|
+
|
|
39
|
+
@locale.setter
|
|
40
|
+
def locale(self, to: Locale):
|
|
41
|
+
"""
|
|
42
|
+
Sets the default localization used to display information in this object.
|
|
43
|
+
|
|
44
|
+
:param to: The new :class:`Locale` to be used to display information in this object.
|
|
45
|
+
:type to: Locale
|
|
46
|
+
:exception Error: If the ``to`` argument is not a part of the :class:`Locale` enum.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
if not isinstance(to, Locale):
|
|
50
|
+
raise Error(f'Expected {to!r} to be a Locale enum')
|
|
51
|
+
|
|
52
|
+
self.__locale = to
|
|
53
|
+
|
|
54
|
+
class BaseForecast(CustomizableBase):
|
|
55
|
+
__slots__ = ('__inner',)
|
|
56
|
+
|
|
57
|
+
def __init__(self, json: dict, unit: _Unit, locale: Locale):
|
|
58
|
+
self.__inner = json
|
|
59
|
+
|
|
60
|
+
super().__init__(unit, locale)
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def ultraviolet(self) -> UltraViolet:
|
|
64
|
+
"""The ultra-violet (UV) index."""
|
|
65
|
+
|
|
66
|
+
return UltraViolet._new(int(self.__inner['uvIndex']))
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def feels_like(self) -> int:
|
|
70
|
+
"""What it felt like, in Celcius or Fahrenheit."""
|
|
71
|
+
|
|
72
|
+
return int(
|
|
73
|
+
self.__inner[f'FeelsLike{self._CustomizableBase__unit.temperature}']
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def humidity(self) -> int:
|
|
78
|
+
"""The humidity value in percent."""
|
|
79
|
+
|
|
80
|
+
return int(self.__inner['humidity'])
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def temperature(self) -> int:
|
|
84
|
+
"""The temperature in either Celcius or Fahrenheit."""
|
|
85
|
+
|
|
86
|
+
return int(self.__inner[f'temp_{self._CustomizableBase__unit.temperature}'])
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def precipitation(self) -> float:
|
|
90
|
+
"""The precipitation in either Millimeters or Inches."""
|
|
91
|
+
|
|
92
|
+
return float(
|
|
93
|
+
self.__inner[f'precip{self._CustomizableBase__unit.precipitation}']
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def pressure(self) -> float:
|
|
98
|
+
"""The pressure in either Pascal or Inches."""
|
|
99
|
+
|
|
100
|
+
return float(
|
|
101
|
+
self.__inner[f'pressure{self._CustomizableBase__unit.pressure}']
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
@property
|
|
105
|
+
def visibility(self) -> int:
|
|
106
|
+
"""The visibility distance in either Kilometers or Miles."""
|
|
107
|
+
|
|
108
|
+
return int(
|
|
109
|
+
self.__inner[f'visibility{self._CustomizableBase__unit.visibility}']
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
@property
|
|
113
|
+
def wind_speed(self) -> int:
|
|
114
|
+
"""The wind speeds in either Kilometers per hour or Miles per hour."""
|
|
115
|
+
|
|
116
|
+
return int(
|
|
117
|
+
self.__inner[f'windspeed{self._CustomizableBase__unit.velocity}']
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
@property
|
|
121
|
+
def wind_direction(self) -> WindDirection:
|
|
122
|
+
"""The wind direction."""
|
|
123
|
+
|
|
124
|
+
return WindDirection._new(
|
|
125
|
+
self.__inner['winddir16Point'], int(self.__inner['winddirDegree'])
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
@property
|
|
129
|
+
def description(self) -> str:
|
|
130
|
+
"""The description regarding the forecast. This can be localized in different languages depending on the localization used."""
|
|
131
|
+
|
|
132
|
+
description = self.__inner['weatherDesc'][0]['value'] if self._CustomizableBase__locale == Locale.ENGLISH else self.__inner[f'lang_{self._CustomizableBase__locale.value}'][0]['value'] # yapf: disable
|
|
133
|
+
|
|
134
|
+
return description.strip()
|
|
135
|
+
|
|
136
|
+
@property
|
|
137
|
+
def kind(self) -> Kind:
|
|
138
|
+
"""The kind of the forecast."""
|
|
139
|
+
|
|
140
|
+
return Kind(int(self.__inner['weatherCode']))
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
from aiohttp import ClientSession, ClientTimeout, TCPConnector
|
|
2
|
+
from urllib.parse import quote_plus
|
|
3
|
+
from typing import Optional
|
|
4
|
+
from asyncio import sleep
|
|
5
|
+
from enum import auto
|
|
6
|
+
|
|
7
|
+
from .constants import _Unit, METRIC
|
|
8
|
+
from .base import CustomizableBase
|
|
9
|
+
from .forecast import Forecast
|
|
10
|
+
from .errors import Error
|
|
11
|
+
from .enums import Locale
|
|
12
|
+
|
|
13
|
+
class Client(CustomizableBase):
|
|
14
|
+
"""
|
|
15
|
+
The class that lets you interact with the API.
|
|
16
|
+
|
|
17
|
+
:param unit: Whether to use the metric or imperial/customary system (``IMPERIAL``). Defaults to ``METRIC``.
|
|
18
|
+
:type unit: Optional[:py:class:`enum.auto`]
|
|
19
|
+
:param locale: Whether to use a different locale/language as the description for the returned forecast. Defaults to ``Locale.ENGLISH``.
|
|
20
|
+
:type locale: Optional[Locale]
|
|
21
|
+
:param session: Whether to use an existing aiohttp client session for requesting or not. Defaults to ``None`` (creates a new one instead)
|
|
22
|
+
:type session: Optional[:class:`aiohttp.ClientSession`]
|
|
23
|
+
|
|
24
|
+
:raises Error: If the ``unit`` argument is not ``None`` and it's also not ``METRIC`` or ``IMPERIAL``, or if the ``locale`` argument is not ``None`` and it's also not a part of the :class:`Locale` enum.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
__slots__ = ('__session',)
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
*,
|
|
32
|
+
unit: Optional[auto] = METRIC,
|
|
33
|
+
locale: Optional[Locale] = Locale.ENGLISH,
|
|
34
|
+
session: Optional[ClientSession] = None
|
|
35
|
+
):
|
|
36
|
+
super().__init__(unit, locale)
|
|
37
|
+
|
|
38
|
+
self.__session = session or ClientSession(
|
|
39
|
+
timeout=ClientTimeout(total=5000.0),
|
|
40
|
+
connector=TCPConnector(verify_ssl=False)
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
def __repr__(self) -> str:
|
|
44
|
+
return f'<{self.__class__.__name__} {self.__session!r}>'
|
|
45
|
+
|
|
46
|
+
async def get(
|
|
47
|
+
self,
|
|
48
|
+
location: str,
|
|
49
|
+
*,
|
|
50
|
+
unit: Optional[auto] = None,
|
|
51
|
+
locale: Optional[Locale] = None
|
|
52
|
+
) -> Forecast:
|
|
53
|
+
"""
|
|
54
|
+
Fetches a weather forecast for a specific location.
|
|
55
|
+
|
|
56
|
+
:param location: The requested location name for said weather forecast.
|
|
57
|
+
:type location: str
|
|
58
|
+
:param unit: Overrides the metric or imperial/customary system (``IMPERIAL``) used by the :class:`Client` object. Defaults to ``None`` (uses the one from the :class:`Client`).
|
|
59
|
+
:type unit: Optional[:py:class:`enum.auto`]
|
|
60
|
+
:param locale: Overrides the locale/language used by the :class:`Client` object. Defaults to ``None`` (uses the one from the :class:`Client`).
|
|
61
|
+
:type locale: Optional[Locale]
|
|
62
|
+
|
|
63
|
+
:exception Error: If the aiohttp client session used by the :class:`Client` object is already closed, if the ``unit`` argument is not ``None`` and it's also not ``METRIC`` or ``IMPERIAL``, if the ``locale`` argument is not ``None`` and it's also not a part of the :class:`Locale` enum, or if the :class:`Client` cannot send a web request to the web server.
|
|
64
|
+
|
|
65
|
+
:returns: The requested weather forecast.
|
|
66
|
+
:rtype: Forecast
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
if (not isinstance(location, str)) or (not location):
|
|
70
|
+
raise Error(f'Expected a proper location str, got {location!r}')
|
|
71
|
+
elif self.__session.closed:
|
|
72
|
+
raise Error('Client is already closed')
|
|
73
|
+
|
|
74
|
+
if not isinstance(unit, _Unit):
|
|
75
|
+
unit = self._CustomizableBase__unit
|
|
76
|
+
|
|
77
|
+
if not isinstance(locale, Locale):
|
|
78
|
+
locale = self._CustomizableBase__locale
|
|
79
|
+
|
|
80
|
+
subdomain = f'{locale.value}.' if locale != Locale.ENGLISH else ''
|
|
81
|
+
delay = 0
|
|
82
|
+
|
|
83
|
+
while True:
|
|
84
|
+
if delay != 0:
|
|
85
|
+
await sleep(delay)
|
|
86
|
+
delay *= 2
|
|
87
|
+
|
|
88
|
+
async with self.__session.get(
|
|
89
|
+
f'https://{subdomain}wttr.in/{quote_plus(location)}?format=j1'
|
|
90
|
+
) as resp:
|
|
91
|
+
try:
|
|
92
|
+
return Forecast(await resp.json(), unit, locale)
|
|
93
|
+
except Exception as e:
|
|
94
|
+
if delay == 4:
|
|
95
|
+
raise e # okay, that's too much requests - just raise the error
|
|
96
|
+
elif delay == 0:
|
|
97
|
+
delay = 0.5
|
|
98
|
+
|
|
99
|
+
async def close(self):
|
|
100
|
+
"""Closes the :class:`Client` object. Nothing will happen if it's already closed."""
|
|
101
|
+
|
|
102
|
+
if not self.__session.closed:
|
|
103
|
+
await self.__session.close()
|
|
104
|
+
|
|
105
|
+
async def __aenter__(self):
|
|
106
|
+
return self
|
|
107
|
+
|
|
108
|
+
async def __aexit__(self, *_, **__):
|
|
109
|
+
await self.close()
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from typing import Union
|
|
2
|
+
from re import compile
|
|
3
|
+
from enum import auto
|
|
4
|
+
|
|
5
|
+
class _Unit:
|
|
6
|
+
__slots__ = (
|
|
7
|
+
'temperature', 'velocity', 'pressure', 'precipitation', 'visibility',
|
|
8
|
+
'cm_divisor'
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
temperature: str,
|
|
14
|
+
velocity: str,
|
|
15
|
+
pressure: str,
|
|
16
|
+
precipitation: str,
|
|
17
|
+
visibility: str,
|
|
18
|
+
cm_divisor: Union[int, float],
|
|
19
|
+
):
|
|
20
|
+
self.temperature = temperature
|
|
21
|
+
self.velocity = velocity
|
|
22
|
+
self.pressure = pressure
|
|
23
|
+
self.precipitation = precipitation
|
|
24
|
+
self.visibility = visibility
|
|
25
|
+
self.cm_divisor = cm_divisor
|
|
26
|
+
|
|
27
|
+
def __repr__(self) -> str:
|
|
28
|
+
return f'<Unit [{self.temperature}, {self.velocity}]>'
|
|
29
|
+
|
|
30
|
+
METRIC = _Unit('C', 'Kmph', '', 'MM', '', 1)
|
|
31
|
+
IMPERIAL = _Unit('F', 'Miles', 'Inches', 'Inches', 'Miles', 2.54)
|
|
32
|
+
|
|
33
|
+
WIND_DIRECTION_EMOJIS = ['↓', '↙', '←', '↖', '↑', '↗', '→', '↘']
|
|
34
|
+
LATLON_REGEX = compile(r'^Lat (\-?[\d\.]+) and Lon (\-?[\d\.]+)$')
|