Исправление: добавил type hints ко всем 20 production-функциям
This commit is contained in:
parent
613dea55cf
commit
65e01f0091
@ -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:
|
||||||
|
|||||||
@ -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)
|
||||||
|
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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())
|
||||||
|
|||||||
@ -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()
|
||||||
|
|||||||
@ -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):
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user