Если run_morning выбрасывает исключение, ошибка теперь
перехватывается: логируется с exc_info, пользователю
отправлено сообщение об ошибке. Тест обновлён — проверяется
что исключение не пробрасывается наружу.
Если _scheduler_loop завершится с неожиданной ошибкой
(не CancelledError), это теперь залогировано через
_on_task_done callback. Штатное завершение через cancel()
пропускается без логов.
Объединены зависимости из requirements.txt и requirements-dev.txt,
настройки pytest из pytest.ini, и базовая конфигурация ruff.
Dockerfile обновлён: установка зависимостей через pyproject.toml.
requirements.txt/pytest.ini сохранены для обратной совместимости.
- WEATHER_CITY и WEATHER_CACHE_TTL добавлены в docker-compose.yml
с дефолтными значениями
- conftest.py удалён из Dockerfile — тестовый файл не нужен в production
Файлы: Dockerfile, docker-compose.yml
Блоки обработки articles и posts в !nw были почти идентичны.
Вынесено в _format_feed_section() с параметризацией лейблов,
сообщений об ошибках и заголовков RSS-источников.
Файлы: commands/news.py
Город больше не захардкожен в коде. Переопределяется через
WEATHER_CITY (по умолчанию "Магнитогорск"). Шаблон изменён на
"Погода: {city}:" для обхода проблемы падежей в русском языке.
Файлы: utils/pogoda.py, .env.example, tests/test_morning_runner.py
ruff format --check падает на 7 файлах (не 5 как было указано).
Изменения — чистое форматирование: line wrapping, trailing commas, blank lines.
Никаких логических изменений.
Файлы: bot.py, tests/test_commands_news.py, tests/test_commands_pg.py,
tests/test_fetch_weather.py, tests/test_help_command.py,
tests/test_morning_runner.py, utils/pogoda.py
- fetch_weather кэширует результат на 3600 сек (WEATHER_CACHE_TTL)
- Провал запроса тоже кэшируется — не долбит API повторно
- bypass_cache=True для форсирования свежего запроса
- clear_weather_cache() для сброса кэша
- asyncio.Lock для thread-safety
- 5 новых тестов (cache hit, bypass, failure cache, clear, TTL expiry)
- JSONDecodeError теперь ловится в fetch_weather (был краш при невалидном JSON от API)
- Порывы ветра больше не теряются при отсутствии base wind (gust fallback)
- Устранено дублирование 'м/с' при порывах + отсутствии направления ветра
- Переименован windspeedKmph → wind_speed_mps (ключ хранил м/с, а не км/ч)
- Обновлены тесты, добавлены 6 новых (gust-only, no-duplication, JSONDecodeError)
- высокий: ruff format на 5 файлах
- средний: pyproject.toml, дублирование в news.py, хардкод города,
Scheduler без callback, неверный тест HTTP-ошибки
- низкий: list comprehension в stats.py, дублирование в TextHelpCommand,
try/except в morning.py, файл nul
Точное совпадение (case-insensitive) теперь имеет приоритет над
substring-matching, что исключает ложные совпадения вида
'Heavy rain' внутри 'Heavy rain shower'.
Добавлен root.handlers.clear() перед добавлением новых хендлеров.
Решает проблему накопления StreamHandler/RotatingFileHandler при
повторных вызовах setup_logging().