- test_fetch_cat.py: 10 тестов (def → async def, asyncio.run → await)
- test_fetch_rss.py: 21 тест (def → async def, asyncio.run → await)
- test_fetch_weather.py: 19 тест (def → async def, asyncio.run → await)
- Удалён лишний import asyncio из тестовых файлов
- Больше не создаётся новый event loop на каждый тест
- RateLimiter (asyncio.Lock) теперь корректно работает в одном loop
230 тестов проходят.
- Добавлена проверка if self.bot.cogs: return перед добавлением cogs
- on_ready может сработать несколько раз при reconnect gateway
- Без защиты команды регистрировались бы заново каждый раз
230 тестов проходят.
- Заменён dict на _WEATHER_MAPPING (list of tuples, отсортирован по длине ключей)
- Длинные фразы проверяются первыми, исключая ложные подстроочные совпадения
- "Moderate or heavy rain at times" теперь корректно -> "Дождь" вместо "Сильный дождь"
- Обновлены тесты: test_translate_known и test_translate_longer_key_priority
230 тестов проходят.
- Защита от пустого списка [] и пустого dict [{}] в current_condition
- Возврат None вместо краша, команда !pg показывает fallback-сообщение
- Обновлён тест test_pg_empty_current_condition (graceful fallback вместо IndexError)
230 тестов проходят.
- Удалён dead code except KeyboardInterrupt (никогда не срабатывал в bot.run())
- Добавлен _signal_handler() для SIGINT/SIGTERM с остановкой scheduler и bot.close()
- Заменён bot.run(token) на asyncio.run(main()) с async with self.bot:
- Добавлен reconnect=True для устойчивости к разрывам gateway
- Тесты: string-matching заменены на поведенческие mock-тесты (5 тестов, все OK)
- Добавлен CODE_REVIEW.md с результатами ревью
- Scheduler больше не опрашивает каждую секунду (tasks.loop мог пропустить
момент срабатывания из-за неточности тайминга). Теперь спит ровно до
целевого времени через asyncio.sleep, затем запускает morning и повторяет.
- Добавлено логирование ожидания и срабатывания расписания.
- Перенес инициализацию планировщика из on_ready в on_guild_available —
гарантирует, что кэш гильдии загружен до запуска Scheduler.
- Обновлены тесты под новый Scheduler (asyncio.create_task вместо tasks.loop).
- README.md: исправлены пути admin.py → console_commands/admin.py для docker exec.
- docker-compose.yml: добавлены переменные LOG_LEVEL и rate-limit конфиги.
- console_commands/__init__.py: переименованы help → console_help,
reload → reload_cogs (избежал конфликта с built-in и уточнил имена).
guild.channels содержит все типы включая CategoryChannel.
Категории — это контейнеры для группировки, а не каналы.
Изменено:
- commands/stats.py: filter по isinstance(CategoryChannel)
- console_commands/stats.py: аналогичный фильтр
- test_commands_stats.py: тест test_stats_excludes_categories
- Итого: 234 теста
Проблема: _start_time хранился в Status Cog, но консольная
команда искала его на объекте bot — всегда получала fallback
time.time() и показывала 0с.
Решение: _start_time устанавливается в BotRunner.__init__ на
объекте bot. Cog и console_command читают getattr(bot, '_start_time').
Изменено: bot.py, commands/status.py, console_commands/status.py,
tests/test_commands_status.py
- commands/help.py: список команд генерируется автоматически из
ctx.bot.commands с описаниями из docstring
- tests/test_help_discord.py: добавлен _make_mock_command() и мок
ctx.bot.commands для тестов
- ctx.command.name: добавлена проверка ctx.command на None
- ctx.interaction: добавлен hasattr() — атрибута нет у commands.Context
(текстовые команды !prefix), что вызывало AttributeError
- utils/pogoda.py: добавлена API_URL_WEATHER, format_weather_for_embed(),
проверка None в format_weather_data_for_console()
- utils/morning_runner.py: вынесен MorningData (dataclass) и gather_morning();
run_morning() использует их вместо ручного asyncio.gather
- utils/__init__.py: экспортирован публичный API (__all__)
- commands/pg.py: убран ручной парсинг погоды, используется
format_weather_data_for_console()
- console_commands/morning.py: дубликат asyncio.gather заменён на gather_morning()
- console_commands/pogoda.py: хардкод URL заменён на API_URL_WEATHER
- console_commands/cat.py: заглушка заменена на рабочий вызов fetch_cat()
- tests/test_commands_pg.py: обновлён тест fetch_returns_none (бот теперь
отправляет сообщение об ошибке вместо молчаливого возврата)
- Убран discord.Embed в пользу простого текста без timestamp ошибки
- Добавлены разделители = вокруг заголовка
- Создан tests/test_help_discord.py с 2 тестами для Discord команды
- Создан tests/test_help_console.py с 2 тестами для консольной команды
- Закрыто: AttributeError 'Message' object has no attribute 'timestamp'