fix(weather): исправлены баги в погодном функционале
- JSONDecodeError теперь ловится в fetch_weather (был краш при невалидном JSON от API) - Порывы ветра больше не теряются при отсутствии base wind (gust fallback) - Устранено дублирование 'м/с' при порывах + отсутствии направления ветра - Переименован windspeedKmph → wind_speed_mps (ключ хранил м/с, а не км/ч) - Обновлены тесты, добавлены 6 новых (gust-only, no-duplication, JSONDecodeError)
This commit is contained in:
parent
517bb4b9fa
commit
b8b1801f23
@ -27,7 +27,7 @@ class TestPgCommand:
|
|||||||
def _make_weather_data(self, **extra):
|
def _make_weather_data(self, **extra):
|
||||||
"""Создать mock weather data (Яндекс Погода формат).
|
"""Создать mock weather data (Яндекс Погода формат).
|
||||||
|
|
||||||
windspeedKmph — м/с от Яндекса.
|
wind_speed_mps — скорость ветра в м/с от Яндекса.
|
||||||
wind_gust — порывы ветра в м/с.
|
wind_gust — порывы ветра в м/с.
|
||||||
wind_dir — направление ветра.
|
wind_dir — направление ветра.
|
||||||
pressure — уже в мм рт. ст.
|
pressure — уже в мм рт. ст.
|
||||||
@ -40,7 +40,7 @@ class TestPgCommand:
|
|||||||
"FeelsLikeC": 24,
|
"FeelsLikeC": 24,
|
||||||
"weatherDesc": [{"value": "Ясно"}],
|
"weatherDesc": [{"value": "Ясно"}],
|
||||||
"humidity": 45,
|
"humidity": 45,
|
||||||
"windspeedKmph": 5.0, # м/с
|
"wind_speed_mps": 5.0, # м/с
|
||||||
"wind_gust": 8.0,
|
"wind_gust": 8.0,
|
||||||
"wind_dir": "n",
|
"wind_dir": "n",
|
||||||
"pressure": 735.0,
|
"pressure": 735.0,
|
||||||
@ -66,7 +66,7 @@ class TestPgCommand:
|
|||||||
assert "(ощущается как 24°C)" in args
|
assert "(ощущается как 24°C)" in args
|
||||||
assert "Описание: Ясно" in args
|
assert "Описание: Ясно" in args
|
||||||
assert "Влажность: 45%" in args
|
assert "Влажность: 45%" in args
|
||||||
assert "Ветер: 5.0 м/с" in args
|
assert "Ветер: 5.0 (порывы 8.0), северный м/с" in args
|
||||||
assert "Давление: 735.0 мм рт. ст." in args
|
assert "Давление: 735.0 мм рт. ст." in args
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@ -94,7 +94,7 @@ class TestPgCommand:
|
|||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_pg_current_condition_none(self) -> None:
|
async def test_pg_current_condition_none(self) -> None:
|
||||||
"""current_condition — пустой dict — бот должен сообщить об ошибке."""
|
"""current_condition — пустой dict — бот сообщает об ошибке (empty dict is falsy)."""
|
||||||
cog = self._make_cog()
|
cog = self._make_cog()
|
||||||
ctx = self._make_ctx()
|
ctx = self._make_ctx()
|
||||||
weather = {"current_condition": [{}]}
|
weather = {"current_condition": [{}]}
|
||||||
@ -106,23 +106,26 @@ class TestPgCommand:
|
|||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_pg_wind_non_numeric(self) -> None:
|
async def test_pg_wind_non_numeric(self) -> None:
|
||||||
"""windspeedKmph — не число — wind должен быть '—'."""
|
"""wind_speed_mps — не число — показываются порывы ветра (gust fallback)."""
|
||||||
cog = self._make_cog()
|
cog = self._make_cog()
|
||||||
ctx = self._make_ctx()
|
ctx = self._make_ctx()
|
||||||
weather = self._make_weather_data(windspeedKmph="abc")
|
weather = self._make_weather_data(wind_speed_mps="abc") # gust=8.0, dir=n по умолчанию
|
||||||
|
|
||||||
with patch("commands.pg.fetch_weather", new=AsyncMock(return_value=weather)):
|
with patch("commands.pg.fetch_weather", new=AsyncMock(return_value=weather)):
|
||||||
await cog.pg.callback(cog, ctx)
|
await cog.pg.callback(cog, ctx)
|
||||||
|
|
||||||
args = ctx.send.call_args[0][0]
|
args = ctx.send.call_args[0][0]
|
||||||
assert "Ветер: — м/с" in args
|
# base wind невалиден → показываем порывы
|
||||||
|
assert "Ветер: порывы 8.0, северный м/с" in args
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_pg_wind_none(self) -> None:
|
async def test_pg_wind_none(self) -> None:
|
||||||
"""windspeedKmph отсутствует — wind должен быть '—'."""
|
"""wind_speed_mps отсутствует, порывов нет — wind должен быть '— м/с'."""
|
||||||
cog = self._make_cog()
|
cog = self._make_cog()
|
||||||
ctx = self._make_ctx()
|
ctx = self._make_ctx()
|
||||||
weather = self._make_weather_data(windspeedKmph=None)
|
weather = self._make_weather_data(
|
||||||
|
wind_speed_mps=None, wind_gust=None, wind_dir=None
|
||||||
|
)
|
||||||
|
|
||||||
with patch("commands.pg.fetch_weather", new=AsyncMock(return_value=weather)):
|
with patch("commands.pg.fetch_weather", new=AsyncMock(return_value=weather)):
|
||||||
await cog.pg.callback(cog, ctx)
|
await cog.pg.callback(cog, ctx)
|
||||||
@ -132,16 +135,16 @@ class TestPgCommand:
|
|||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_pg_zero_wind(self) -> None:
|
async def test_pg_zero_wind(self) -> None:
|
||||||
"""windspeedKmph = 0 — wind должен быть 0.0."""
|
"""wind_speed_mps = 0 — 0.0 + порывы + направление."""
|
||||||
cog = self._make_cog()
|
cog = self._make_cog()
|
||||||
ctx = self._make_ctx()
|
ctx = self._make_ctx()
|
||||||
weather = self._make_weather_data(windspeedKmph=0)
|
weather = self._make_weather_data(wind_speed_mps=0) # gust=8.0, dir=n по умолчанию
|
||||||
|
|
||||||
with patch("commands.pg.fetch_weather", new=AsyncMock(return_value=weather)):
|
with patch("commands.pg.fetch_weather", new=AsyncMock(return_value=weather)):
|
||||||
await cog.pg.callback(cog, ctx)
|
await cog.pg.callback(cog, ctx)
|
||||||
|
|
||||||
args = ctx.send.call_args[0][0]
|
args = ctx.send.call_args[0][0]
|
||||||
assert "Ветер: 0.0 м/с" in args
|
assert "Ветер: 0.0 (порывы 8.0), северный м/с" in args
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_pg_default_values(self) -> None:
|
async def test_pg_default_values(self) -> None:
|
||||||
@ -188,7 +191,7 @@ class TestPgCommand:
|
|||||||
cog = self._make_cog()
|
cog = self._make_cog()
|
||||||
ctx = self._make_ctx()
|
ctx = self._make_ctx()
|
||||||
weather = self._make_weather_data(
|
weather = self._make_weather_data(
|
||||||
windspeedKmph=3.0,
|
wind_speed_mps=3.0,
|
||||||
wind_gust=10.5,
|
wind_gust=10.5,
|
||||||
wind_dir="n",
|
wind_dir="n",
|
||||||
)
|
)
|
||||||
@ -197,7 +200,7 @@ class TestPgCommand:
|
|||||||
await cog.pg.callback(cog, ctx)
|
await cog.pg.callback(cog, ctx)
|
||||||
|
|
||||||
args = ctx.send.call_args[0][0]
|
args = ctx.send.call_args[0][0]
|
||||||
assert "Ветер: 3.0 м/с (порывы 10.5 м/с), северный" in args
|
assert "Ветер: 3.0 (порывы 10.5), северный м/с" in args
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_pg_with_wind_direction(self) -> None:
|
async def test_pg_with_wind_direction(self) -> None:
|
||||||
@ -205,7 +208,7 @@ class TestPgCommand:
|
|||||||
cog = self._make_cog()
|
cog = self._make_cog()
|
||||||
ctx = self._make_ctx()
|
ctx = self._make_ctx()
|
||||||
weather = self._make_weather_data(
|
weather = self._make_weather_data(
|
||||||
windspeedKmph=5.0,
|
wind_speed_mps=5.0,
|
||||||
wind_gust=8.0,
|
wind_gust=8.0,
|
||||||
wind_dir="se",
|
wind_dir="se",
|
||||||
)
|
)
|
||||||
@ -225,7 +228,7 @@ class TestPgCommand:
|
|||||||
temp_C=17.3,
|
temp_C=17.3,
|
||||||
FeelsLikeC=16.8,
|
FeelsLikeC=16.8,
|
||||||
humidity=87.5,
|
humidity=87.5,
|
||||||
windspeedKmph=2.1, # м/с
|
wind_speed_mps=2.1, # м/с
|
||||||
wind_gust=5.5,
|
wind_gust=5.5,
|
||||||
wind_dir="n",
|
wind_dir="n",
|
||||||
pressure=750.1,
|
pressure=750.1,
|
||||||
@ -236,5 +239,41 @@ class TestPgCommand:
|
|||||||
|
|
||||||
args = ctx.send.call_args[0][0]
|
args = ctx.send.call_args[0][0]
|
||||||
assert "Температура: 17.3°C" in args
|
assert "Температура: 17.3°C" in args
|
||||||
assert "Ветер: 2.1 м/с" in args
|
assert "Ветер: 2.1 (порывы 5.5), северный м/с" in args
|
||||||
assert "Давление: 750.1 мм рт. ст." in args
|
assert "Давление: 750.1 мм рт. ст." in args
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_pg_gust_only_no_base_wind(self) -> None:
|
||||||
|
"""При отсутствии base wind порывы ветра всё равно показываются."""
|
||||||
|
cog = self._make_cog()
|
||||||
|
ctx = self._make_ctx()
|
||||||
|
weather = self._make_weather_data(
|
||||||
|
wind_speed_mps=None,
|
||||||
|
wind_gust=10.5,
|
||||||
|
wind_dir="n",
|
||||||
|
)
|
||||||
|
|
||||||
|
with patch("commands.pg.fetch_weather", new=AsyncMock(return_value=weather)):
|
||||||
|
await cog.pg.callback(cog, ctx)
|
||||||
|
|
||||||
|
args = ctx.send.call_args[0][0]
|
||||||
|
assert "Ветер: порывы 10.5, северный м/с" in args
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_pg_gust_only_no_direction(self) -> None:
|
||||||
|
"""Порывы ветра без направления и base wind — без дублирования 'м/с'."""
|
||||||
|
cog = self._make_cog()
|
||||||
|
ctx = self._make_ctx()
|
||||||
|
weather = self._make_weather_data(
|
||||||
|
wind_speed_mps=None,
|
||||||
|
wind_gust=10.5,
|
||||||
|
wind_dir=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
with patch("commands.pg.fetch_weather", new=AsyncMock(return_value=weather)):
|
||||||
|
await cog.pg.callback(cog, ctx)
|
||||||
|
|
||||||
|
args = ctx.send.call_args[0][0]
|
||||||
|
assert "Ветер: порывы 10.5 м/с" in args
|
||||||
|
# Убеждаемся, что 'м/с' не дублируется
|
||||||
|
assert args.count("м/с") == 1
|
||||||
|
|||||||
@ -229,7 +229,7 @@ class TestFetchWeather:
|
|||||||
result = await fetch_weather()
|
result = await fetch_weather()
|
||||||
|
|
||||||
assert result is not None
|
assert result is not None
|
||||||
assert result["current_condition"][0]["windspeedKmph"] == 0
|
assert result["current_condition"][0]["wind_speed_mps"] == 0
|
||||||
assert result["current_condition"][0]["pressure"] == 750.0
|
assert result["current_condition"][0]["pressure"] == 750.0
|
||||||
|
|
||||||
@patch("utils.pogoda._session.get")
|
@patch("utils.pogoda._session.get")
|
||||||
@ -285,3 +285,17 @@ class TestFetchWeather:
|
|||||||
call_kwargs = mock_get.call_args[1]
|
call_kwargs = mock_get.call_args[1]
|
||||||
assert "X-Yandex-API-Key" in call_kwargs["headers"]
|
assert "X-Yandex-API-Key" in call_kwargs["headers"]
|
||||||
assert call_kwargs["headers"]["X-Yandex-API-Key"] == "test-key"
|
assert call_kwargs["headers"]["X-Yandex-API-Key"] == "test-key"
|
||||||
|
|
||||||
|
@patch("utils.pogoda._session.get")
|
||||||
|
async def test_fetch_weather_json_decode_error(self, mock_get) -> None:
|
||||||
|
"""json.JSONDecodeError (невалидный JSON от API) → graceful None."""
|
||||||
|
import json as _json
|
||||||
|
|
||||||
|
mock_response = MagicMock()
|
||||||
|
mock_response.raise_for_status = MagicMock()
|
||||||
|
mock_response.json.side_effect = _json.JSONDecodeError("Expecting value", "", 0)
|
||||||
|
mock_get.return_value = mock_response
|
||||||
|
|
||||||
|
result = await fetch_weather(max_retries=1)
|
||||||
|
|
||||||
|
assert result is None
|
||||||
|
|||||||
@ -20,7 +20,7 @@ class TestFormatWeatherDataForConsole:
|
|||||||
"FeelsLikeC": 26,
|
"FeelsLikeC": 26,
|
||||||
"weatherDesc": [{"value": "Ясно"}],
|
"weatherDesc": [{"value": "Ясно"}],
|
||||||
"humidity": 45,
|
"humidity": 45,
|
||||||
"windspeedKmph": 5.0, # м/с от Яндекса
|
"wind_speed_mps": 5.0, # м/с от Яндекса
|
||||||
"wind_gust": 8.0,
|
"wind_gust": 8.0,
|
||||||
"wind_dir": "n",
|
"wind_dir": "n",
|
||||||
"pressure": 735.0, # уже в мм рт. ст.
|
"pressure": 735.0, # уже в мм рт. ст.
|
||||||
@ -35,7 +35,7 @@ class TestFormatWeatherDataForConsole:
|
|||||||
assert "Температура: 25°C (ощущается как 26°C)" in result[0]
|
assert "Температура: 25°C (ощущается как 26°C)" in result[0]
|
||||||
assert "Описание: Ясно" in result[1]
|
assert "Описание: Ясно" in result[1]
|
||||||
assert "Влажность: 45%" in result[2]
|
assert "Влажность: 45%" in result[2]
|
||||||
assert "Ветер: 5.0 м/с (порывы 8.0 м/с), северный" in result[3]
|
assert "Ветер: 5.0 (порывы 8.0), северный м/с" in result[3]
|
||||||
assert "Давление: 735.0 мм рт. ст." in result[4]
|
assert "Давление: 735.0 мм рт. ст." in result[4]
|
||||||
|
|
||||||
def test_format_empty_data(self) -> None:
|
def test_format_empty_data(self) -> None:
|
||||||
@ -63,7 +63,8 @@ class TestFormatWeatherDataForConsole:
|
|||||||
"FeelsLikeC": None,
|
"FeelsLikeC": None,
|
||||||
"weatherDesc": [{"value": "Неизвестно"}],
|
"weatherDesc": [{"value": "Неизвестно"}],
|
||||||
"humidity": None,
|
"humidity": None,
|
||||||
"windspeedKmph": None,
|
"wind_speed_mps": None,
|
||||||
|
"wind_gust": None,
|
||||||
"pressure": None,
|
"pressure": None,
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -87,7 +88,7 @@ class TestFormatWeatherDataForConsole:
|
|||||||
"FeelsLikeC": -10,
|
"FeelsLikeC": -10,
|
||||||
"weatherDesc": [{"value": "Снег"}],
|
"weatherDesc": [{"value": "Снег"}],
|
||||||
"humidity": 80,
|
"humidity": 80,
|
||||||
"windspeedKmph": 5,
|
"wind_speed_mps": 5,
|
||||||
"wind_gust": 10,
|
"wind_gust": 10,
|
||||||
"wind_dir": "n",
|
"wind_dir": "n",
|
||||||
"pressure": 720.0,
|
"pressure": 720.0,
|
||||||
@ -109,7 +110,7 @@ class TestFormatWeatherDataForConsole:
|
|||||||
"FeelsLikeC": 16.8,
|
"FeelsLikeC": 16.8,
|
||||||
"weatherDesc": [{"value": "Облачно"}],
|
"weatherDesc": [{"value": "Облачно"}],
|
||||||
"humidity": 87.5,
|
"humidity": 87.5,
|
||||||
"windspeedKmph": 2.1, # м/с
|
"wind_speed_mps": 2.1, # м/с
|
||||||
"pressure": 750.0,
|
"pressure": 750.0,
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -140,7 +141,7 @@ class TestFormatWeatherDataForConsole:
|
|||||||
"FeelsLikeC": 18,
|
"FeelsLikeC": 18,
|
||||||
"weatherDesc": [{"value": "Ясно"}],
|
"weatherDesc": [{"value": "Ясно"}],
|
||||||
"humidity": 50,
|
"humidity": 50,
|
||||||
"windspeedKmph": 3.0,
|
"wind_speed_mps": 3.0,
|
||||||
"wind_dir": code,
|
"wind_dir": code,
|
||||||
"pressure": 750.0,
|
"pressure": 750.0,
|
||||||
}
|
}
|
||||||
@ -149,6 +150,68 @@ class TestFormatWeatherDataForConsole:
|
|||||||
result = format_weather_data_for_console(data)
|
result = format_weather_data_for_console(data)
|
||||||
assert expected in result[3], f"Направление {code} → {expected} не найдено"
|
assert expected in result[3], f"Направление {code} → {expected} не найдено"
|
||||||
|
|
||||||
|
def test_format_gust_only_no_base_wind(self) -> None:
|
||||||
|
"""При отсутствии base wind порывы ветра всё равно показываются."""
|
||||||
|
data = {
|
||||||
|
"current_condition": [
|
||||||
|
{
|
||||||
|
"temp_C": 20,
|
||||||
|
"FeelsLikeC": 18,
|
||||||
|
"weatherDesc": [{"value": "Ясно"}],
|
||||||
|
"humidity": 50,
|
||||||
|
"wind_speed_mps": None,
|
||||||
|
"wind_gust": 10.5,
|
||||||
|
"wind_dir": "n",
|
||||||
|
"pressure": 750.0,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
result = format_weather_data_for_console(data)
|
||||||
|
assert "Ветер: порывы 10.5, северный м/с" in result[3]
|
||||||
|
|
||||||
|
def test_format_gust_only_no_duplication(self) -> None:
|
||||||
|
"""Порывы без направления и base wind — 'м/с' не дублируется."""
|
||||||
|
data = {
|
||||||
|
"current_condition": [
|
||||||
|
{
|
||||||
|
"temp_C": 20,
|
||||||
|
"FeelsLikeC": 18,
|
||||||
|
"weatherDesc": [{"value": "Ясно"}],
|
||||||
|
"humidity": 50,
|
||||||
|
"wind_speed_mps": None,
|
||||||
|
"wind_gust": 10.5,
|
||||||
|
"wind_dir": None,
|
||||||
|
"pressure": 750.0,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
result = format_weather_data_for_console(data)
|
||||||
|
assert "Ветер: порывы 10.5 м/с" in result[3]
|
||||||
|
assert result[3].count("м/с") == 1
|
||||||
|
|
||||||
|
def test_format_base_wind_with_gust_no_dir(self) -> None:
|
||||||
|
"""Base wind + порывы без направления — 'м/с' не дублируется."""
|
||||||
|
data = {
|
||||||
|
"current_condition": [
|
||||||
|
{
|
||||||
|
"temp_C": 20,
|
||||||
|
"FeelsLikeC": 18,
|
||||||
|
"weatherDesc": [{"value": "Ясно"}],
|
||||||
|
"humidity": 50,
|
||||||
|
"wind_speed_mps": 5.0,
|
||||||
|
"wind_gust": 8.0,
|
||||||
|
"wind_dir": None,
|
||||||
|
"pressure": 750.0,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
result = format_weather_data_for_console(data)
|
||||||
|
assert "Ветер: 5.0 (порывы 8.0) м/с" in result[3]
|
||||||
|
assert result[3].count("м/с") == 1
|
||||||
|
|
||||||
|
|
||||||
class TestPressureToMMHG:
|
class TestPressureToMMHG:
|
||||||
"""Тесты функции pressure_to_mmhg() — конвертация давления из мб в мм рт. ст."""
|
"""Тесты функции pressure_to_mmhg() — конвертация давления из мб в мм рт. ст."""
|
||||||
|
|||||||
@ -7,6 +7,7 @@ https://yandex.ru/dev/weather/
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
@ -66,7 +67,7 @@ async def fetch_weather(
|
|||||||
"FeelsLikeC": fact.get("feels_like"),
|
"FeelsLikeC": fact.get("feels_like"),
|
||||||
"weatherDesc": [{"value": yandex_condition_to_russian(fact.get("condition"))}],
|
"weatherDesc": [{"value": yandex_condition_to_russian(fact.get("condition"))}],
|
||||||
"humidity": fact.get("humidity"),
|
"humidity": fact.get("humidity"),
|
||||||
"windspeedKmph": fact.get("wind_speed"),
|
"wind_speed_mps": fact.get("wind_speed"),
|
||||||
"wind_gust": fact.get("wind_gust"),
|
"wind_gust": fact.get("wind_gust"),
|
||||||
"wind_dir": fact.get("wind_dir"),
|
"wind_dir": fact.get("wind_dir"),
|
||||||
"pressure": fact.get("pressure_mm"),
|
"pressure": fact.get("pressure_mm"),
|
||||||
@ -83,7 +84,7 @@ async def fetch_weather(
|
|||||||
await asyncio.sleep(delay)
|
await asyncio.sleep(delay)
|
||||||
continue
|
continue
|
||||||
break
|
break
|
||||||
except requests.RequestException as e:
|
except (requests.RequestException, json.JSONDecodeError, ValueError) as e:
|
||||||
logger.error("Ошибка Яндекс Погоды: %s", e)
|
logger.error("Ошибка Яндекс Погоды: %s", e)
|
||||||
break
|
break
|
||||||
|
|
||||||
@ -153,23 +154,34 @@ def format_weather_data_for_console(data: Optional[dict]) -> Optional[list[str]]
|
|||||||
if humidity is None:
|
if humidity is None:
|
||||||
humidity = "—"
|
humidity = "—"
|
||||||
|
|
||||||
# Яндекс возвращает ветер в м/с, но для совместимости с унифицированным
|
# Скорость ветра (м/с)
|
||||||
# форматом WindspeedKmph содержит м/с — конвертируем обратно в м/с для вывода
|
wind_mps = current.get("wind_speed_mps")
|
||||||
wind_mps = current.get("windspeedKmph")
|
wind_value = None
|
||||||
if wind_mps is None:
|
if wind_mps is not None:
|
||||||
wind = "—"
|
|
||||||
else:
|
|
||||||
try:
|
try:
|
||||||
# windspeedKmph на самом деле хранит м/с от Яндекса
|
wind_value = round(float(wind_mps), 1)
|
||||||
wind = round(float(wind_mps), 1)
|
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
wind = "—"
|
pass
|
||||||
|
|
||||||
# Порывы ветра (м/с)
|
# Собираем компоненты ветра
|
||||||
|
wind_parts = []
|
||||||
|
|
||||||
|
if wind_value is not None:
|
||||||
|
wind_parts.append(str(wind_value))
|
||||||
|
elif wind_value is None:
|
||||||
|
# Базовая скорость отсутствует — покажем порывы, если есть
|
||||||
|
wind_gust = current.get("wind_gust")
|
||||||
|
if wind_gust is not None:
|
||||||
|
try:
|
||||||
|
wind_parts.append(f"порывы {round(float(wind_gust), 1)}")
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Порывы ветра (м/с) — добавляем к базовой скорости
|
||||||
wind_gust = current.get("wind_gust")
|
wind_gust = current.get("wind_gust")
|
||||||
if wind_gust is not None:
|
if wind_gust is not None and wind_value is not None:
|
||||||
try:
|
try:
|
||||||
wind = f"{wind} м/с (порывы {round(float(wind_gust), 1)} м/с)"
|
wind_parts[-1] = f"{wind_parts[-1]} (порывы {round(float(wind_gust), 1)})"
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -177,8 +189,12 @@ def format_weather_data_for_console(data: Optional[dict]) -> Optional[list[str]]
|
|||||||
wind_dir = current.get("wind_dir")
|
wind_dir = current.get("wind_dir")
|
||||||
if wind_dir is not None:
|
if wind_dir is not None:
|
||||||
wind_dir_ru = _wind_dir_to_russian(wind_dir)
|
wind_dir_ru = _wind_dir_to_russian(wind_dir)
|
||||||
if wind != "—":
|
wind_parts.append(wind_dir_ru)
|
||||||
wind = f"{wind}, {wind_dir_ru}"
|
|
||||||
|
if wind_parts:
|
||||||
|
wind = ", ".join(wind_parts) + " м/с"
|
||||||
|
else:
|
||||||
|
wind = "— м/с"
|
||||||
|
|
||||||
# Давление — Яндекс уже возвращает в мм рт. ст.
|
# Давление — Яндекс уже возвращает в мм рт. ст.
|
||||||
pressure_mm = current.get("pressure")
|
pressure_mm = current.get("pressure")
|
||||||
@ -194,7 +210,7 @@ def format_weather_data_for_console(data: Optional[dict]) -> Optional[list[str]]
|
|||||||
f"Температура: {temp}°C (ощущается как {feels_like}°C)",
|
f"Температура: {temp}°C (ощущается как {feels_like}°C)",
|
||||||
f"Описание: {description}",
|
f"Описание: {description}",
|
||||||
f"Влажность: {humidity}%",
|
f"Влажность: {humidity}%",
|
||||||
f"Ветер: {wind} м/с" if not wind_dir or wind_dir in ("—", None) else f"Ветер: {wind}",
|
f"Ветер: {wind}",
|
||||||
f"Давление: {pressure_mm} мм рт. ст.",
|
f"Давление: {pressure_mm} мм рт. ст.",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user