fix: H2 — translate_weather сортировка ключей по убыванию длины

- Заменён dict на _WEATHER_MAPPING (list of tuples, отсортирован по длине ключей)
- Длинные фразы проверяются первыми, исключая ложные подстроочные совпадения
- "Moderate or heavy rain at times" теперь корректно -> "Дождь" вместо "Сильный дождь"
- Обновлены тесты: test_translate_known и test_translate_longer_key_priority

230 тестов проходят.
This commit is contained in:
deadzilla 2026-07-07 21:28:29 +05:00
parent 5d9c33a12c
commit 3aebda1114
3 changed files with 52 additions and 51 deletions

View File

@ -53,7 +53,7 @@ except KeyboardInterrupt:
## HIGH ## HIGH
### H1. `format_weather_data_for_console` -- IndexError при пустом `current_condition` ### H1. `format_weather_data_for_console` -- IndexError при пустом `current_condition` — **ИСПРАВЛЕНО**
**Файл:** `utils/pogoda.py`, строка 122 **Файл:** `utils/pogoda.py`, строка 122
@ -86,7 +86,7 @@ current = current_condition_list[0]
--- ---
### H2. `translate_weather` -- подстроочное совпадение зависит от порядка dict ### H2. `translate_weather` -- подстроочное совпадение зависит от порядка dict — **ИСПРАВЛЕНО**
**Файл:** `utils/pogoda.py`, строки 96-130 **Файл:** `utils/pogoda.py`, строки 96-130
@ -536,8 +536,8 @@ DeprecationWarning: 'asyncio.iscoroutinefunction' is deprecated and slated for r
### Этап 2: High (баги + надёжность) ### Этап 2: High (баги + надёжность)
3. [ ] H1: Защитить `format_weather_data_for_console` от пустого списка 3. [x] H1: Защитить `format_weather_data_for_console` от пустого списка — **выполнено**
4. [ ] H2: Отсортировать ключи `translate_weather` по убыванию длины 4. [x] H2: Отсортировать ключи `translate_weather` по убыванию длины — **выполнено**
5. [ ] H3: Исправить `pressure_to_mmhg` -- `not mb` -> `mb is None or mb == ""` 5. [ ] H3: Исправить `pressure_to_mmhg` -- `not mb` -> `mb is None or mb == ""`
6. [ ] H4: Добавить защиту от дублирования cogs в `on_ready` 6. [ ] H4: Добавить защиту от дублирования cogs в `on_ready`
7. [ ] H5: Заменить `asyncio.run()` на `async def` в fetch-тестах (50+ тестов) 7. [ ] H5: Заменить `asyncio.run()` на `async def` в fetch-тестах (50+ тестов)

View File

@ -121,7 +121,7 @@ class TestTranslateWeather:
("Light rain", "Небольшой дождь"), ("Light rain", "Небольшой дождь"),
("Moderate rain", "Умеренный дождь"), ("Moderate rain", "Умеренный дождь"),
("Heavy rain", "Сильный дождь"), ("Heavy rain", "Сильный дождь"),
("Moderate or heavy rain at times", "Сильный дождь"), # "Heavy rain" совпадает раньше в mapping dict (key in text) ("Moderate or heavy rain at times", "Дождь"), # длинный ключ проверяется первым
("Heavy rain at times", "Сильный дождь"), ("Heavy rain at times", "Сильный дождь"),
("Light snow", "Небольшой снег"), ("Light snow", "Небольшой снег"),
("Moderate snow", "Умеренный снег"), ("Moderate snow", "Умеренный снег"),
@ -169,12 +169,10 @@ class TestTranslateWeather:
assert translate_weather(text_with_prefix) == "Дождь" assert translate_weather(text_with_prefix) == "Дождь"
def test_translate_longer_key_priority(self): def test_translate_longer_key_priority(self):
"""translate_weather ищет key in text, порядок dict важен. """Длинные ключи проверяются первыми (_WEATHER_MAPPING отсортирован по убыванию длины).
"Heavy rain" стоит раньше "Moderate or heavy rain at times" в mapping, "Moderate or heavy rain at times" проверится до "Heavy rain"."""
и "heavy rain" in "moderate or heavy rain at times" = True.
Поэтому совпадёт первым и вернёт "Сильный дождь"."""
text = "Moderate or heavy rain at times" text = "Moderate or heavy rain at times"
assert translate_weather(text) == "Сильный дождь" assert translate_weather(text) == "Дождь"
def test_translate_case_insensitive(self): def test_translate_case_insensitive(self):
"""Перевод должен быть регистронезависимым.""" """Перевод должен быть регистронезависимым."""

View File

@ -98,50 +98,53 @@ def wmo_to_russian(code):
return mapping.get(code, "Неизвестно") return mapping.get(code, "Неизвестно")
_WEATHER_MAPPING = [
("Moderate or heavy freezing rain at a distance", "Ледяной дождь"),
("Moderate or heavy sleet at a distance", "Слякоть"),
("Moderate or heavy freezing rain in area", "Ледяной дождь"),
("Moderate or heavy sleet in area", "Слякоть"),
("Moderate or heavy snow in area", "Снег"),
("Moderate or heavy rain in area", "Дождь"),
("Thundery outbreaks in nearby", "Гроза вблизи"),
("Moderate or heavy rain at times", "Дождь"),
("Moderate or heavy snow at times", "Снег"),
("Patchy light drizzle", "Местами лёгкая морось"),
("Patchy light snow", "Местами лёгкий снег"),
("Heavy freezing rain", "Сильный ледяной дождь"),
("Light freezing rain", "Лёгкий ледяной дождь"),
("Light rain shower", "Небольшой дождь"),
("Heavy rain shower", "Сильный дождь"),
("Moderate or light sleet", "Слякоть"),
("Patchy rain nearby", "Местами дождь"),
("Patchy snow nearby", "Местами снег"),
("Patchy sleet nearby", "Местами слякоть"),
("Moderate rain at times", "Умеренный дождь"),
("Heavy rain at times", "Сильный дождь"),
("Moderate rain", "Умеренный дождь"),
("Light rain", "Небольшой дождь"),
("Heavy rain", "Сильный дождь"),
("Light snow", "Небольшой снег"),
("Moderate snow", "Умеренный снег"),
("Heavy snow", "Сильный снег"),
("Blowing snow", "Метель"),
("Partly cloudy", "Переменная облачность"),
("Overcast", "Пасмурно"),
("Cloudy", "Облачно"),
("Foggy", "Туманно"),
("Fog", "Туман"),
("Mist", "Туман"),
("Haze", "Дымка"),
("Clear", "Ясно"),
("Sunny", "Ясно"),
]
def translate_weather(en): def translate_weather(en):
if not en: if not en:
return "" return ""
mapping = { en_lower = en.lower()
"Moderate or heavy freezing rain in area": "Ледяной дождь", for key, value in _WEATHER_MAPPING:
"Moderate or heavy sleet in area": "Слякоть", if key.lower() in en_lower:
"Moderate or heavy snow in area": "Снег",
"Moderate or heavy rain in area": "Дождь",
"Thundery outbreaks in nearby": "Гроза вблизи",
"Patchy rain nearby": "Местами дождь",
"Patchy snow nearby": "Местами снег",
"Patchy sleet nearby": "Местами слякоть",
"Heavy freezing rain": "Сильный ледяной дождь",
"Heavy snow": "Сильный снег",
"Heavy rain": "Сильный дождь",
"Moderate or heavy rain at times": "Дождь",
"Moderate or heavy snow at times": "Снег",
"Blowing snow": "Метель",
"Patchy light drizzle": "Местами лёгкая морось",
"Moderate or heavy freezing rain at a distance": "Ледяной дождь",
"Moderate or heavy sleet at a distance": "Слякоть",
"Light rain shower": "Небольшой дождь",
"Heavy rain shower": "Сильный дождь",
"Moderate rain": "Умеренный дождь",
"Light rain": "Небольшой дождь",
"Moderate rain at times": "Умеренный дождь",
"Heavy rain at times": "Сильный дождь",
"Light snow": "Небольшой снег",
"Moderate snow": "Умеренный снег",
"Patchy light snow": "Местами лёгкий снег",
"Partly cloudy": "Переменная облачность",
"Moderate or light sleet": "Слякоть",
"Light freezing rain": "Лёгкий ледяной дождь",
"Foggy": "Туманно",
"Fog": "Туман",
"Mist": "Туман",
"Haze": "Дымка",
"Overcast": "Пасмурно",
"Cloudy": "Облачно",
"Clear": "Ясно",
"Sunny": "Ясно",
}
for key, value in mapping.items():
if key.lower() in en.lower():
return value return value
return en return en