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
11 KiB
ISSUES — Задачи и баг-трекер
Исправлено
Эмодзи в embed-сообщениях— удалены🌅,✅,❌изutils/morning_runner.pyf-string в logger— замена на%-формат вbot.py— перенесён на уровень модуля вimport timeвнутри__init__bot.pyПроверка наличия—.env.envв.gitignore, есть.env.exampleКоманда— удалена из проекта!msgв BotRunnerОтсутствует— файл существует.gitignoreОтсутствует Dockerfile— файл существуетОтсутствует— файл существует.env.example- Type hints в production-коде — добавлены аннотации ко всем 20 функциям
asyncio.iscoroutinefunctiondeprecated — monkey-patch вbot.py+conftest.py- Утечка корутины Scheduler в тестах — mock
_start_schedulerвместоasyncio.create_task - Graceful shutdown (SIGTERM) — реализован через
on_shutdownlistener +async with self.bot - Пустой
__init__в Morning — удалён - Global RateLimiter на модульном уровне — добавлены factory-функции
make_*_limiter() - Type hints в тестах — добавлены
-> Noneко всем 140 test-функциям importвнутри функций в тестах — вынесены наверх модулей (35 вхождений)- Добавить pre-commit хуки —
.pre-commit-config.yaml(ruff + ruff-format),requirements-dev.txt - Интеграционные тесты — 9 тестов загрузок когов, команд и утилит
format_weather_for_embedотсутствует в коде — заменено наformat_weather_for_messageв README.md (README.md)_WEATHER_MAPPINGне отсортирован по убыванию длины ключей — отсортирован список по убываниюlen(key), добавлен комментарий (utils/pogoda.py)- Глобальные
requests.Sessionне закрываются — добавленаclose_all_sessions()вutils/__init__.py, вызов из_on_shutdownвbot.py run_morningfallback может отправить дайджест в несколько каналов — fallback перебирает каналы целевого сервера вместоbot.get_all_channels()(utils/morning_runner.py)!nw: последовательные вызовы API вместо параллельных — заменено наasyncio.gather()(commands/news.py)format_weather_data_for_consoleвыводитNoneв текст — добавлена явная проверкаis Noneдля всех полей (utils/pogoda.py), обновлён тест (tests/test_commands_pg.py)_parse_dateхрупкий fallback — валидация формата через regex, ISO даты конвертируются в DD.MM.YYYY (utils/news.py)wmo_to_russianсоздаёт dict на каждый вызов — вынесен в константу_WMO_MAPPING(utils/pogoda.py)TextHelpCommandпропускает команды без cog — standalone-команды показываются если не hidden (bot.py)translate_weather(" ")возвращает пробелы — добавлен.strip()перед проверкой (utils/pogoda.py)pressure_to_mmhg(mb: Any)— заменён наfloat | int | str | None(utils/pogoda.py)conftest.pyиbot.pyдублируют monkey-patch — вынесен вutils/compat.py, оба файла импортируют оттудаRateLimiterтесты зависят от реального времени — добавлен_time_funcпараметр, все тесты используют контролируемую функцию времениDockerfileне копируетconftest.py— добавленCOPY conftest.py .requirements.txtбез пиннинга версий —>=заменён на~=(compatible release)- Закомментированный тест
pressure_to_mmhg(0)— удалена устаревшая закомментированная строка format_articles(None)бросаетTypeError— добавлена валидацияNone, graceful fallback с сообщениемsetup_logging()создаёт дублирующиеся handlers — добавленroot.handlers.clear()(utils/logger.py)- Первый
logger.info()теряется —setup_logging()вызывается до первого лога (bot.py) translate_weather()уязвим к ложным substring-совпадениям — точное совпадение приоритизируется (utils/pogoda.py)
Открытые задачи
Критические
— добавленsetup_logging()создаёт дублирующиеся handlersroot.handlers.clear()перед добавлением новых хендлеров (utils/logger.py)Первый—logger.info()теряетсяsetup_logging()перемещён до первогоlogger.info()(bot.py)— добавлена проверка точного совпадения (case-insensitive) перед substring-matching (translate_weather()уязвим к ложным substring-совпадениямutils/pogoda.py)
Средние
— вынесен на уровень модуля (fromstringимпортирован внутри функцииfetch_rssutils/news.py)—Scheduler._start_scheduler()создаёт task синхронно__init__больше не создаёт task;start()стал async-методом (utils/morning_runner.py,bot.py)— удалёнPg.__init__хранитself.api_urlкак инстанс-переменную__init__, используетсяAPI_URL_WEATHERнапрямую (commands/pg.py)— добавлена поддержкаfetch_cat()не передаётx-api-keyCAT_API_KEYиз окружения, заголовокx-api-keyпередаётся при наличии ключа (utils/cat.py)
Низкие
Глобальные экземпляры RateLimiter + factory-функции— дизайн подтверждён: глобальные синглтоны для production, factory-функции для тестов. Добавлен поясняющий комментарий (utils/rate_limiter.py)— удалены 5 декораторов из@pytest.mark.asyncioизбыточенtests/test_integration.py(pytest.iniимеетasyncio_mode = auto)— отклонено: Docker — production-окружение, тесты туда не нужныDockerfileне копируетtests/Приватные атрибуты на объекте бота—START_TIMEвынесен на уровень модуляbot.py,self.bot._schedulerудалён (не использовался). Обновленыcommands/status.pyи тестыИзбыточная проверка— удалены проверкиctxвon_command_errorctx and, так какctxгарантированно передан discord.py (bot.py)
Открытые задачи
Высокий приоритет
— применёнruff format --checkпадает на 5 файлахruff formatк 7 файлам (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)
Средний приоритет
-
Отсутствует
pyproject.toml— проект используетrequirements.txt+requirements-dev.txtбез единого файла конфигурации. Рекомендуетсяpyproject.tomlс[project], настройками ruff и pytest -
commands/news.py— дублирование кода для статей и постов — блоки обработкиarticlesиpostsпочти идентичны (проверкаNone, форматирование, fallback). Вынести в вспомогательную функцию -
Город захардкожен в
API_URL_WEATHER—Magnitogorskв URLwttr.in. При необходимости поддержки других городов потребуется рефакторинг. Минимум — задокументировать ограничение и вынести в env-переменнуюWEATHER_CITY -
Scheduler._taskбезadd_done_callback— если_scheduler_loopзавершится unexpectedly (не черезCancelledError), это не будет залогировано. Добавить callback для логирования нештатного завершения task -
Тест
test_fetch_weather_http_error_no_fallback— raises bareExceptionвместоrequests.HTTPError— в реальностиraise_for_status()бросаетrequests.HTTPError, который ловитсяexcept requests.RequestExceptionи корректно переходит на fallback. Тест проверяет несуществующий сценарий
Низкий приоритет
-
commands/stats.py— list comprehension вместо generator —len([ch for ch in guild.channels if ...])создаёт временный список. Заменить наsum(1 for ch in guild.channels if ...) -
TextHelpCommand.send_bot_help()— дублирование логики — веткиif cog_or_none is Noneиelseделают одинаковую работу по итерации команд. Объединить в общий цикл -
commands/morning.pyне ловит исключенияrun_morning— еслиrun_morningвыбросит, лог!morning завершенне запишется, а ошибка уйдёт вon_command_error. Добавитьtry/exceptдля локальной обработки и логирования -
Файл
nulв корне проекта — артефакт Windows (29 байт). Удалить из рабочей директории