chore(userbot): apply ruff check --fix and ruff format

- ruff check --fix: 210 auto-fixed errors (import sorting, trailing
  whitespace, unused imports, f-string fixups, deprecated annotations)
- ruff format: 104 files reformatted to consistent style
- 268 non-auto-fixable issues remain (S113 requests timeout, etc.)
This commit is contained in:
2026-06-19 12:19:01 +02:00
parent 95cec59263
commit 7ba6bc44f2
104 changed files with 4338 additions and 5319 deletions
+98 -128
View File
@@ -25,22 +25,20 @@ import sys
import tempfile
import time
import traceback
from PIL import Image
from io import BytesIO
from types import ModuleType
from typing import Dict, Tuple
import psutil
from PIL import Image
from pyrogram import Client, errors, filters
from pyrogram.errors import FloodWait, MessageNotModified, UserNotParticipant
from pyrogram.types import Message
from pyrogram.enums import ChatMembersFilter
from utils.db import db
from .misc import modules_help, prefix, requirements_list
META_COMMENTS = re.compile(r"^ *# *meta +(\S+) *: *(.*?)\s*$", re.MULTILINE)
META_COMMENTS = re.compile(r'^ *# *meta +(\S+) *: *(.*?)\s*$', re.MULTILINE)
interact_with_to_delete = []
@@ -51,11 +49,11 @@ def time_formatter(milliseconds: int) -> str:
hours, minutes = divmod(minutes, 60)
days, hours = divmod(hours, 24)
tmp = (
((str(days) + " day(s), ") if days else "")
+ ((str(hours) + " hour(s), ") if hours else "")
+ ((str(minutes) + " minute(s), ") if minutes else "")
+ ((str(seconds) + " second(s), ") if seconds else "")
+ ((str(milliseconds) + " millisecond(s), ") if milliseconds else "")
((str(days) + ' day(s), ') if days else '')
+ ((str(hours) + ' hour(s), ') if hours else '')
+ ((str(minutes) + ' minute(s), ') if minutes else '')
+ ((str(seconds) + ' second(s), ') if seconds else '')
+ ((str(milliseconds) + ' millisecond(s), ') if milliseconds else '')
)
return tmp[:-2]
@@ -63,32 +61,30 @@ def time_formatter(milliseconds: int) -> str:
def humanbytes(size):
"""Convert Bytes To Bytes So That Human Can Read It"""
if not size:
return ""
return ''
power = 2**10
raised_to_pow = 0
dict_power_n = {0: "", 1: "Ki", 2: "Mi", 3: "Gi", 4: "Ti"}
dict_power_n = {0: '', 1: 'Ki', 2: 'Mi', 3: 'Gi', 4: 'Ti'}
while size > power:
size /= power
raised_to_pow += 1
return str(round(size, 2)) + " " + dict_power_n[raised_to_pow] + "B"
return str(round(size, 2)) + ' ' + dict_power_n[raised_to_pow] + 'B'
async def edit_or_send_as_file(
tex: str,
message: Message,
client: Client,
caption: str = "<code>Result!</code>",
file_name: str = "result",
caption: str = '<code>Result!</code>',
file_name: str = 'result',
):
"""Send As File If Len Of Text Exceeds Tg Limit Else Edit Message"""
if not tex:
await message.edit("<code>Wait, What?</code>")
await message.edit('<code>Wait, What?</code>')
return
if len(tex) > 1024:
await message.edit("<code>OutPut is Too Large, Sending As File!</code>")
with tempfile.NamedTemporaryFile(
"w", delete=False, suffix=".txt", prefix=f"{file_name}_"
) as fn:
await message.edit('<code>OutPut is Too Large, Sending As File!</code>')
with tempfile.NamedTemporaryFile('w', delete=False, suffix='.txt', prefix=f'{file_name}_') as fn:
fn.write(tex)
temp_path = fn.name
try:
@@ -106,7 +102,7 @@ def get_text(message: Message) -> None | str:
text_to_return = message.text
if message.text is None:
return None
if " " in text_to_return:
if ' ' in text_to_return:
try:
return message.text.split(None, 1)[1]
except IndexError:
@@ -127,32 +123,28 @@ async def progress(current, total, message, start, type_of_ps, file_name=None):
return
time_to_completion = round((total - current) / speed) * 1000
estimated_total_time = elapsed_time + time_to_completion
progress_str = f"{''.join(['' for i in range(math.floor(percentage / 10))])}"
progress_str += (
f"{''.join(['' for i in range(10 - math.floor(percentage / 10))])}"
)
progress_str += f"{round(percentage, 2)}%\n"
tmp = f"{progress_str}{humanbytes(current)} of {humanbytes(total)}\n"
tmp += f"ETA: {time_formatter(estimated_total_time)}"
progress_str = f'{"".join(["" for i in range(math.floor(percentage / 10))])}'
progress_str += f'{"".join(["" for i in range(10 - math.floor(percentage / 10))])}'
progress_str += f'{round(percentage, 2)}%\n'
tmp = f'{progress_str}{humanbytes(current)} of {humanbytes(total)}\n'
tmp += f'ETA: {time_formatter(estimated_total_time)}'
if file_name:
try:
await message.edit(
f"{type_of_ps}\n<b>File Name:</b> <code>{file_name}</code>\n{tmp}"
)
await message.edit(f'{type_of_ps}\n<b>File Name:</b> <code>{file_name}</code>\n{tmp}')
except FloodWait as e:
await asyncio.sleep(e.x)
except MessageNotModified:
pass
else:
try:
await message.edit(f"{type_of_ps}\n{tmp}")
await message.edit(f'{type_of_ps}\n{tmp}')
except FloodWait as e:
await asyncio.sleep(e.x)
except MessageNotModified:
pass
async def run_cmd(prefix: str) -> Tuple[str, str, int, int]:
async def run_cmd(prefix: str) -> tuple[str, str, int, int]:
"""Run Commands"""
args = shlex.split(prefix)
process = await asyncio.create_subprocess_exec(
@@ -160,45 +152,45 @@ async def run_cmd(prefix: str) -> Tuple[str, str, int, int]:
)
stdout, stderr = await process.communicate()
return (
stdout.decode("utf-8", "replace").strip(),
stderr.decode("utf-8", "replace").strip(),
stdout.decode('utf-8', 'replace').strip(),
stderr.decode('utf-8', 'replace').strip(),
process.returncode,
process.pid,
)
def mediainfo(media):
xx = str((str(media)).split("(", maxsplit=1)[0])
m = ""
if xx == "MessageMediaDocument":
xx = str((str(media)).split('(', maxsplit=1)[0])
m = ''
if xx == 'MessageMediaDocument':
mim = media.document.mime_type
if mim == "application/x-tgsticker":
m = "sticker animated"
elif "image" in mim:
if mim == "image/webp":
m = "sticker"
elif mim == "image/gif":
m = "gif as doc"
if mim == 'application/x-tgsticker':
m = 'sticker animated'
elif 'image' in mim:
if mim == 'image/webp':
m = 'sticker'
elif mim == 'image/gif':
m = 'gif as doc'
else:
m = "pic as doc"
elif "video" in mim:
if "DocumentAttributeAnimated" in str(media):
m = "gif"
elif "DocumentAttributeVideo" in str(media):
m = 'pic as doc'
elif 'video' in mim:
if 'DocumentAttributeAnimated' in str(media):
m = 'gif'
elif 'DocumentAttributeVideo' in str(media):
i = str(media.document.attributes[0])
if "supports_streaming=True" in i:
m = "video"
m = "video as doc"
if 'supports_streaming=True' in i:
m = 'video'
m = 'video as doc'
else:
m = "video"
elif "audio" in mim:
m = "audio"
m = 'video'
elif 'audio' in mim:
m = 'audio'
else:
m = "document"
elif xx == "MessageMediaPhoto":
m = "pic"
elif xx == "MessageMediaWebPage":
m = "web"
m = 'document'
elif xx == 'MessageMediaPhoto':
m = 'pic'
elif xx == 'MessageMediaWebPage':
m = 'web'
return m
@@ -217,31 +209,31 @@ def text(message: Message) -> str:
def restart() -> None:
music_bot_pid = db.get("custom.musicbot", "music_bot_pid", None)
music_bot_pid = db.get('custom.musicbot', 'music_bot_pid', None)
if music_bot_pid is not None:
try:
music_bot_process = psutil.Process(music_bot_pid)
music_bot_process.terminate()
except psutil.NoSuchProcess:
print("Music bot is not running.")
os.execvp(sys.executable, [sys.executable, "main.py"]) # skipcq
print('Music bot is not running.')
os.execvp(sys.executable, [sys.executable, 'main.py']) # skipcq
def format_exc(e: Exception, suffix="") -> str:
def format_exc(e: Exception, suffix='') -> str:
traceback.print_exc()
err = traceback.format_exc()
if isinstance(e, errors.RPCError):
return (
f"<b>Telegram API error!</b>\n"
f"<code>[{e.CODE} {e.ID or e.NAME}] — {e.MESSAGE.format(value=e.value)}</code>\n\n<b>{suffix}</b>"
f'<b>Telegram API error!</b>\n'
f'<code>[{e.CODE} {e.ID or e.NAME}] — {e.MESSAGE.format(value=e.value)}</code>\n\n<b>{suffix}</b>'
)
return f"<b>Error!</b>\n" f"<code>{err}</code>"
return f'<b>Error!</b>\n<code>{err}</code>'
def with_reply(func):
async def wrapped(client: Client, message: Message):
if not message.reply_to_message:
await message.edit("<b>Reply to message is required</b>")
await message.edit('<b>Reply to message is required</b>')
else:
return await func(client, message)
@@ -251,16 +243,12 @@ def with_reply(func):
def is_admin(func):
async def wrapped(client: Client, message: Message):
try:
chat_member = await client.get_chat_member(
message.chat.id, message.from_user.id
)
if chat_member.status in ("administrator", "creator"):
chat_member = await client.get_chat_member(message.chat.id, message.from_user.id)
if chat_member.status in ('administrator', 'creator'):
return await func(client, message)
await message.edit("You need to be an admin to perform this action.")
await message.edit('You need to be an admin to perform this action.')
except UserNotParticipant:
await message.edit(
"You need to be a participant in the chat to perform this action."
)
await message.edit('You need to be a participant in the chat to perform this action.')
return wrapped
@@ -278,9 +266,7 @@ async def interact_with(message: Message) -> Message:
await asyncio.sleep(1)
# noinspection PyProtectedMember
response = [
msg async for msg in message._client.get_chat_history(message.chat.id, limit=1)
]
response = [msg async for msg in message._client.get_chat_history(message.chat.id, limit=1)]
seconds_waiting = 0
while response[0].from_user.is_self:
@@ -290,10 +276,7 @@ async def interact_with(message: Message) -> Message:
await asyncio.sleep(1)
# noinspection PyProtectedMember
response = [
msg
async for msg in message._client.get_chat_history(message.chat.id, limit=1)
]
response = [msg async for msg in message._client.get_chat_history(message.chat.id, limit=1)]
interact_with_to_delete.append(message.id)
interact_with_to_delete.append(response[0].id)
@@ -304,14 +287,12 @@ async def interact_with(message: Message) -> Message:
def format_module_help(module_name: str, full=True):
commands = modules_help[module_name]
help_text = (
f"<b>Help for |{module_name}|\n\nUsage:</b>\n" if full else "<b>Usage:</b>\n"
)
help_text = f'<b>Help for |{module_name}|\n\nUsage:</b>\n' if full else '<b>Usage:</b>\n'
for command, desc in commands.items():
cmd = command.split(maxsplit=1)
args = " <code>" + cmd[1] + "</code>" if len(cmd) > 1 else ""
help_text += f"<code>{prefix}{cmd[0]}</code>{args} — <i>{desc}</i>\n"
args = ' <code>' + cmd[1] + '</code>' if len(cmd) > 1 else ''
help_text += f'<code>{prefix}{cmd[0]}</code>{args} — <i>{desc}</i>\n'
return help_text
@@ -319,16 +300,12 @@ def format_module_help(module_name: str, full=True):
def format_small_module_help(module_name: str, full=True):
commands = modules_help[module_name]
help_text = (
f"<b>Help for |{module_name}|\n\nCommands list:\n"
if full
else "<b>Commands list:\n"
)
help_text = f'<b>Help for |{module_name}|\n\nCommands list:\n' if full else '<b>Commands list:\n'
for command, _desc in commands.items():
cmd = command.split(maxsplit=1)
args = " <code>" + cmd[1] + "</code>" if len(cmd) > 1 else ""
help_text += f"<code>{prefix}{cmd[0]}</code>{args}\n"
help_text += f"\nGet full usage: <code>{prefix}help {module_name}</code></b>"
args = ' <code>' + cmd[1] + '</code>' if len(cmd) > 1 else ''
help_text += f'<code>{prefix}{cmd[0]}</code>{args}\n'
help_text += f'\nGet full usage: <code>{prefix}help {module_name}</code></b>'
return help_text
@@ -348,12 +325,12 @@ def import_library(library_name: str, package_name: str = None):
return importlib.import_module(library_name)
except ImportError as exc:
completed = subprocess.run(
[sys.executable, "-m", "pip", "install", "--upgrade", package_name],
[sys.executable, '-m', 'pip', 'install', '--upgrade', package_name],
check=True,
)
if completed.returncode != 0:
raise AssertionError(
f"Failed to install library {package_name} (pip exited with code {completed.returncode})"
f'Failed to install library {package_name} (pip exited with code {completed.returncode})'
) from exc
return importlib.import_module(library_name)
@@ -363,21 +340,17 @@ def uninstall_library(package_name: str):
Uninstalls a library
:param package_name: package name in PyPi (pip uninstall example)
"""
completed = subprocess.run(
[sys.executable, "-m", "pip", "uninstall", "-y", package_name], check=True
)
completed = subprocess.run([sys.executable, '-m', 'pip', 'uninstall', '-y', package_name], check=True)
if completed.returncode != 0:
raise AssertionError(
f"Failed to uninstall library {package_name} (pip exited with code {completed.returncode})"
f'Failed to uninstall library {package_name} (pip exited with code {completed.returncode})'
)
def resize_image(
input_img, output=None, img_type="PNG", size: int = 512, size2: int = None
):
def resize_image(input_img, output=None, img_type='PNG', size: int = 512, size2: int = None):
if output is None:
output = BytesIO()
output.name = f"sticker.{img_type.lower()}"
output.name = f'sticker.{img_type.lower()}'
with Image.open(input_img) as img:
# We used to use thumbnail(size) here, but it returns with a *max* dimension of 512,512
@@ -435,13 +408,13 @@ async def load_module(
if module_name in modules_help and not core:
await unload_module(module_name, client)
path = f"modules.{'custom_modules.' if not core else ''}{module_name}"
path = f'modules.{"custom_modules." if not core else ""}{module_name}'
with open(f"{path.replace('.', '/')}.py", encoding="utf-8") as f:
with open(f'{path.replace(".", "/")}.py', encoding='utf-8') as f:
code = f.read()
meta = parse_meta_comments(code)
packages = meta.get("requires", "").split()
packages = meta.get('requires', '').split()
requirements_list.extend(packages)
try:
@@ -455,39 +428,36 @@ async def load_module(
raise
if message:
await message.edit(f"<b>Installing requirements: {' '.join(packages)}</b>")
await message.edit(f'<b>Installing requirements: {" ".join(packages)}</b>')
proc = await asyncio.create_subprocess_exec(
sys.executable,
"-m",
"pip",
"install",
"-U",
'-m',
'pip',
'install',
'-U',
*packages,
)
try:
await asyncio.wait_for(proc.wait(), timeout=120)
except asyncio.TimeoutError:
except TimeoutError:
if message:
await message.edit(
"<b>Timeout while installed requirements."
+ "Try to install them manually</b>"
)
raise TimeoutError("timeout while installing requirements") from e
await message.edit('<b>Timeout while installed requirements.' + 'Try to install them manually</b>')
raise TimeoutError('timeout while installing requirements') from e
if proc.returncode != 0:
if message:
await message.edit(
f"<b>Failed to install requirements (pip exited with code {proc.returncode}). "
f"Check logs for futher info</b>",
f'<b>Failed to install requirements (pip exited with code {proc.returncode}). '
f'Check logs for futher info</b>',
)
raise RuntimeError("failed to install requirements") from e
raise RuntimeError('failed to install requirements') from e
module = importlib.import_module(path)
for _name, obj in vars(module).items():
if isinstance(getattr(obj, "handlers", []), list):
for handler, group in getattr(obj, "handlers", []):
if isinstance(getattr(obj, 'handlers', []), list):
for handler, group in getattr(obj, 'handlers', []):
client.add_handler(handler, group)
module.__meta__ = meta
@@ -496,14 +466,14 @@ async def load_module(
async def unload_module(module_name: str, client: Client) -> bool:
path = "modules.custom_modules." + module_name
path = 'modules.custom_modules.' + module_name
if path not in sys.modules:
return False
module = importlib.import_module(path)
for _name, obj in vars(module).items():
for handler, group in getattr(obj, "handlers", []):
for handler, group in getattr(obj, 'handlers', []):
client.remove_handler(handler, group)
del modules_help[module_name]
@@ -521,7 +491,7 @@ def no_prefix(handler):
return filters.create(func)
def parse_meta_comments(code: str) -> Dict[str, str]:
def parse_meta_comments(code: str) -> dict[str, str]:
try:
groups = META_COMMENTS.search(code).groups()
except AttributeError: