From 65e01f009199d682dd993655eec373dce053b43b Mon Sep 17 00:00:00 2001 From: deadzilla Date: Tue, 7 Jul 2026 23:17:25 +0500 Subject: [PATCH] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20type=20hints=20=D0=BA=D0=BE=20=D0=B2=D1=81=D0=B5?= =?UTF-8?q?=D0=BC=2020=20production-=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8?= =?UTF-8?q?=D1=8F=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- commands/cat.py | 2 +- commands/help.py | 2 +- commands/morning.py | 2 +- commands/news.py | 2 +- commands/pg.py | 2 +- commands/stats.py | 2 +- commands/status.py | 2 +- utils/morning_runner.py | 6 +++--- utils/news.py | 9 +++++---- utils/pogoda.py | 16 +++++++++------- 10 files changed, 24 insertions(+), 21 deletions(-) diff --git a/commands/cat.py b/commands/cat.py index 5166a39..8e98043 100644 --- a/commands/cat.py +++ b/commands/cat.py @@ -11,7 +11,7 @@ class Cat(commands.Cog): """Команда !cat — случайный котик""" @commands.command(name="cat") - async def cat(self, ctx): + async def cat(self, ctx: commands.Context) -> None: """Получить случайного котика""" url = await fetch_cat() if url is None: diff --git a/commands/help.py b/commands/help.py index 502652d..bbc031a 100644 --- a/commands/help.py +++ b/commands/help.py @@ -6,7 +6,7 @@ class Help(commands.Cog): """Команда !hp — список всех команд бота""" @commands.command(name="hp") - async def hp(self, ctx): + async def hp(self, ctx: commands.Context) -> None: """Показать список доступных команд""" await self._show_help(ctx) diff --git a/commands/morning.py b/commands/morning.py index 1bf08e9..dcaa926 100644 --- a/commands/morning.py +++ b/commands/morning.py @@ -14,7 +14,7 @@ class Morning(commands.Cog): pass @commands.command(name="morning") - async def morning(self, ctx): + async def morning(self, ctx: commands.Context) -> None: """Погода, лучшие статьи за сутки и котик""" logger.info("%s: !morning запущен", ctx.author) await run_morning(ctx.bot, ctx.channel) diff --git a/commands/news.py b/commands/news.py index ff673fd..726f3ec 100644 --- a/commands/news.py +++ b/commands/news.py @@ -16,7 +16,7 @@ class News(commands.Cog): """Команда !news — свежие статьи и новости по AI с Habr""" @commands.command(name="nw") - async def nw(self, ctx): + async def nw(self, ctx: commands.Context) -> None: """Топ-5 свежих статей и новостей по AI с Habr""" articles = await fetch_rss(RSS_URL_ARTICLES) if articles is None: diff --git a/commands/pg.py b/commands/pg.py index 1613a49..7df8137 100644 --- a/commands/pg.py +++ b/commands/pg.py @@ -12,7 +12,7 @@ class Pg(commands.Cog): self.api_url = API_URL_WEATHER @commands.command(name="pg") - async def pg(self, ctx): + async def pg(self, ctx: commands.Context) -> None: """Прогноз погоды в Магнитогорске""" data = await fetch_weather(self.api_url) if data is None: diff --git a/commands/stats.py b/commands/stats.py index d62661f..5aece5a 100644 --- a/commands/stats.py +++ b/commands/stats.py @@ -9,7 +9,7 @@ class Stats(commands.Cog): """Команда !stats — статистика серверов""" @commands.command(name="stats") - async def stats(self, ctx): + async def stats(self, ctx: commands.Context) -> None: """Количество серверов, каналов и пользователей""" guilds = ctx.bot.guilds total_guilds = len(guilds) diff --git a/commands/status.py b/commands/status.py index 5244be8..f283862 100644 --- a/commands/status.py +++ b/commands/status.py @@ -11,7 +11,7 @@ class Status(commands.Cog): """Команда !status — статус бота, пинг, uptime""" @commands.command(name="status") - async def status(self, ctx): + async def status(self, ctx: commands.Context) -> None: """Статус бота: пинг к Discord gateway и время работы""" latency_ms = round(ctx.bot.latency * 1000, 1) start_time = getattr(ctx.bot, "_start_time", time.time()) diff --git a/utils/morning_runner.py b/utils/morning_runner.py index 0a4597c..46afb41 100644 --- a/utils/morning_runner.py +++ b/utils/morning_runner.py @@ -52,7 +52,7 @@ async def gather_morning() -> MorningData: ) -async def run_morning(bot: "commands.Bot", channel: discord.TextChannel): +async def run_morning(bot: "commands.Bot", channel: discord.TextChannel) -> None: """Выполнить утренний дайджест и отправить в канал.""" try: data = await gather_morning() @@ -249,8 +249,8 @@ class Scheduler: if not sent: logger.error("Не удалось найти канал для отправки morning-дайджеста") - def start(self): + def start(self) -> None: self._start_scheduler() - def stop(self): + def stop(self) -> None: self._stop_scheduler() diff --git a/utils/news.py b/utils/news.py index e510a6f..b937a22 100644 --- a/utils/news.py +++ b/utils/news.py @@ -1,6 +1,7 @@ import asyncio import logging from datetime import datetime +from typing import Optional import requests @@ -14,7 +15,7 @@ RSS_URL_POSTS = "https://habr.com/ru/rss/hubs/artificial_intelligence/news/top/d _session = requests.Session() -async def fetch_rss(url): +async def fetch_rss(url: str) -> Optional[list[dict]]: """Скачать и распарсить RSS-ленту (RSS 2.0 / Atom).""" await habr_rss_limiter.acquire() from defusedxml.ElementTree import fromstring @@ -74,7 +75,7 @@ async def fetch_rss(url): return None -def _parse_date(pub_date): +def _parse_date(pub_date: Optional[str]) -> str: """Парсить дату из RSS в строку 'дд.мм.гггг' или вернуть часть даты.""" if not pub_date: return "" @@ -86,7 +87,7 @@ def _parse_date(pub_date): return pub_date[:10].replace("-", ".") -def truncate_title(title, max_len=60): +def truncate_title(title: str, max_len: int = 60) -> str: """Обрезать заголовок, если он длиннее max_len.""" if len(title) > max_len: return title[:max_len] + "..." @@ -107,7 +108,7 @@ def truncate_embed_field(text: str, max_len: int = 1024) -> str: return text[:max_len - 3] + "..." -def format_articles(articles, title, link): +def format_articles(articles: list[dict], title: str, link: str) -> list[str]: """Сформировать список строк для вывода статей/постов.""" lines = [f"**{title}**\n<{link}>"] for i, article in enumerate(articles[:5], 1): diff --git a/utils/pogoda.py b/utils/pogoda.py index 5e32d24..9cb1b45 100644 --- a/utils/pogoda.py +++ b/utils/pogoda.py @@ -1,5 +1,7 @@ import asyncio import logging +from typing import Any, Optional + import requests from requests.exceptions import ConnectionError, Timeout, SSLError @@ -12,7 +14,7 @@ API_URL_WEATHER = "https://wttr.in/Magnitogorsk?format=j1&lang=ru" _session = requests.Session() -async def fetch_weather(api_url, timeout=10, max_retries=3): +async def fetch_weather(api_url: str, timeout: int = 10, max_retries: int = 3) -> Optional[dict]: """Получить данные о погоде с retry.""" await weather_limiter.acquire() for attempt in range(max_retries): @@ -35,7 +37,7 @@ async def fetch_weather(api_url, timeout=10, max_retries=3): return await fetch_open_meteo() -async def fetch_open_meteo(lat=53.4069, lon=58.9797, timeout=10, max_retries=3): +async def fetch_open_meteo(lat: float = 53.4069, lon: float = 58.9797, timeout: int = 10, max_retries: int = 3) -> Optional[dict]: """Fallback на Open-Meteo API.""" await open_meteo_limiter.acquire() url = ( @@ -78,7 +80,7 @@ async def fetch_open_meteo(lat=53.4069, lon=58.9797, timeout=10, max_retries=3): return None -def wmo_to_russian(code): +def wmo_to_russian(code: Optional[int]) -> str: """Перевод WMO weather code в русский.""" mapping = { 0: "Ясно", @@ -139,7 +141,7 @@ _WEATHER_MAPPING = [ ] -def translate_weather(en): +def translate_weather(en: Optional[str]) -> str: if not en: return "—" en_lower = en.lower() @@ -149,7 +151,7 @@ def translate_weather(en): return en -def format_weather_data_for_console(data): +def format_weather_data_for_console(data: Optional[dict]) -> Optional[list[str]]: """ Форматировать погодные данные для консольного вывода. @@ -186,7 +188,7 @@ def format_weather_data_for_console(data): ] -def format_weather_for_embed(data): +def format_weather_for_embed(data: Optional[dict]) -> Optional[str]: """Форматировать погоду для Discord embed (с заголовком).""" if data is None: return None @@ -196,7 +198,7 @@ def format_weather_for_embed(data): return "**Погода в Магнитогорске:**\n" + "\n".join(lines) -def pressure_to_mmhg(mb): +def pressure_to_mmhg(mb: Any) -> float | str: if mb == "—" or mb is None or mb == "": return "—" try: