Исправление: добавил type hints ко всем 20 production-функциям

This commit is contained in:
deadzilla 2026-07-07 23:17:25 +05:00
parent 613dea55cf
commit 65e01f0091
10 changed files with 24 additions and 21 deletions

View File

@ -11,7 +11,7 @@ class Cat(commands.Cog):
"""Команда !cat — случайный котик""" """Команда !cat — случайный котик"""
@commands.command(name="cat") @commands.command(name="cat")
async def cat(self, ctx): async def cat(self, ctx: commands.Context) -> None:
"""Получить случайного котика""" """Получить случайного котика"""
url = await fetch_cat() url = await fetch_cat()
if url is None: if url is None:

View File

@ -6,7 +6,7 @@ class Help(commands.Cog):
"""Команда !hp — список всех команд бота""" """Команда !hp — список всех команд бота"""
@commands.command(name="hp") @commands.command(name="hp")
async def hp(self, ctx): async def hp(self, ctx: commands.Context) -> None:
"""Показать список доступных команд""" """Показать список доступных команд"""
await self._show_help(ctx) await self._show_help(ctx)

View File

@ -14,7 +14,7 @@ class Morning(commands.Cog):
pass pass
@commands.command(name="morning") @commands.command(name="morning")
async def morning(self, ctx): async def morning(self, ctx: commands.Context) -> None:
"""Погода, лучшие статьи за сутки и котик""" """Погода, лучшие статьи за сутки и котик"""
logger.info("%s: !morning запущен", ctx.author) logger.info("%s: !morning запущен", ctx.author)
await run_morning(ctx.bot, ctx.channel) await run_morning(ctx.bot, ctx.channel)

View File

@ -16,7 +16,7 @@ class News(commands.Cog):
"""Команда !news — свежие статьи и новости по AI с Habr""" """Команда !news — свежие статьи и новости по AI с Habr"""
@commands.command(name="nw") @commands.command(name="nw")
async def nw(self, ctx): async def nw(self, ctx: commands.Context) -> None:
"""Топ-5 свежих статей и новостей по AI с Habr""" """Топ-5 свежих статей и новостей по AI с Habr"""
articles = await fetch_rss(RSS_URL_ARTICLES) articles = await fetch_rss(RSS_URL_ARTICLES)
if articles is None: if articles is None:

View File

@ -12,7 +12,7 @@ class Pg(commands.Cog):
self.api_url = API_URL_WEATHER self.api_url = API_URL_WEATHER
@commands.command(name="pg") @commands.command(name="pg")
async def pg(self, ctx): async def pg(self, ctx: commands.Context) -> None:
"""Прогноз погоды в Магнитогорске""" """Прогноз погоды в Магнитогорске"""
data = await fetch_weather(self.api_url) data = await fetch_weather(self.api_url)
if data is None: if data is None:

View File

@ -9,7 +9,7 @@ class Stats(commands.Cog):
"""Команда !stats — статистика серверов""" """Команда !stats — статистика серверов"""
@commands.command(name="stats") @commands.command(name="stats")
async def stats(self, ctx): async def stats(self, ctx: commands.Context) -> None:
"""Количество серверов, каналов и пользователей""" """Количество серверов, каналов и пользователей"""
guilds = ctx.bot.guilds guilds = ctx.bot.guilds
total_guilds = len(guilds) total_guilds = len(guilds)

View File

@ -11,7 +11,7 @@ class Status(commands.Cog):
"""Команда !status — статус бота, пинг, uptime""" """Команда !status — статус бота, пинг, uptime"""
@commands.command(name="status") @commands.command(name="status")
async def status(self, ctx): async def status(self, ctx: commands.Context) -> None:
"""Статус бота: пинг к Discord gateway и время работы""" """Статус бота: пинг к Discord gateway и время работы"""
latency_ms = round(ctx.bot.latency * 1000, 1) latency_ms = round(ctx.bot.latency * 1000, 1)
start_time = getattr(ctx.bot, "_start_time", time.time()) start_time = getattr(ctx.bot, "_start_time", time.time())

View File

@ -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: try:
data = await gather_morning() data = await gather_morning()
@ -249,8 +249,8 @@ class Scheduler:
if not sent: if not sent:
logger.error("Не удалось найти канал для отправки morning-дайджеста") logger.error("Не удалось найти канал для отправки morning-дайджеста")
def start(self): def start(self) -> None:
self._start_scheduler() self._start_scheduler()
def stop(self): def stop(self) -> None:
self._stop_scheduler() self._stop_scheduler()

View File

@ -1,6 +1,7 @@
import asyncio import asyncio
import logging import logging
from datetime import datetime from datetime import datetime
from typing import Optional
import requests import requests
@ -14,7 +15,7 @@ RSS_URL_POSTS = "https://habr.com/ru/rss/hubs/artificial_intelligence/news/top/d
_session = requests.Session() _session = requests.Session()
async def fetch_rss(url): async def fetch_rss(url: str) -> Optional[list[dict]]:
"""Скачать и распарсить RSS-ленту (RSS 2.0 / Atom).""" """Скачать и распарсить RSS-ленту (RSS 2.0 / Atom)."""
await habr_rss_limiter.acquire() await habr_rss_limiter.acquire()
from defusedxml.ElementTree import fromstring from defusedxml.ElementTree import fromstring
@ -74,7 +75,7 @@ async def fetch_rss(url):
return None return None
def _parse_date(pub_date): def _parse_date(pub_date: Optional[str]) -> str:
"""Парсить дату из RSS в строку 'дд.мм.гггг' или вернуть часть даты.""" """Парсить дату из RSS в строку 'дд.мм.гггг' или вернуть часть даты."""
if not pub_date: if not pub_date:
return "" return ""
@ -86,7 +87,7 @@ def _parse_date(pub_date):
return pub_date[:10].replace("-", ".") return pub_date[:10].replace("-", ".")
def truncate_title(title, max_len=60): def truncate_title(title: str, max_len: int = 60) -> str:
"""Обрезать заголовок, если он длиннее max_len.""" """Обрезать заголовок, если он длиннее max_len."""
if len(title) > max_len: if len(title) > max_len:
return 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] + "..." 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}>"] lines = [f"**{title}**\n<{link}>"]
for i, article in enumerate(articles[:5], 1): for i, article in enumerate(articles[:5], 1):

View File

@ -1,5 +1,7 @@
import asyncio import asyncio
import logging import logging
from typing import Any, Optional
import requests import requests
from requests.exceptions import ConnectionError, Timeout, SSLError 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() _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.""" """Получить данные о погоде с retry."""
await weather_limiter.acquire() await weather_limiter.acquire()
for attempt in range(max_retries): 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() 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.""" """Fallback на Open-Meteo API."""
await open_meteo_limiter.acquire() await open_meteo_limiter.acquire()
url = ( url = (
@ -78,7 +80,7 @@ async def fetch_open_meteo(lat=53.4069, lon=58.9797, timeout=10, max_retries=3):
return None return None
def wmo_to_russian(code): def wmo_to_russian(code: Optional[int]) -> str:
"""Перевод WMO weather code в русский.""" """Перевод WMO weather code в русский."""
mapping = { mapping = {
0: "Ясно", 0: "Ясно",
@ -139,7 +141,7 @@ _WEATHER_MAPPING = [
] ]
def translate_weather(en): def translate_weather(en: Optional[str]) -> str:
if not en: if not en:
return "" return ""
en_lower = en.lower() en_lower = en.lower()
@ -149,7 +151,7 @@ def translate_weather(en):
return 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 (с заголовком).""" """Форматировать погоду для Discord embed (с заголовком)."""
if data is None: if data is None:
return None return None
@ -196,7 +198,7 @@ def format_weather_for_embed(data):
return "**Погода в Магнитогорске:**\n" + "\n".join(lines) 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 == "": if mb == "" or mb is None or mb == "":
return "" return ""
try: try: