discordBot/ISSUES.md

67 lines
7.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ISSUES — Задачи и баг-трекер
---
## Исправлено
- [x] ~~Эмодзи в embed-сообщениях~~ — удалены `🌅`, `✅`, `❌` из `utils/morning_runner.py`
- [x] ~~f-string в logger~~ — замена на `%`-формат в `bot.py`
- [x] ~~`import time` внутри `__init__`~~ — перенесён на уровень модуля в `bot.py`
- [x] ~~Проверка наличия `.env`~~`.env` в `.gitignore`, есть `.env.example`
- [x] ~~Команда `!msg` в BotRunner~~ — удалена из проекта
- [x] ~~Отсутствует `.gitignore`~~ — файл существует
- [x] ~~Отсутствует Dockerfile~~ — файл существует
- [x] ~~Отсутствует `.env.example`~~ — файл существует
- [x] **Type hints в production-коде** — добавлены аннотации ко всем 20 функциям
- [x] **`asyncio.iscoroutinefunction` deprecated** — monkey-patch в `bot.py` + `conftest.py`
- [x] **Утечка корутины Scheduler в тестах** — mock `_start_scheduler` вместо `asyncio.create_task`
- [x] **Graceful shutdown (SIGTERM)** — реализован через `on_shutdown` listener + `async with self.bot`
- [x] **Пустой `__init__` в Morning** — удалён
- [x] **Global RateLimiter на модульном уровне** — добавлены factory-функции `make_*_limiter()`
- [x] **Type hints в тестах** — добавлены `-> None` ко всем 140 test-функциям
- [x] **`import` внутри функций в тестах** — вынесены наверх модулей (35 вхождений)
- [x] **Добавить pre-commit хуки**`.pre-commit-config.yaml` (ruff + ruff-format), `requirements-dev.txt`
- [x] **Интеграционные тесты** — 9 тестов загрузок когов, команд и утилит
- [x] **`format_weather_for_embed` отсутствует в коде** — заменено на `format_weather_for_message` в README.md (`README.md`)
- [x] **`_WEATHER_MAPPING` не отсортирован по убыванию длины ключей** — отсортирован список по убыванию `len(key)`, добавлен комментарий (`utils/pogoda.py`)
- [x] **Глобальные `requests.Session` не закрываются** — добавлена `close_all_sessions()` в `utils/__init__.py`, вызов из `_on_shutdown` в `bot.py`
- [x] **`run_morning` fallback может отправить дайджест в несколько каналов** — fallback перебирает каналы целевого сервера вместо `bot.get_all_channels()` (`utils/morning_runner.py`)
- [x] **`!nw`: последовательные вызовы API вместо параллельных** — заменено на `asyncio.gather()` (`commands/news.py`)
- [x] **`format_weather_data_for_console` выводит `None` в текст** — добавлена явная проверка `is None` для всех полей (`utils/pogoda.py`), обновлён тест (`tests/test_commands_pg.py`)
- [x] **`_parse_date` хрупкий fallback** — валидация формата через regex, ISO даты конвертируются в DD.MM.YYYY (`utils/news.py`)
- [x] **`wmo_to_russian` создаёт dict на каждый вызов** — вынесен в константу `_WMO_MAPPING` (`utils/pogoda.py`)
- [x] **`TextHelpCommand` пропускает команды без cog** — standalone-команды показываются если не hidden (`bot.py`)
- [x] **`translate_weather(" ")` возвращает пробелы** — добавлен `.strip()` перед проверкой (`utils/pogoda.py`)
- [x] **`pressure_to_mmhg(mb: Any)`** — заменён на `float | int | str | None` (`utils/pogoda.py`)
- [x] **`conftest.py` и `bot.py` дублируют monkey-patch** — вынесен в `utils/compat.py`, оба файла импортируют оттуда
- [x] **`RateLimiter` тесты зависят от реального времени** — добавлен `_time_func` параметр, все тесты используют контролируемую функцию времени
- [x] **`Dockerfile` не копирует `conftest.py`** — добавлен `COPY conftest.py .`
- [x] **`requirements.txt` без пиннинга версий** — `>=` заменён на `~=` (compatible release)
- [x] **Закомментированный тест `pressure_to_mmhg(0)`** — удалена устаревшая закомментированная строка
- [x] **`format_articles(None)` бросает `TypeError`** — добавлена валидация `None`, graceful fallback с сообщением
---
## Открытые задачи
### Критические
- [ ] **`setup_logging()` создаёт дублирующиеся handlers** — каждый вызов добавляет новые `StreamHandler` и `RotatingFileHandler` к root-логгеру без проверки (`utils/logger.py`, строки 30-39)
- [ ] **Первый `logger.info()` теряется**`"=== Запуск Discord бота ==="` вызван до `setup_logging()`, у root-логгера нет handlers (`bot.py`, строка 196)
- [ ] **`translate_weather()` уязвим к ложным substring-совпадениям** — `if key.lower() in en_lower` может вернуть неверный перевод (например, `"Heavy rain"` совпадёт в `"Heavy rain shower"` раньше, чем точный ключ) (`utils/pogoda.py`)
### Средние
- [ ] **`fromstring` импортирован внутри функции `fetch_rss`** — `from defusedxml.ElementTree import fromstring` на строке 24, скрывает зависимость от линтеров и добавляет оверхед (`utils/news.py`)
- [ ] **`Scheduler._start_scheduler()` создаёт task синхронно** — `asyncio.create_task()` в `__init__` зависит от активного event loop неявно (`utils/morning_runner.py`, строка 119)
- [ ] **`Pg.__init__` хранит `self.api_url` как инстанс-переменную** — копия константы `API_URL_WEATHER` без необходимости (`commands/pg.py`, строки 13-14)
- [ ] **`fetch_cat()` не передаёт `x-api-key`** — TheCatAPI требует/рекомендует заголовок `x-api-key`, без него запросы могут быть ограничены (`utils/cat.py`, строка 15)
### Низкие
- [ ] **Глобальные экземпляры RateLimiter + factory-функции** — factory-функции `make_*_limiter()` существуют, но production-код импортирует глобальные переменные напрямую (`utils/rate_limiter.py`, строки 94-97)
- [ ] **`@pytest.mark.asyncio` избыточен** — `pytest.ini` уже содержит `asyncio_mode = auto` (`tests/test_integration.py`)
- [ ] **`Dockerfile` не копирует `tests/`** — нельзя запустить `pytest` внутри контейнера, затрудняет отладку в Docker
- [ ] **Приватные атрибуты на объекте бота**`self.bot._start_time` и `self.bot._scheduler` нарушают инкапсуляцию (`bot.py`, строки 116, 148)
- [ ] **Избыточная проверка `ctx` в `on_command_error`**`ctx` всегда передан и не может быть `None` (`bot.py`, строки 138-143)