From 47e4b6011108f86f33201ebef098bf40ddd7821d Mon Sep 17 00:00:00 2001 From: deadzilla Date: Tue, 9 Jun 2026 21:37:07 +0500 Subject: [PATCH] =?UTF-8?q?docs:=20=D1=81=D0=B8=D0=BD=D1=85=D1=80=D0=BE?= =?UTF-8?q?=D0=BD=D0=B8=D0=B7=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20?= =?UTF-8?q?ISSUES.md,=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=B8=D1=82=D1=8C?= =?UTF-8?q?=20README.md,=20=D0=BE=D1=87=D0=B8=D1=81=D1=82=D0=B8=D1=82?= =?UTF-8?q?=D1=8C=20AGENTS.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ISSUES.md: закрыто 7 задач с ссылками на коммиты (on_command_error, !hp харкод, харкод URL, utils/__init__.py, print→logging, автогенерация !hp, дублирование команд, healthcheck) - AGENTS.md: удалена пустая секция 'Структура проекта' (есть в README.md) - README.md: обновлена архитектура (добавлены utils/__init__.py, utils/morning_runner.py, console_commands/help.py, Docker-файлы), исправлено кол-во тестов (262→204), добавлена секция 'Запуск в Docker', убрана ссылка на AGENTS.md как основной документ, добавлена консольная команда help, обновлены таблицы утилит --- AGENTS.md | 4 +-- ISSUES.md | 29 +++++++++++++-------- README.md | 77 ++++++++++++++++++++++++++++++++++++++++--------------- 3 files changed, 77 insertions(+), 33 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index a71ab68..279480b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -52,6 +52,4 @@ model_requirements: - Используй type hints для всех функций - Документируй публичные методы через docstrings - Следуй PEP 8 -- Используй f-строки вместо конкатенации - -### Структура проекта \ No newline at end of file +- Используй f-строки вместо конкатенации \ No newline at end of file diff --git a/ISSUES.md b/ISSUES.md index 045b9b2..949454a 100644 --- a/ISSUES.md +++ b/ISSUES.md @@ -2,10 +2,14 @@ ## Баги -- [ ] `on_command_error`: проверка `ctx.interaction` может падать — при текстовых командах (`command_prefix`) `ctx.interaction` может быть `None` -- [ ] `commands/help.py`: список команд хардкодится вручную — при добавлении новой команды `!hp` покажет устаревший список -- [ ] `console_commands/pogoda.py`: хардкодит URL `wttr.in`, дублируя логику из `utils/pogoda.py` -- [ ] `utils/pogoda.py` + `utils/cat.py`: нет отдельного модуля `utils/__init__.py` с публичным API — импорты разбросаны +- [x] `on_command_error`: проверка `ctx.interaction` может падать — при текстовых командах (`command_prefix`) `ctx.interaction` может быть `None` + - **Закрыто:** коммит `d698380` — добавлен `hasattr(ctx, 'interaction')` и проверка `ctx.command` на `None` +- [x] `commands/help.py`: список команд хардкодился вручную — при добавлении новой команды `!hp` показывал устаревший список + - **Закрыто:** коммит `2690ee7` — собирает команды автоматически из `ctx.bot.commands` +- [x] `console_commands/pogoda.py`: хардкодил URL `wttr.in`, дублируя логику из `utils/pogoda.py` + - **Закрыто:** коммит `560dc55` — использует `API_URL_WEATHER` из `utils.pogoda` +- [x] `utils/pogoda.py` + `utils/cat.py`: нет отдельного модуля `utils/__init__.py` с публичным API — импорты разбросаны + - **Закрыто:** коммит `560dc55` — создан `utils/__init__.py` с `__all__` и явными импортами --- @@ -13,9 +17,12 @@ ### Высокий приоритет -- [ ] **Заменить все `print()` на `logging`** — в `utils/pogoda.py`, `utils/morning_runner.py`, `console_commands/`, `bot.py` -- [ ] **Автоматическая генерация `!hp`** — собирать список команд из `bot.commands` вместо хардкода -- [ ] **Убрать дублирование `commands/` и `console_commands/`** — вынести общую логику в `utils/`, оставить тонкие обёртки +- [x] **Заменить все `print()` на `logging`** — в `utils/pogoda.py`, `utils/morning_runner.py`, `console_commands/`, `bot.py` + - **Закрыто:** коммит `52fdbc3` — системные сообщения (startup, shutdown, retry, ошибки API) переведены на `logging`; `print()` оставлены в `console_commands/` как пользовательский вывод в терминал +- [x] **Автоматическая генерация `!hp`** — собирать список команд из `bot.commands` вместо хардкода + - **Закрыто:** коммит `2690ee7` +- [x] **Убрать дублирование `commands/` и `console_commands/`** — вынести общую логику в `utils/`, оставить тонкие обёртки + - **Закрыто:** коммит `560dc55` — `format_weather_data_for_console()`, `gather_morning()`, `utils/__init__.py` - [ ] **Валидация конфигурации** — проверить формат `MORNING_TIME` (`ЧЧ:ММ`) и наличие `MORNING_CHANNEL_ID` при запуске ### Средний приоритет @@ -28,9 +35,11 @@ ### Низкий приоритет -- [ ] **Улучшить Dockerfile** — multi-stage сборка, healthcheck +- [ ] **Улучшить Dockerfile** — multi-stage сборка +- [x] **Добавить healthcheck** — в Dockerfile + - **Закрыто:** healthcheck присутствует в Dockerfile (`CMD python -c "import discord; print('Bot is running')"`), добавлен коммитом `7bfb96c` - [ ] **Добавить pre-commit хуки** — lint (flake8/ruff), форматирование (black) -- [ ] **Добавить type hints** повсеместно — не все функции имеют аннотации +- [ ] **Добавить type hints** повсеместно — не все функции имеют аннотации (отсутствуют в `utils/pogoda.py`, `utils/news.py`, присутствуют в `utils/cat.py`, `utils/morning_runner.py`) - [ ] **Интеграционные тесты** — сейчас только unit-тесты с моками --- @@ -38,4 +47,4 @@ ## Замечания - [ ] `README.md` ссылается на `AGENTS.md` как основной документ проекта, но AGENTS.md — инструкции для AI-ассистента -- [ ] В тестовых файлах используется `asyncio.run()` внутри синхронных тестов — может конфликтовать с event loop +- [ ] В тестовых файлах используется `asyncio.run()` внутри синхронных тестов — может конфликтовать с event loop (подтверждено: 50+ вхождений в `test_fetch_cat.py`, `test_fetch_rss.py`, `test_fetch_weather.py`) diff --git a/README.md b/README.md index b50ed30..47907c3 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,6 @@ Discord-бот для Магнитогорска. Команды погоды, новостей, котиков и утреннего дайджеста. -## 📖 Документация - -Основной документ проекта — [`AGENTS.md`](./AGENTS.md). Содержит детальные инструкции по архитектуре, командам и работе с ботом. - ## Установка ```bash @@ -39,8 +35,8 @@ python bot.py | Команда | Описание | |---------|----------| | `!pg` | Прогноз погоды для Магнитогорска | -| `!nw` | Топ-5 свежих статей по AI с Habr | -| `!hp` | Список всех команд бота с описанием | +| `!nw` | Топ-5 статей и топ-5 новостей по AI с Habr | +| `!hp` | Список всех команд бота с описанием (автогенерация из `bot.commands`) | | `!morning` | Погода + топ-5 статей + топ-5 новостей + котик (утренний дайджест) | | `!cat` | Случайный котик | | `!msg <текст>` | Повторить текст в чате | @@ -53,19 +49,22 @@ python bot.py | 2 | `pogoda` | Прогноз погоды для Магнитогорска | | 3 | `morning` | Погода + топ-5 статей + топ-5 новостей + котик | | 4 | `cat` | Вывести URL случайного котика | +| 5 | `help` | Показать список всех команд | | 0 | `stop` | Остановка бота | +> Номера команд генерируются автоматически из `ALL_CONSOLE_COMMANDS` в порядке определения в `console_commands/__init__.py`. + ## Архитектура ``` bot.py # Точка входа, инициализация бота, console_input() commands/ # Discord команды (cogs) __init__.py # ALL_COMMANDS — явные импорты - pg.py # !pg — погода с retry + fallback - news.py # !nw — новости с Habr + pg.py # !pg — погода (обёртка над utils.pogoda) + news.py # !nw — статьи + новости с Habr cat.py # !cat — случайный котик - morning.py # !morning — утренний дайджест - help.py # !hp — список команд + morning.py # !morning — утренний дайджест (обёртка над utils.morning_runner) + help.py # !hp — список команд (автогенерация из bot.commands) console_commands/ # Консольные команды __init__.py # ALL_CONSOLE_COMMANDS — явные импорты stop.py # stop — остановка бота @@ -73,23 +72,29 @@ console_commands/ # Консольные команды pogoda.py # pogoda — погода в терминале morning.py # morning — утренний дайджест в терминале cat.py # cat — вывод URL котика + help.py # help — список всех команд utils/ # Утилиты (API-клиенты, конвертации) - pogoda.py # fetch_weather(), fetch_open_meteo(), wmo_to_russian(), translate_weather(), pressure_to_mmhg(), format_weather_data_for_console() - news.py # fetch_rss(), format_articles(), truncate_title(), parse_date() + __init__.py # __all__ — публичный API утилит + pogoda.py # fetch_weather(), fetch_open_meteo(), wmo_to_russian(), translate_weather(), pressure_to_mmhg(), format_weather_data_for_console(), format_weather_for_embed() + news.py # fetch_rss(), format_articles(), truncate_title() cat.py # fetch_cat() + morning_runner.py # Scheduler, MorningData, gather_morning(), run_morning() tests/ # pytest-тесты test_pogoda.py # translate_weather, pressure_to_mmhg, wmo_to_russian, format_weather_data_for_console test_fetch_cat.py # fetch_cat test_fetch_rss.py # fetch_rss test_fetch_weather.py # fetch_weather, fetch_open_meteo - test_format_articles.py # truncate_title, parse_date, format_articles + test_format_articles.py # truncate_title, _parse_date, format_articles test_commands_pg.py # Pg cog test_bot.py # инициализация бота test_morning_runner.py# тесты morning runner-а - test_help_discord.py # команда !hp — проверка формата вывода и контента (2 теста) - test_help_console.py # консольная help — проверка списка команд (2 теста) + test_help_discord.py # команда !hp — проверка формата вывода и контента + test_help_console.py # консольная help — проверка списка команд ISSUES.md # Задачи и баг-трекер проекта -pytest.ini # Конфигурация pytest +pytest.ini # Конфигурация pytest (asyncio_mode = auto) +Dockerfile # Сборка образа бота (Python 3.14-slim, healthcheck) +docker-compose.yml # Запуск бота в Docker +.dockerignore # Исключения для Docker-контекста ``` ### Добавление Discord команды @@ -118,12 +123,35 @@ python -m pytest tests/ -v | `test_fetch_cat.py` | `fetch_cat()` | 10 | | `test_fetch_rss.py` | `fetch_rss()` | 20 | | `test_fetch_weather.py` | `fetch_weather()`, `fetch_open_meteo()` | 20 | -| `test_format_articles.py` | `truncate_title()`, `parse_date()`, `format_articles()` | 24 | +| `test_format_articles.py` | `truncate_title()`, `_parse_date()`, `format_articles()` | 24 | | `test_commands_pg.py` | `Pg` cog, команда `!pg` | 13 | | `test_bot.py` | инициализация бота | 7 | | `test_morning_runner.py` | morning runner-а | 68 | +| `test_help_discord.py` | команда `!hp` | 2 | +| `test_help_console.py` | консольная `help` | 2 | -**Итого: 262 теста (4 новых для help).** +**Итого: 204 теста.** + +## Запуск в Docker + +### Сборка и запуск + +```bash +docker-compose up --build +``` + +Передайте токен через переменную окружения: + +```bash +DISCORD_TOKEN=ваш_токен docker-compose up +``` + +### Особенности + +- База: `python:3.14-slim` +- Healthcheck: проверка каждые 30 сек (старт-период 60 сек) +- Консольный ввод отключён в Docker (stdin недоступен) +- Версия Python настраивается через `ARG PYTHON_VERSION` ## API и внешние сервисы @@ -200,7 +228,7 @@ pytest-asyncio>=0.21.0 Заголовки обрезаются до 60 символов с суффиксом `...`. -Ссылки отображаются без `<>` и `https://` префикса для предотвращения embed-превью в Discord. +Ссылки отображаются в виде `` для предотвращения embed-превью в Discord. ## Основные функции утилит @@ -214,13 +242,13 @@ pytest-asyncio>=0.21.0 | `translate_weather()` | Перевод погодных описаний на русский язык | | `pressure_to_mmhg()` | Конвертация давления из hPa в мм рт. ст. | | `format_weather_data_for_console()` | Форматирование данных погоды для вывода в консоль | +| `format_weather_for_embed()` | Форматирование погоды для Discord embed (с заголовком) | ### utils/news.py | Функция | Описание | |---------|----------| | `fetch_rss()` | Получение RSS ленты (статьи или новости) | -| `parse_date()` | Парсинг даты из RSS | | `truncate_title()` | Обрезка заголовка до заданной длины | | `format_articles()` | Форматирование списка статей для вывода | @@ -229,3 +257,12 @@ pytest-asyncio>=0.21.0 | Функция | Описание | |---------|----------| | `fetch_cat()` | Получение URL случайного котика | + +### utils/morning_runner.py + +| Функция / Класс | Описание | +|----------------|----------| +| `MorningData` | dataclass с полями weather, articles, posts, cat_url | +| `gather_morning()` | Параллельный сбор всех данных для дайджеста | +| `run_morning()` | Формирование и отправка embed в канал Discord | +| `Scheduler` | Планировщик ежедневных задач (discord.ext.tasks.loop) |