discordBot/ISSUES.md

71 lines
7.8 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 с сообщением
- [x] **`setup_logging()` создаёт дублирующиеся handlers** — добавлен `root.handlers.clear()` (`utils/logger.py`)
- [x] **Первый `logger.info()` теряется**`setup_logging()` вызывается до первого лога (`bot.py`)
- [x] **`translate_weather()` уязвим к ложным substring-совпадениям** — точное совпадение приоритизируется (`utils/pogoda.py`)
---
## Открытые задачи
### Критические
- [x] ~~**`setup_logging()` создаёт дублирующиеся handlers**~~ — добавлен `root.handlers.clear()` перед добавлением новых хендлеров (`utils/logger.py`)
- [x] ~~**Первый `logger.info()` теряется**~~`setup_logging()` перемещён до первого `logger.info()` (`bot.py`)
- [x] ~~**`translate_weather()` уязвим к ложным substring-совпадениям**~~ — добавлена проверка точного совпадения (case-insensitive) перед substring-matching (`utils/pogoda.py`)
### Средние
- [x] ~~**`fromstring` импортирован внутри функции `fetch_rss`**~~ — вынесен на уровень модуля (`utils/news.py`)
- [x] ~~**`Scheduler._start_scheduler()` создаёт task синхронно**~~`__init__` больше не создаёт task; `start()` стал async-методом (`utils/morning_runner.py`, `bot.py`)
- [x] ~~**`Pg.__init__` хранит `self.api_url` как инстанс-переменную**~~ — удалён `__init__`, используется `API_URL_WEATHER` напрямую (`commands/pg.py`)
- [x] ~~**`fetch_cat()` не передаёт `x-api-key`**~~ — добавлена поддержка `CAT_API_KEY` из окружения, заголовок `x-api-key` передаётся при наличии ключа (`utils/cat.py`)
### Низкие
- [ ] **Глобальные экземпляры 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)