deadzilla 071e313015 refactor: инкапсулировать глобальные переменные в BotRunner + валидация конфига
- bot.py: создан класс BotRunner (bot, stop_event, bot_ready, scheduler)
- bot.py: добавлена _validate_config() — проверка MORNING_TIME (ЧЧ:ММ) и MORNING_CHANNEL_ID (int)
- bot.py: убраны все глобальные переменные
- Dockerfile: healthcheck через ps aux (проверка процесса python bot.py)
- docker-compose.yml: добавлен MORNING_CHANNEL_ID
- ISSUES.md: закрыто 3 задачи (валидация конфига, инкапсуляция, multi-stage)
- tests/test_bot.py: адаптирован тест под BotRunner
2026-06-09 23:09:02 +05:00

Discord Bot

Discord-бот для Магнитогорска. Команды погоды, новостей, котиков и утреннего дайджеста.

Установка

pip install -r requirements.txt

Запуск

python bot.py

Введите номер команды в терминале или !команда в Discord.

Настройка

  1. Скопируйте .env.example в .env:

    cp .env.example .env
    
  2. Вставьте токен бота в .env:

    DISCORD_TOKEN=ваш_токен
    

Токен получите на Discord Developer Portal.

Команды Discord

Команда Описание
!pg Прогноз погоды для Магнитогорска
!nw Топ-5 статей и топ-5 новостей по AI с Habr
!hp Список всех команд бота с описанием (автогенерация из bot.commands)
!morning Погода + топ-5 статей + топ-5 новостей + котик (утренний дайджест)
!cat Случайный котик
!msg <текст> Повторить текст в чате

Команды терминала

Номер Команда Описание
1 news Топ-5 статей + топ-5 новостей с Habr
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 — погода (обёртка над utils.pogoda)
  news.py               # !nw — статьи + новости с Habr
  cat.py                # !cat — случайный котик
  morning.py            # !morning — утренний дайджест (обёртка над utils.morning_runner)
  help.py               # !hp — список команд (автогенерация из bot.commands)
console_commands/       # Консольные команды
  __init__.py           # ALL_CONSOLE_COMMANDS — явные импорты
  stop.py               # stop — остановка бота
  news.py               # news — новости с Habr
  pogoda.py             # pogoda — погода в терминале
  morning.py            # morning — утренний дайджест в терминале
  cat.py                # cat — вывод URL котика
  help.py               # help — список всех команд
utils/                  # Утилиты (API-клиенты, конвертации)
  __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_commands_pg.py   # Pg cog
  test_bot.py           # инициализация бота
  test_morning_runner.py# тесты morning runner-а
  test_help_discord.py  # команда !hp — проверка формата вывода и контента
  test_help_console.py  # консольная help — проверка списка команд
ISSUES.md               # Задачи и баг-трекер проекта
pytest.ini              # Конфигурация pytest (asyncio_mode = auto)
Dockerfile              # Сборка образа бота (Python 3.14-slim, healthcheck)
docker-compose.yml      # Запуск бота в Docker
.dockerignore           # Исключения для Docker-контекста

Добавление Discord команды

  1. Создать файл commands/имя.py с классом, наследующим commands.Cog
  2. Добавить импорт в commands/__init__.py
  3. Добавить класс в ALL_COMMANDS

Добавление консольной команды

  1. Создать файл console_commands/имя.py с функцией func(stop_event, bot)
  2. Добавить импорт в console_commands/__init__.py
  3. Добавить функцию в ALL_CONSOLE_COMMANDS

Запуск тестов

python -m pytest tests/ -v

Структура тестов

Файл Что тестирует Кол-во
test_pogoda.py translate_weather(), pressure_to_mmhg(), wmo_to_russian(), format_weather_data_for_console() 93
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_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

Итого: 204 теста.

Запуск в Docker

Сборка и запуск

docker-compose up --build

Передайте токен через переменную окружения:

DISCORD_TOKEN=ваш_токен docker-compose up

Особенности

  • База: python:3.14-slim
  • Healthcheck: проверка каждые 30 сек (старт-период 60 сек)
  • Консольный ввод отключён в Docker (stdin недоступен)
  • Версия Python настраивается через ARG PYTHON_VERSION

API и внешние сервисы

Погода (!pg, !morning)

  • Основной: wttr.in/Magnitogorsk (бесплатный, без ключа)
  • Fallback: api.open-meteo.com (бесплатный, без ключа)
  • Retry: 3 попытки с экспоненциальной задержкой при SSL/Connection/Timeout ошибках
  • Fallback срабатывает автоматически при неуспешных попытках
  • WMO weather codes → русский перевод в wmo_to_russian()

Конвертации

  • Давление: hPa → мм рт. ст. (* 0.750062)
  • Ветер: км/ч → м/с (/ 3.6)
  • Погодные описания: английский → русский (translate_weather())

Новости (!nw, !morning)

  • Articles: https://habr.com/ru/rss/hubs/artificial_intelligence/articles/top/daily/?fl=ru
  • News: https://habr.com/ru/rss/hubs/artificial_intelligence/news/top/daily/?fl=ru
  • Парсинг RSS 2.0 и Atom форматов
  • Извлечение ссылок из <guid isPermaLink="true"> и авторов из <dc:creator>
  • Формат вывода: заголовок → дата → ссылка

Котики (!cat, !morning)

  • API: https://api.thecatapi.com/v1/images/search
  • Картинка встраивается в Discord Embed

Структура данных погоды

Команда !pg возвращает:

Температура: X°C (ощущается как Y°C)
Описание: Z
Влажность: X%
Ветер: X м/с
Давление: X мм рт. ст.

Формат дат

Даты форматируются как дд.мм.гггг через datetime.strptime с форматом %a, %d %b %Y %H:%M:%S %z.

Конфигурация

Переменная Описание Где взять
DISCORD_TOKEN Токен бота Discord Developer Portal
MORNING_TIME Время запуска утреннего дайджеста .env (формат ЧЧ:ММ, по умолчанию 07:00)
MORNING_CHANNEL_ID ID канала для утреннего дайджеста Правый клик по каналу → Копировать ID

Зависимости

discord.py>=2.3.2
python-dotenv>=1.0.0
requests>=2.31.0
pytest>=7.4.0
pytest-asyncio>=0.21.0

Безопасность

  • .env в .gitignore — токен никогда не должен попадать в репозиторий
  • Используйте .env.example как шаблон

Формат новостей

Каждая новость выводится в формате:

Заголовок статьи
   дд.мм.гггг   https://habr.com/ru/articles/...

Заголовки обрезаются до 60 символов с суффиксом ....

Ссылки отображаются в виде <url> для предотвращения embed-превью в Discord.

Основные функции утилит

utils/pogoda.py

Функция Описание
fetch_weather() Основная функция получения погоды с wttr.in
fetch_open_meteo() Fallback при ошибках основного API
wmo_to_russian() Перевод WMO кодов погоды в русское описание
translate_weather() Перевод погодных описаний на русский язык
pressure_to_mmhg() Конвертация давления из hPa в мм рт. ст.
format_weather_data_for_console() Форматирование данных погоды для вывода в консоль
format_weather_for_embed() Форматирование погоды для Discord embed (с заголовком)

utils/news.py

Функция Описание
fetch_rss() Получение RSS ленты (статьи или новости)
truncate_title() Обрезка заголовка до заданной длины
format_articles() Форматирование списка статей для вывода

utils/cat.py

Функция Описание
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)
Description
Бот анонсер начала дня. Погода + новости + отельный команды.
Readme 546 KiB
Languages
Python 99.4%
Dockerfile 0.6%