meteo-lt-pkg 0.5.2__py3-none-any.whl → 0.6.0__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.
- meteo_lt/api.py +1 -1
- meteo_lt/models.py +2 -1
- meteo_lt/warnings.py +26 -33
- {meteo_lt_pkg-0.5.2.dist-info → meteo_lt_pkg-0.6.0.dist-info}/METADATA +26 -3
- meteo_lt_pkg-0.6.0.dist-info/RECORD +12 -0
- meteo_lt_pkg-0.5.2.dist-info/RECORD +0 -12
- {meteo_lt_pkg-0.5.2.dist-info → meteo_lt_pkg-0.6.0.dist-info}/WHEEL +0 -0
- {meteo_lt_pkg-0.5.2.dist-info → meteo_lt_pkg-0.6.0.dist-info}/licenses/LICENSE +0 -0
- {meteo_lt_pkg-0.5.2.dist-info → meteo_lt_pkg-0.6.0.dist-info}/top_level.txt +0 -0
meteo_lt/api.py
CHANGED
|
@@ -67,7 +67,7 @@ class MeteoLtAPI:
|
|
|
67
67
|
|
|
68
68
|
return await self.get_forecast(place_code, include_warnings=True)
|
|
69
69
|
|
|
70
|
-
async def get_forecast(self, place_code: str, include_warnings: bool =
|
|
70
|
+
async def get_forecast(self, place_code: str, include_warnings: bool = True) -> Forecast:
|
|
71
71
|
"""Retrieves forecast data from API"""
|
|
72
72
|
forecast = await self.client.fetch_forecast(place_code)
|
|
73
73
|
|
meteo_lt/models.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass, field, fields
|
|
4
4
|
from datetime import datetime, timezone
|
|
5
|
-
from typing import
|
|
5
|
+
from typing import Any, Dict, List, Optional, Type
|
|
6
6
|
|
|
7
7
|
from .const import COUNTY_MUNICIPALITIES
|
|
8
8
|
|
|
@@ -60,6 +60,7 @@ class MeteoWarning:
|
|
|
60
60
|
category: str = "weather" # "weather" or "hydro"
|
|
61
61
|
start_time: Optional[str] = None
|
|
62
62
|
end_time: Optional[str] = None
|
|
63
|
+
instruction: Optional[str] = None
|
|
63
64
|
|
|
64
65
|
|
|
65
66
|
@dataclass
|
meteo_lt/warnings.py
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"""Unified warnings processor for handling weather and hydrological warning-related logic"""
|
|
2
2
|
|
|
3
3
|
import re
|
|
4
|
-
from datetime import datetime, timezone
|
|
5
|
-
from typing import
|
|
4
|
+
from datetime import datetime, timedelta, timezone
|
|
5
|
+
from typing import Any, Dict, List, Literal, Optional
|
|
6
6
|
|
|
7
|
-
from .models import Forecast, MeteoWarning
|
|
8
|
-
from .const import COUNTY_MUNICIPALITIES, WARNINGS_URL, HYDRO_WARNINGS_URL
|
|
9
7
|
from .client import MeteoLtClient
|
|
8
|
+
from .const import COUNTY_MUNICIPALITIES, HYDRO_WARNINGS_URL, WARNINGS_URL
|
|
9
|
+
from .models import Forecast, MeteoWarning
|
|
10
10
|
|
|
11
11
|
WarningCategory = Literal["weather", "hydro"]
|
|
12
12
|
|
|
@@ -77,20 +77,17 @@ class WarningsProcessor:
|
|
|
77
77
|
inst_dict = alert.get("instruction", {})
|
|
78
78
|
|
|
79
79
|
description = desc_dict.get("en") or desc_dict.get("lt", "")
|
|
80
|
-
instruction = inst_dict.get("en") or inst_dict.get("lt", "")
|
|
81
|
-
|
|
82
|
-
full_description = description
|
|
83
|
-
if instruction:
|
|
84
|
-
full_description += f"\n\nRecommendations: {instruction}"
|
|
80
|
+
instruction = inst_dict.get("en") or inst_dict.get("lt", "") or None
|
|
85
81
|
|
|
86
82
|
return MeteoWarning(
|
|
87
83
|
county=county,
|
|
88
84
|
warning_type=warning_type,
|
|
89
85
|
severity=severity,
|
|
90
|
-
description=
|
|
86
|
+
description=description,
|
|
91
87
|
category=self.category,
|
|
92
88
|
start_time=alert.get("t_from"),
|
|
93
89
|
end_time=alert.get("t_to"),
|
|
90
|
+
instruction=instruction,
|
|
94
91
|
)
|
|
95
92
|
|
|
96
93
|
def _warning_affects_area(self, warning: MeteoWarning, administrative_division: str) -> bool:
|
|
@@ -112,10 +109,7 @@ class WarningsProcessor:
|
|
|
112
109
|
return False
|
|
113
110
|
|
|
114
111
|
def enrich_forecast_with_warnings(self, forecast: Forecast, warnings: List[MeteoWarning]) -> None:
|
|
115
|
-
"""Enrich forecast timestamps with relevant warnings
|
|
116
|
-
|
|
117
|
-
All warnings (weather and hydro) are added to 'warnings' attribute
|
|
118
|
-
"""
|
|
112
|
+
"""Enrich forecast timestamps with relevant warnings"""
|
|
119
113
|
if not warnings:
|
|
120
114
|
return
|
|
121
115
|
|
|
@@ -138,27 +132,26 @@ class WarningsProcessor:
|
|
|
138
132
|
def _get_warnings_for_timestamp(self, timestamp_str: str, warnings: List[MeteoWarning]) -> List[MeteoWarning]:
|
|
139
133
|
"""Get warnings that are active for a specific timestamp"""
|
|
140
134
|
try:
|
|
141
|
-
timestamp = datetime.fromisoformat(timestamp_str).
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
for warning in warnings:
|
|
145
|
-
if not warning.start_time or not warning.end_time:
|
|
146
|
-
continue
|
|
135
|
+
timestamp = datetime.fromisoformat(timestamp_str).astimezone(timezone.utc)
|
|
136
|
+
except (ValueError, AttributeError):
|
|
137
|
+
return []
|
|
147
138
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
139
|
+
# Forecast timestamp represents an hour starting at this time
|
|
140
|
+
hour_start = timestamp
|
|
141
|
+
hour_end = timestamp + timedelta(hours=1)
|
|
151
142
|
|
|
152
|
-
|
|
153
|
-
if start_time <= timestamp <= end_time:
|
|
154
|
-
applicable_warnings.append(warning)
|
|
143
|
+
applicable_warnings = []
|
|
155
144
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
145
|
+
for warning in warnings:
|
|
146
|
+
try:
|
|
147
|
+
start_time = datetime.fromisoformat(warning.start_time).astimezone(timezone.utc)
|
|
148
|
+
end_time = datetime.fromisoformat(warning.end_time).astimezone(timezone.utc)
|
|
149
|
+
except (ValueError, AttributeError, TypeError):
|
|
150
|
+
continue
|
|
159
151
|
|
|
160
|
-
|
|
152
|
+
# Check if warning period overlaps with the hour
|
|
153
|
+
# Warning overlaps if it starts before hour ends AND ends after hour starts
|
|
154
|
+
if start_time < hour_end and end_time > hour_start:
|
|
155
|
+
applicable_warnings.append(warning)
|
|
161
156
|
|
|
162
|
-
|
|
163
|
-
# Return empty list if timestamp parsing fails
|
|
164
|
-
return []
|
|
157
|
+
return applicable_warnings
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: meteo_lt-pkg
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: A library to fetch weather data from api.meteo.lt
|
|
5
5
|
Author-email: Brunas <brunonas@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/Brunas/meteo_lt-pkg
|
|
@@ -9,7 +9,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
9
9
|
Classifier: License :: OSI Approved :: MIT License
|
|
10
10
|
Classifier: Operating System :: OS Independent
|
|
11
11
|
Classifier: Development Status :: 4 - Beta
|
|
12
|
-
Requires-Python: >=3.
|
|
12
|
+
Requires-Python: >=3.11
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
License-File: LICENSE
|
|
15
15
|
Requires-Dist: aiohttp>=3.13
|
|
@@ -37,6 +37,11 @@ Dynamic: license-file
|
|
|
37
37
|
|
|
38
38
|
MeteoLt-Pkg is a Python library designed to fetch weather data from [`api.meteo.lt`](https://api.meteo.lt/). This library provides convenient methods to interact with the API and obtain weather forecasts and related data. Please visit for more information.
|
|
39
39
|
|
|
40
|
+
## Requirements
|
|
41
|
+
|
|
42
|
+
- Python 3.11 or higher
|
|
43
|
+
- aiohttp 3.13 or higher
|
|
44
|
+
|
|
40
45
|
## Installation
|
|
41
46
|
|
|
42
47
|
You can install the package using pip:
|
|
@@ -153,7 +158,7 @@ To get the weather forecast for a specific place:
|
|
|
153
158
|
```python
|
|
154
159
|
async def fetch_forecast():
|
|
155
160
|
async with MeteoLtAPI() as api:
|
|
156
|
-
# Get forecast for Vilnius
|
|
161
|
+
# Get forecast for Vilnius (warnings included by default)
|
|
157
162
|
forecast = await api.get_forecast("vilnius")
|
|
158
163
|
|
|
159
164
|
# Current conditions
|
|
@@ -162,6 +167,12 @@ async def fetch_forecast():
|
|
|
162
167
|
print(f"Feels like: {current.apparent_temperature}°C")
|
|
163
168
|
print(f"Condition: {current.condition_code}")
|
|
164
169
|
|
|
170
|
+
# Check for warnings (automatically included)
|
|
171
|
+
if current.warnings:
|
|
172
|
+
print(f"\nActive warnings: {len(current.warnings)}")
|
|
173
|
+
for warning in current.warnings:
|
|
174
|
+
print(f"- {warning.warning_type}: {warning.severity}")
|
|
175
|
+
|
|
165
176
|
# Future forecasts
|
|
166
177
|
print(f"\nNext 24 hours:")
|
|
167
178
|
for timestamp in forecast.forecast_timestamps[:24]:
|
|
@@ -170,6 +181,8 @@ async def fetch_forecast():
|
|
|
170
181
|
asyncio.run(fetch_forecast())
|
|
171
182
|
```
|
|
172
183
|
|
|
184
|
+
> **NOTE**: Weather and hydrological warnings are automatically included in forecast data by default. To exclude warnings, use `get_forecast(place_code, include_warnings=False)`.
|
|
185
|
+
|
|
173
186
|
> **NOTE**: `current_conditions` is the current hour record from the `forecast_timestamps` array. Also, `forecast_timestamps` array has past time records filtered out due to `api.meteo.lt` not doing that automatically.
|
|
174
187
|
|
|
175
188
|
### Fetching Weather Forecast with Warnings
|
|
@@ -212,6 +225,8 @@ async def fetch_warnings():
|
|
|
212
225
|
print(f"Warning: {warning.warning_type} in {warning.county}")
|
|
213
226
|
print(f"Severity: {warning.severity}")
|
|
214
227
|
print(f"Description: {warning.description}")
|
|
228
|
+
if warning.instruction:
|
|
229
|
+
print(f"Instruction: {warning.instruction}")
|
|
215
230
|
print(f"Active: {warning.start_time} to {warning.end_time}")
|
|
216
231
|
print("-" * 50)
|
|
217
232
|
|
|
@@ -243,6 +258,8 @@ async def fetch_hydro_warnings():
|
|
|
243
258
|
print(f"Hydro Warning: {warning.warning_type} in {warning.county}")
|
|
244
259
|
print(f"Severity: {warning.severity}")
|
|
245
260
|
print(f"Description: {warning.description}")
|
|
261
|
+
if warning.instruction:
|
|
262
|
+
print(f"Instruction: {warning.instruction}")
|
|
246
263
|
print("-" * 50)
|
|
247
264
|
|
|
248
265
|
async def fetch_hydro_warnings_for_area():
|
|
@@ -270,6 +287,8 @@ async def fetch_all_warnings():
|
|
|
270
287
|
print(f"{warning.warning_type} in {warning.county}")
|
|
271
288
|
print(f"Severity: {warning.severity}")
|
|
272
289
|
print(f"Description: {warning.description}")
|
|
290
|
+
if warning.instruction:
|
|
291
|
+
print(f"Instruction: {warning.instruction}")
|
|
273
292
|
print("-" * 50)
|
|
274
293
|
|
|
275
294
|
async def fetch_all_warnings_for_area():
|
|
@@ -379,11 +398,14 @@ weather_warning = MeteoWarning(
|
|
|
379
398
|
warning_type="frost",
|
|
380
399
|
severity="Moderate",
|
|
381
400
|
description="Ground surface frost 0-5 degrees in many places",
|
|
401
|
+
instruction="Protect sensitive plants and be cautious on roads", # Optional safety instruction
|
|
382
402
|
category="weather",
|
|
383
403
|
start_time="2024-07-23T12:00:00Z",
|
|
384
404
|
end_time="2024-07-23T18:00:00Z"
|
|
385
405
|
)
|
|
386
406
|
print(f"Warning for {weather_warning.county}: {weather_warning.description}")
|
|
407
|
+
if weather_warning.instruction:
|
|
408
|
+
print(f"Safety instruction: {weather_warning.instruction}")
|
|
387
409
|
print(f"Category: {weather_warning.category}") # "weather" or "hydro"
|
|
388
410
|
|
|
389
411
|
# Hydrological warning example
|
|
@@ -392,6 +414,7 @@ hydro_warning = MeteoWarning(
|
|
|
392
414
|
warning_type="flood",
|
|
393
415
|
severity="High",
|
|
394
416
|
description="High water levels expected",
|
|
417
|
+
instruction="Avoid low-lying areas and do not attempt to cross flooded roads", # Optional
|
|
395
418
|
category="hydro",
|
|
396
419
|
start_time="2024-07-23T12:00:00Z",
|
|
397
420
|
end_time="2024-07-24T12:00:00Z"
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
meteo_lt/__init__.py,sha256=3Ef5fihtzaxsRcygINTnNdQI9W_9JULe6ycyeRw8bN8,452
|
|
2
|
+
meteo_lt/api.py,sha256=Zjp_HHEyxKlrySFyBsszdpToHOeGDh-HacsBZoXJnG8,5068
|
|
3
|
+
meteo_lt/client.py,sha256=R4lfX9_m-x7Va7IcU6d3rxAE0plOg2gD4NJ9gqtIVvg,5189
|
|
4
|
+
meteo_lt/const.py,sha256=w0eEOss0YbTJzNdpfocrd5DZ7pFSwR3aQ-uMfNttvag,2791
|
|
5
|
+
meteo_lt/models.py,sha256=ENQmWFZMQmXhHIddoAuC7givYbXIlu58v_pI8iACR4o,6143
|
|
6
|
+
meteo_lt/utils.py,sha256=VhXWnqfeBdKrncrsIrSwzsiN3Sg4-kDG5v6Yz-PBOLc,1281
|
|
7
|
+
meteo_lt/warnings.py,sha256=tHoXRIxlxntXqP6XyU9qyG0nzcdjAxuRmcRDPwcr6-U,7015
|
|
8
|
+
meteo_lt_pkg-0.6.0.dist-info/licenses/LICENSE,sha256=3IGi6xn6NUdXGvcdwD0MUbhy3Yz5NRnUjJrwKanFAD4,1073
|
|
9
|
+
meteo_lt_pkg-0.6.0.dist-info/METADATA,sha256=LEds1ZWvATaad6IB21-XltyrtlEmdQ8YzZJfb5n5bIY,18804
|
|
10
|
+
meteo_lt_pkg-0.6.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
11
|
+
meteo_lt_pkg-0.6.0.dist-info/top_level.txt,sha256=-aEdc9FzHhcIH4_0TNdKNxuvDnS3chKoJy6LK9Ud-G4,9
|
|
12
|
+
meteo_lt_pkg-0.6.0.dist-info/RECORD,,
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
meteo_lt/__init__.py,sha256=3Ef5fihtzaxsRcygINTnNdQI9W_9JULe6ycyeRw8bN8,452
|
|
2
|
-
meteo_lt/api.py,sha256=GQDhDnTj3cx1hokt5188NnGz8FVDJHJDJXGm_fXxop8,5069
|
|
3
|
-
meteo_lt/client.py,sha256=R4lfX9_m-x7Va7IcU6d3rxAE0plOg2gD4NJ9gqtIVvg,5189
|
|
4
|
-
meteo_lt/const.py,sha256=w0eEOss0YbTJzNdpfocrd5DZ7pFSwR3aQ-uMfNttvag,2791
|
|
5
|
-
meteo_lt/models.py,sha256=aUF2K99bxKaLw9bRQkVkM18z44AvhmcvqmtzHXuQnkc,6105
|
|
6
|
-
meteo_lt/utils.py,sha256=VhXWnqfeBdKrncrsIrSwzsiN3Sg4-kDG5v6Yz-PBOLc,1281
|
|
7
|
-
meteo_lt/warnings.py,sha256=XKMCO45_AGjBfXD8NxyYXIel1w1Rm3OP8lkE_tnNKq0,7195
|
|
8
|
-
meteo_lt_pkg-0.5.2.dist-info/licenses/LICENSE,sha256=3IGi6xn6NUdXGvcdwD0MUbhy3Yz5NRnUjJrwKanFAD4,1073
|
|
9
|
-
meteo_lt_pkg-0.5.2.dist-info/METADATA,sha256=P6z7698ZBbUnEiUC9YZxz4mVDRmsdwdKOoc9zpjt0vw,17679
|
|
10
|
-
meteo_lt_pkg-0.5.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
11
|
-
meteo_lt_pkg-0.5.2.dist-info/top_level.txt,sha256=-aEdc9FzHhcIH4_0TNdKNxuvDnS3chKoJy6LK9Ud-G4,9
|
|
12
|
-
meteo_lt_pkg-0.5.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|