things are working, and all is well

This commit is contained in:
Chris W 2023-10-31 02:05:43 -06:00
parent ebd352cf80
commit 1a9ed07a02
30 changed files with 1131 additions and 76 deletions

0
.env.example Normal file → Executable file
View File

0
.gitignore vendored Normal file → Executable file
View File

0
README.md Normal file → Executable file
View File

20
cyber_fenneko/__init__.py Normal file → Executable file
View File

@ -1,6 +1,7 @@
import os import os
from mongoengine import connect
from telemongo import MongoSession
from telethon import TelegramClient from telethon import TelegramClient
from telethon.sessions import SQLiteSession
from dotenv import load_dotenv from dotenv import load_dotenv
from cyber_fenneko.bot import Bot from cyber_fenneko.bot import Bot
@ -12,11 +13,24 @@ api_id = os.environ.get('APP_ID')
api_hash = os.environ.get('APP_HASH') api_hash = os.environ.get('APP_HASH')
phone_number = os.environ.get('TG_PHONE') phone_number = os.environ.get('TG_PHONE')
session = SQLiteSession('fenneko-' + phone_number) db_host = os.environ.setdefault('DB_HOST', 'localhost')
client = TelegramClient(session, api_id, api_hash) db_port = os.environ.setdefault('DB_PORT', 27017)
db_user = os.environ.get('DB_USER')
db_pass = os.environ.get('DB_PASS')
db_name = os.environ.get('DB_NAME')
session = MongoSession(db=db_name, host=db_host, port=int(db_port), username=db_user, password=db_pass)
client = TelegramClient(session, api_id, api_hash)
bot = Bot(client) bot = Bot(client)
# Import all middlewares from the middleware directory
# We just need the files to be imported, nothing else
# This is a bit hacky, but it works
for filename in os.listdir('cyber_fenneko/middleware'):
if filename.endswith('.py'):
__import__('cyber_fenneko.middleware.' + filename[:-3])
# Import all commands from the commands directory # Import all commands from the commands directory
# We just need the files to be imported, nothing else # We just need the files to be imported, nothing else
# This is a bit hacky, but it works # This is a bit hacky, but it works

9
cyber_fenneko/__main__.py Normal file → Executable file
View File

@ -1,11 +1,8 @@
from telethon.events import NewMessage from telethon.events import NewMessage, Raw
from . import client, bot, phone_number from . import client, bot, phone_number
async def new_message_handler(event: NewMessage): client.add_event_handler(bot._on_raw, Raw)
print(event) client.add_event_handler(bot._on_new_message, NewMessage)
client.add_event_handler(bot.on_new_message, NewMessage)
# client.add_event_handler(new_message_handler, NewMessage)
with client: with client:
client.start(phone_number) client.start(phone_number)

32
cyber_fenneko/bot.py Normal file → Executable file
View File

@ -1,5 +1,7 @@
import logging import logging
from typing import Dict
from telethon import TelegramClient from telethon import TelegramClient
from telethon.tl.types import TypeUpdate
from telethon.tl.custom.message import Message from telethon.tl.custom.message import Message
from cyber_fenneko.internal.constants import GLOBAL_ARGS from cyber_fenneko.internal.constants import GLOBAL_ARGS
from cyber_fenneko.internal.command import Command from cyber_fenneko.internal.command import Command
@ -7,9 +9,17 @@ from cyber_fenneko.internal.command_context import CommandContext
from cyber_fenneko.internal.arg_parser import parse_args from cyber_fenneko.internal.arg_parser import parse_args
class Bot: class Bot:
commands: Dict[str, Command]
command_aliases: Dict[str, str]
update_handlers: Dict[TypeUpdate, list]
client: TelegramClient
logger: logging.Logger
default_prefix: str
def __init__(self, client: TelegramClient): def __init__(self, client: TelegramClient):
self.commands = {} self.commands = {}
self.command_aliases = {} self.command_aliases = {}
self.update_handlers = {}
self.client = client self.client = client
self.logger = logging.getLogger('cyber_fenneko.bot') self.logger = logging.getLogger('cyber_fenneko.bot')
self.default_prefix = '.' self.default_prefix = '.'
@ -17,13 +27,22 @@ class Bot:
def set_default_prefix(self, prefix: str): def set_default_prefix(self, prefix: str):
self.default_prefix = prefix self.default_prefix = prefix
def on(self, *events: TypeUpdate):
def decorator(func):
for event in events:
if event not in self.update_handlers:
self.update_handlers[event] = []
self.update_handlers[event].append(func)
return func
return decorator
def command(self, cmd: str, **kwargs: dict): def command(self, cmd: str, **kwargs: dict):
def decorator(func): def decorator(func):
# Set some defaults # Set some defaults
kwargs.setdefault('prefix', self.default_prefix) kwargs.setdefault('prefix', self.default_prefix)
command = Command(func, cmd, **kwargs) command = Command(func, cmd, **kwargs)
command.args = GLOBAL_ARGS + command.args
# Check if a command with the same name already exists # Check if a command with the same name already exists
if command.command in self.commands: if command.command in self.commands:
@ -42,7 +61,14 @@ class Bot:
return func # we still want the function to be normally accessible return func # we still want the function to be normally accessible
return decorator return decorator
async def on_new_message(self, event: Message): async def _on_raw(self, event: TypeUpdate):
if event.__class__ not in self.update_handlers:
return
for handler in self.update_handlers[event.__class__]:
await handler(self, event)
async def _on_new_message(self, event: Message):
message_text = event.message.message.strip() message_text = event.message.message.strip()
if not message_text: if not message_text:
return return
@ -63,7 +89,7 @@ class Bot:
text = message_text[len(command_text) + 1:].strip() text = message_text[len(command_text) + 1:].strip()
try: try:
args, text = parse_args(text, cmd.args) args, text = parse_args(self.client, text, cmd.args)
except ValueError as e: except ValueError as e:
await event.respond(f'Error: {e}') await event.respond(f'Error: {e}')
return return

81
cyber_fenneko/commands/ask.py Executable file
View File

@ -0,0 +1,81 @@
import time
import openai
from cyber_fenneko.internal.constants import OPENAI_API_KEY
from .. import bot
from ..internal.command_context import CommandContext
from ..internal.arg_parser import Arg, ArgType
MODELS = {
'3.5': 'gpt-3.5-turbo',
'4': 'gpt-4',
}
@bot.command(
'ask',
args=[
Arg('model', type=ArgType.enum, aliases=['m'], description='The model to use', enum_values=list(MODELS.keys()), default='3.5'),
Arg('max-tokens', type=ArgType.int, aliases=['t'], description='The maximum number of tokens to generate', default=750),
Arg('temperature', type=ArgType.int, aliases=['temp'], description='The temperature to use', default=1),
Arg('top-p', type=ArgType.int, aliases=['top'], description='The top-p value to use', default=1),
Arg('presence-penalty', type=ArgType.int, aliases=['pp'], description='The presence penalty to use', default=0),
Arg('frequency-penalty', type=ArgType.int, aliases=['fp'], description='The frequency penalty to use', default=0),
],
description='Ask a question using ChatGPT',
)
async def ask(bot, ctx: CommandContext):
if not OPENAI_API_KEY:
return
# Get the message. If this command was sent in response to a message, use that message.
# Otherwise, use the message that invoked the command.
message = ctx.reply_to or ctx.message
# Get the prompt
prompt = message.message.strip()
# If this message was sent in response to another message, delete the sent message
if ctx.reply_to:
await ctx.event.delete()
# Get the arguments to be passed to the API
model = MODELS[ctx.args['model']]
max_tokens = ctx.args['max-tokens']
temperature = ctx.args['temperature']
top_p = ctx.args['top-p']
presence_penalty = ctx.args['presence-penalty']
frequency_penalty = ctx.args['frequency-penalty']
# Set the scene
messages = [{
"role": "system",
"content": """You are a chatbot within Telegram masquerading as a real person.
Your name is watzon, and you should act and respond like watzon would.
Watzon is a web developer of 13 years, father of 2, and husband of 1.
You are having a conversation with other humans in a Telegram group chat.
The person you're responding to is either asking a question, or making a statement.
You should respond to the human in a way that makes sense.
The human is not trying to trick you. You are responding as a user, so act natural. Use slang if necessary, acronyms, etc.
Do not be too formal, and keep responses short unless the question requires a larger response.
You may use markdown formatting in your responses.
Markdown code blocks should not include the language, and should be delimited by triple backticks.
"""
}, {
"role": "user",
"content": prompt
}]
# Generate the completion
openai.api_key = OPENAI_API_KEY
completion = openai.chat.completions.create(
messages=messages,
model=model,
top_p=top_p,
temperature=temperature,
max_tokens=max_tokens,
presence_penalty=presence_penalty,
frequency_penalty=frequency_penalty,
)
# Send the response
await message.reply(completion.choices[0].message.content, link_preview=False, parse_mode='markdown')

21
cyber_fenneko/commands/cache.py Executable file
View File

@ -0,0 +1,21 @@
import time
from cyber_fenneko.utils import format_time
from .. import bot
from ..internal.command_context import CommandContext
@bot.command(
'cache',
description='Cache upto the last 200 dialogs',
)
async def cache(bot, ctx: CommandContext):
start = time.time()
msg = await ctx.event.respond('Caching...')
dlgs = await bot.client.get_dialogs(limit=200)
end = time.time()
ms = round((end - start) * 1000, 3)
time = format_time(ms)
await msg.edit(f'Cached {len(dlgs)} dialogs ({time})')

0
cyber_fenneko/commands/help.py Normal file → Executable file
View File

60
cyber_fenneko/commands/highlight.py Normal file → Executable file
View File

@ -1,9 +1,11 @@
import time import time
import httpx import httpx
from io import BytesIO from tempfile import NamedTemporaryFile
from urllib.parse import urlencode from urllib.parse import urlencode
from collections import OrderedDict from collections import OrderedDict
from telethon.tl.types import TypeMessageEntity, MessageEntityPre from telethon.tl.types import TypeMessageEntity, MessageEntityPre, InputMediaPhoto
from cyber_fenneko.models.settings import Settings, HighlightSettings
from .. import bot from .. import bot
from ..internal.command_context import CommandContext from ..internal.command_context import CommandContext
from ..internal.arg_parser import Arg, ArgType from ..internal.arg_parser import Arg, ArgType
@ -85,29 +87,35 @@ async def highlight(bot, ctx: CommandContext):
else: else:
code_blocks.append(ctx.text) code_blocks.append(ctx.text)
settings = Settings.objects.first()
print(settings)
if settings.highlight is None:
settings.highlight = HighlightSettings()
settings.save()
for code_block in code_blocks: for code_block in code_blocks:
# Inkify returns an image, we just need to build the URL # Inkify returns an image, we just need to build the URL
query = OrderedDict( query = OrderedDict(
code=code_block, code=code_block,
language=ctx.args['language'], language=ctx.args['language'] or settings.highlight.theme,
theme=ctx.args['theme'], theme=ctx.args['theme'] or settings.highlight.theme,
font=ctx.args['font'], font=ctx.args['font'] or settings.highlight.font,
shadow_color=ctx.args['shadow_color'], shadow_color=ctx.args['shadow_color'] or settings.highlight.shadow_color,
background=ctx.args['background'], background=ctx.args['background'] or settings.highlight.background,
tab_width=ctx.args['tab_width'], tab_width=ctx.args['tab_width'] or settings.highlight.tab_width,
line_pad=ctx.args['line_pad'], line_pad=ctx.args['line_pad'] or settings.highlight.line_pad,
line_offset=ctx.args['line_offset'], line_offset=ctx.args['line_offset'] or settings.highlight.line_offset,
window_title=ctx.args['window_title'], window_title=ctx.args['window_title'] or settings.highlight.window_title,
no_line_number=ctx.args['no_line_number'], no_line_number=ctx.args['no_line_number'] or settings.highlight.no_line_number,
no_round_corner=ctx.args['no_round_corner'], no_round_corner=ctx.args['no_round_corner'] or settings.highlight.no_round_corner,
no_window_controls=ctx.args['no_window_controls'], no_window_controls=ctx.args['no_window_controls'] or settings.highlight.no_window_controls,
shadow_blur_radius=ctx.args['shadow_blur_radius'], shadow_blur_radius=ctx.args['shadow_blur_radius'] or settings.highlight.shadow_blur_radius,
shadow_offset_x=ctx.args['shadow_offset_x'], shadow_offset_x=ctx.args['shadow_offset_x'] or settings.highlight.shadow_offset_x,
shadow_offset_y=ctx.args['shadow_offset_y'], shadow_offset_y=ctx.args['shadow_offset_y'] or settings.highlight.shadow_offset_y,
pad_horiz=ctx.args['pad_horiz'], pad_horiz=ctx.args['pad_horiz'] or settings.highlight.pad_horiz,
pad_vert=ctx.args['pad_vert'], pad_vert=ctx.args['pad_vert'] or settings.highlight.pad_vert,
highlight_lines=ctx.args['highlight_lines'], highlight_lines=ctx.args['highlight_lines'] or settings.highlight.highlight_lines,
background_image=ctx.args['background_image'], background_image=ctx.args['background_image'] or settings.highlight.background_image,
) )
# Remove any arguments that are None, and transform booleans into lowercase strings # Remove any arguments that are None, and transform booleans into lowercase strings
@ -116,14 +124,16 @@ async def highlight(bot, ctx: CommandContext):
# Get the image from the URL # Get the image from the URL
url = f'{ENDPOINT_URL}/generate?{urlencode(query)}' url = f'{ENDPOINT_URL}/generate?{urlencode(query)}'
print(url)
res = httpx.get(url) res = httpx.get(url)
if res.status_code != 200: if res.status_code != 200:
await ctx.event.respond(f'Error: {res.status_code}') await ctx.event.respond(f'Error: {res.status_code}')
return return
img = BytesIO(res.content) # Save the image to a temporary file
with NamedTemporaryFile(suffix='.png') as f:
f.write(res.content)
f.flush()
# Send the image # Send the image
await ctx.event.respond(file=img) await ctx.event.respond(file=f.name)

4
cyber_fenneko/commands/jsondump.py Normal file → Executable file
View File

@ -1,5 +1,6 @@
import time import time
import json import json
from telethon.tl.types import MessageEntityPre
from .. import bot from .. import bot
from ..internal.command_context import CommandContext from ..internal.command_context import CommandContext
from ..internal.arg_parser import Arg, ArgType from ..internal.arg_parser import Arg, ArgType
@ -28,4 +29,5 @@ async def jsondump(bot, ctx: CommandContext):
await ctx.event.respond(f'Created paste: {url}', link_preview=False) await ctx.event.respond(f'Created paste: {url}', link_preview=False)
else: else:
# Respond with the JSON # Respond with the JSON
await ctx.event.respond(f'```\n{raw}\n```', link_preview=False) entities = [MessageEntityPre(0, len(raw), "json")]
await ctx.event.respond(raw, formatting_entities=entities, link_preview=False)

24
cyber_fenneko/commands/paste.py Normal file → Executable file
View File

@ -1,7 +1,10 @@
import re
import time import time
import httpx import httpx
from telethon.tl.types import MessageEntityPre from telethon.tl.types import MessageEntityPre
from telethon.tl.custom.message import Message from telethon.tl.custom.message import Message
from cyber_fenneko.models.paste import Paste
from .. import bot from .. import bot
from ..internal.command_context import CommandContext from ..internal.command_context import CommandContext
from ..internal.arg_parser import Arg, ArgType from ..internal.arg_parser import Arg, ArgType
@ -9,11 +12,18 @@ from ..utils.paste import paste as paste_util
ENDPOINT = 'https://0x45.st/api/pastes' ENDPOINT = 'https://0x45.st/api/pastes'
@bot.command( @bot.command(
'paste', 'paste',
description='Send the contents of the replied to message to a pastebin', description='Send the contents of the replied to message to a pastebin',
args=[ args=[
Arg('language', type=ArgType.str, aliases=['lang'], default='txt', description='The language to use for syntax highlighting'), Arg('delete', default=True),
Arg('list', type=ArgType.bool, default=False, aliases=[
'l'], description='List all pastes made by the bot'),
Arg('raw', type=ArgType.bool, default=True,
description='Paste the raw markdown instead of the rendered text'),
Arg('language', type=ArgType.str, aliases=[
'lang'], default=None, description='The language to use for syntax highlighting'),
] ]
) )
async def paste(bot, ctx: CommandContext): async def paste(bot, ctx: CommandContext):
@ -24,7 +34,7 @@ async def paste(bot, ctx: CommandContext):
return return
# Get the message text # Get the message text
text = message.text text = message.text if ctx.args['raw'] else message.message
if text is None: if text is None:
await ctx.event.respond('You must reply to a text message to use this command') await ctx.event.respond('You must reply to a text message to use this command')
return return
@ -32,14 +42,16 @@ async def paste(bot, ctx: CommandContext):
# Get the language # Get the language
language = ctx.args['language'] language = ctx.args['language']
contents = '' contents = None
# Check if the message has entities; any pre entities will be used as the contents # Check if the message has entities; any pre entities will be used as the contents
if message.entities is not None: if message.entities is not None:
for entity in message.entities: for entity in message.entities:
if isinstance(entity, MessageEntityPre): if entity.CONSTRUCTOR_ID == MessageEntityPre.CONSTRUCTOR_ID:
contents += text[entity.offset:entity.offset + entity.length] if entity.language is not None:
contents += '\n\n' language = entity.language
contents = text[entity.offset:entity.offset + entity.length]
contents = re.sub(r'```\n?', '', contents)
break break
if not contents: if not contents:

1
cyber_fenneko/commands/ping.py Normal file → Executable file
View File

@ -1,7 +1,6 @@
import time import time
from .. import bot from .. import bot
from ..internal.command_context import CommandContext from ..internal.command_context import CommandContext
from ..internal.arg_parser import Arg, ArgType
@bot.command( @bot.command(
'ping', 'ping',

View File

@ -0,0 +1,64 @@
import time
from typing import List
from mongoengine import EmbeddedDocumentField, StringField, IntField, BooleanField, EnumField
from cyber_fenneko.internal.arg_parser import Arg, ArgType
from cyber_fenneko.models.settings import Settings
from .. import bot
from ..internal.command_context import CommandContext
def mongo_field_to_arg_type(field):
if isinstance(field, StringField):
return ArgType.str
elif isinstance(field, IntField):
return ArgType.int
elif isinstance(field, BooleanField):
return ArgType.bool
elif isinstance(field, EnumField):
return ArgType.enum
else:
return ArgType.str
# Build the args object for the settings command using the fields from the Settings model.
# Keys are the field names, values are the field types. With EmbeddedDocuments, the key
# is the Settings object property name and the embedded document's field name,
# concaternated with a period. Ex. 'highlight.theme'.
setings_args: List[Arg] = []
for field in Settings._fields:
if isinstance(Settings._fields[field], EmbeddedDocumentField):
for embedded_field in Settings._fields[field].document_type._fields:
if embedded_field == 'id':
continue
name = f'{field}.{embedded_field}'
kind = mongo_field_to_arg_type(Settings._fields[field].document_type._fields[embedded_field])
setings_args.append(Arg(name, type=kind))
else:
if field == 'id':
continue
kind = mongo_field_to_arg_type(Settings._fields[field])
setings_args.append(Arg(field, type=kind))
@bot.command(
'settings',
aliases=['s', 'set'],
args=setings_args,
description='Change the bot\'s settings',
)
async def settings(bot, ctx: CommandContext):
"""Change the bot's settings"""
# Get the settings object
settings = Settings.objects.first()
# Find all args that have a value, and set them on the settings object
for arg in ctx.args:
if ctx.args[arg] is not None:
if '.' in arg:
parts = arg.split('.')
setattr(getattr(settings, parts[0]), parts[1], ctx.args[arg])
else:
setattr(settings, arg, ctx.args[arg])
# Save the settings object
settings.save()
await ctx.reply('Settings updated')

112
cyber_fenneko/commands/user.py Executable file
View File

@ -0,0 +1,112 @@
import time
from telethon.tl.types import User
from telethon.functions import messages
from cyber_fenneko.internal.arg_parser import Arg, ArgType
from cyber_fenneko.utils import format_bool, format_user_status
from cyber_fenneko.bot import Bot
from .. import bot
from ..internal.command_context import CommandContext
@bot.command(
'user',
aliases=['u'],
args = [
Arg('user', type=ArgType.peer, aliases=['u'], description='The user to get information about'),
Arg('id', type=ArgType.bool, aliases=['i'], default=True, description='Return only the user ID'),
Arg('mention', type=ArgType.bool, aliases=['m'], default=False, description='Whether to mention the user in the response'),
Arg('check_forward', type=ArgType.bool, aliases=['fwd'], default=True, description='Whether to check the forward from the reply message'),
Arg('full', type=ArgType.bool, aliases=['f'], default=False, description='Whether to get full information about the user'),
Arg('general', type=ArgType.bool, aliases=['g'], default=False, description='Whether to show general information about the user'),
Arg('common_chats', type=ArgType.bool, aliases=['chats'], default=False, description='Whether to get the user\'s common chats'),
Arg('meta', type=ArgType.bool, default=False, description='Extra infomation about the user that didn\'t fit in the other categories'),
],
description='Gather and return information about the given user',
)
async def user(bot: Bot, ctx: CommandContext):
user: User = ctx.args['user']
if not user:
# Attempt to get the user from the reply message
message = ctx.reply_to
if message:
try:
if ctx.args['check_forward'] and message.forward:
user = await message.forward.get_sender()
else:
user = await message.get_sender()
except:
await ctx.event.respond('Failed to get user from reply message')
return
if not user:
await ctx.event.respond('You must specify a user to get information about')
return
mention = ctx.args['mention']
show_full = ctx.args['full']
id = ctx.args['id']
show_general = show_full or ctx.args['general']
show_meta = show_full or ctx.args['meta']
show_common_chats = show_full or ctx.args['common_chats']
if show_general or show_meta or show_common_chats:
id = False
# Screen name (first name + last name if available)
screen_name = user.first_name
if user.last_name:
screen_name += f' {user.last_name}'
# Start building a response
response = ''
if id:
if mention:
response += f'[{screen_name}](tg://user?id={user.id}) (`{user.id}`)'
else:
response += f'**{screen_name}**: {user.id}'
else:
if mention:
response += f'[{screen_name}](tg://user?id={user.id}) (`{user.id}`):\n'
else:
response += f'**{screen_name}** ({user.id})\n'
# General
if show_general:
response += f'**general**\n'
response += f' username: `{user.username}`\n'
response += f' phone: `{user.phone}`\n'
response += f' bot: {format_bool(user.bot)}\n'
response += f' verified: {format_bool(user.verified)}\n'
response += f' restricted: {format_bool(user.restricted)}\n'
response += f' support: {format_bool(user.support)}\n'
response += f' scam: {format_bool(user.scam)}\n'
response += f' fake: {format_bool(user.fake)}\n'
# Common chats
if show_common_chats:
response += f'**common chats**\n'
common_chats = await bot.client(messages.GetCommonChatsRequest(user.id, 0, 200))
for chat in common_chats.chats:
response += f' {chat.title} ({chat.id})\n'
# Meta
if show_meta:
response += f'**meta**\n'
response += f' access_hash: `{user.access_hash}`\n'
response += f' bot_chat_history: {format_bool(user.bot_chat_history)}\n'
response += f' bot_nochats: {format_bool(user.bot_nochats)}\n'
response += f' bot_inline_geo: {format_bool(user.bot_inline_geo)}\n'
response += f' min: {format_bool(user.min)}\n'
response += f' bot_inline_placeholder: {format_bool(user.bot_inline_placeholder)}\n'
response += f' lang_code: `{user.lang_code}`\n'
response += f' status: `{format_user_status(user.status)}`\n'
response += f' bot_info_version: `{user.bot_info_version}`\n'
response += f' restriction_reason: `{user.restriction_reason}`\n'
response += f' bot_inline_geo: {format_bool(user.bot_inline_geo)}\n'
# Send the response
await ctx.reply(response, link_preview=False, parse_mode='markdown')

51
cyber_fenneko/internal/arg_parser.py Normal file → Executable file
View File

@ -2,8 +2,10 @@ import logging
from enum import Enum from enum import Enum
from typing import Dict, List, Union from typing import Dict, List, Union
from telethon import TelegramClient
ArgType = Enum('ArgType', ['str', 'int', 'bool', 'peer_id'])
ArgType = Enum('ArgType', ['str', 'int', 'bool', 'enum', 'peer'])
logger = logging.getLogger('cyber_fenneko.internal.arg_parser') logger = logging.getLogger('cyber_fenneko.internal.arg_parser')
@ -29,6 +31,9 @@ class Arg:
# Special designation for global args # Special designation for global args
global_arg: bool = False, global_arg: bool = False,
# If the type is enum, this is the list of valid values
enum_values: List[str] = None,
): ):
self.name = name self.name = name
self.type = type self.type = type
@ -37,8 +42,25 @@ class Arg:
self.default = default self.default = default
self.description = description self.description = description
self.global_arg = global_arg self.global_arg = global_arg
self.enum_values = enum_values
def parse_args(text: str, cmd_args: List[Arg]) -> (Dict[str, Arg], str): def merge(self, other: 'Arg'):
"""
Merge the values of another arg into this one.
"""
self.name = self.name if self.name is not None else other.name
self.type = self.type if self.type is not None else other.type
self.aliases = self.aliases if self.aliases is not None else other.aliases
self.required = self.required if self.required is not None else other.required
self.default = self.default if self.default is not None else other.default
self.description = self.description if self.description is not None else other.description
self.global_arg = self.global_arg if self.global_arg is not None else other.global_arg
self.enum_values = self.enum_values if self.enum_values is not None else other.enum_values
def __repr__(self) -> str:
return f'Arg({self.name}, type={self.type}, aliases={self.aliases}, required={self.required}, default={self.default}, description={self.description}, global_arg={self.global_arg}, enum_values={self.enum_values})'
def parse_args(client: TelegramClient, text: str, cmd_args: List[Arg]) -> (Dict[str, Arg], str):
""" """
Take an incoming string and parse args from it. Take an incoming string and parse args from it.
Args are defined one of three ways: Args are defined one of three ways:
@ -96,6 +118,30 @@ def parse_args(text: str, cmd_args: List[Arg]) -> (Dict[str, Arg], str):
raise ValueError(f'Unterminated string for arg "{arg.name}"') raise ValueError(f'Unterminated string for arg "{arg.name}"')
arg_value = arg_value[1:-1] arg_value = arg_value[1:-1]
parsed_args[arg.name] = arg_value parsed_args[arg.name] = arg_value
elif arg.type == ArgType.enum:
# if the arg is an enum, we need to check if the value is valid
if arg_value in arg.enum_values:
parsed_args[arg.name] = arg_value
else:
raise ValueError(f'Invalid enum value {arg_value} for arg "{arg.name}"')
elif arg.type == ArgType.peer:
# peer is a special type that can be a username, user id, or chat id.
# we need to fetch the user or chat that the id belongs to.
# Check if the arg value is an int, if so it's a user or chat id
int_value = None
try:
int_value = int(arg_value)
except ValueError:
pass
id_or_username = int_value if int_value is not None else arg_value
try:
entity = client.get_entity(id_or_username)
parsed_args[arg.name] = entity
except ValueError:
raise ValueError(f'{arg_value} is not a valid user or chat id or username')
elif arg.type == ArgType.bool: elif arg.type == ArgType.bool:
# if the arg is a boolean, we need to check if the value is true or false # if the arg is a boolean, we need to check if the value is true or false
if arg_value.lower() == 'true': if arg_value.lower() == 'true':
@ -118,6 +164,7 @@ def parse_args(text: str, cmd_args: List[Arg]) -> (Dict[str, Arg], str):
# If we get here, we've encountered a non-arg token # If we get here, we've encountered a non-arg token
# so we stop parsing # so we stop parsing
tokens.insert(0, token)
break break
# Check if any required args are missing # Check if any required args are missing

27
cyber_fenneko/internal/command.py Normal file → Executable file
View File

@ -51,6 +51,14 @@ class Command:
self.description = description self.description = description
self.args = args self.args = args
for arg in GLOBAL_ARGS:
if arg.name not in [a.name for a in self.args]:
self.args.append(arg)
else:
for a in self.args:
if a.name == arg.name:
a.merge(arg)
def __call__(self, *args, **kwargs): def __call__(self, *args, **kwargs):
return self.func(*args, **kwargs) return self.func(*args, **kwargs)
@ -85,14 +93,27 @@ class Command:
help_string += f'`{arg.name}' help_string += f'`{arg.name}'
if arg.aliases: if arg.aliases:
help_string += f' ({", ".join(arg.aliases)})' help_string += f' ({", ".join(arg.aliases)})'
help_string += f': {arg.type.name}`\n {arg.description}\n' help_string += f': {arg.type.name}'
if arg.default is not None:
help_string += f' = {arg.default}'
help_string += '`\n'
if arg.description:
help_string += f' {arg.description}\n'
help_string += '\n' help_string += '\n'
for arg in args: for arg in command_args:
help_string += f'`{arg.name}' help_string += f'`{arg.name}'
if arg.aliases: if arg.aliases:
help_string += f' ({", ".join(arg.aliases)})' help_string += f' ({", ".join(arg.aliases)})'
help_string += f': {arg.type.name}`\n {arg.description}\n' help_string += f': {arg.type.name}'
if arg.default is not None:
help_string += f' = {arg.default}'
help_string += '`\n'
if arg.description:
help_string += f' {arg.description}\n'
help_string += '\n' help_string += '\n'
return help_string return help_string
def __repr__(self) -> str:
return f'Command({self.command}, prefix={self.prefix}, incoming={self.incoming}, outgoing={self.outgoing}, aliases={self.aliases}, silent={self.silent}, hidden={self.hidden}, usage={self.usage}, description={self.description}, args={self.args})'

3
cyber_fenneko/internal/command_context.py Normal file → Executable file
View File

@ -54,3 +54,6 @@ class CommandContext:
async def reply(self, *args, **kwargs): async def reply(self, *args, **kwargs):
"""Reply to the message that triggered this command.""" """Reply to the message that triggered this command."""
await self.message.reply(*args, **kwargs) await self.message.reply(*args, **kwargs)
def __repr__(self) -> str:
return f'CommandContext(raw_text={self.raw_text}, text={self.text}, args={self.args})'

3
cyber_fenneko/internal/constants.py Normal file → Executable file
View File

@ -1,5 +1,8 @@
import os
from .arg_parser import Arg, ArgType from .arg_parser import Arg, ArgType
OPENAI_API_KEY = os.getenv('OPENAI_API_KEY')
# Args that exist on every command # Args that exist on every command
GLOBAL_ARGS = [ GLOBAL_ARGS = [
Arg("delete", type=ArgType.bool, aliases=['d', 'del'], default=False, description="Delete the message that triggered this command", global_arg=True) Arg("delete", type=ArgType.bool, aliases=['d', 'del'], default=False, description="Delete the message that triggered this command", global_arg=True)

0
cyber_fenneko/internal/utils.py Normal file → Executable file
View File

View File

@ -0,0 +1,26 @@
from datetime import datetime
from telethon.tl.types import User, TypeMessage, MessageEmpty, UpdateNewMessage, UpdateNewChannelMessage, PeerUser, PeerChat, PeerChannel
from .. import bot
from cyber_fenneko.models.entity import Entity
@bot.on(UpdateNewMessage, UpdateNewChannelMessage)
async def caching(bot, update):
message: TypeMessage = update.message
if isinstance(message, MessageEmpty):
return
from_id = message.from_id
if isinstance(from_id, PeerUser):
# Grab the user from the database
peer_user = Entity.objects(pk=from_id.user_id).first()
if peer_user is not None:
# Only update if it doesn't have a username or hasn't been updated in the last 24 hours
if (peer_user.username is None) or (peer_user.updated_at is not None and (datetime.utcnow() - peer_user.updated_at).total_seconds() > 86400):
try:
# Leave the creation to Telethon, we're just going to update the fields
user: User = await bot.client.get_entity(from_id.user_id)
peer_user.updated_at = datetime.utcnow()
peer_user.save()
except:
pass

18
cyber_fenneko/models/entity.py Executable file
View File

@ -0,0 +1,18 @@
from mongoengine import Document, IntField, StringField, DateTimeField
class Entity(Document):
id = IntField(primary_key=True)
hash = IntField(required=True)
username = StringField()
phone = StringField()
name = StringField()
created_at = DateTimeField()
updated_at = DateTimeField(required=True)
meta = {
'collection': 'telethon_entities',
'indexes': [
'username',
'phone',
'name'
]
}

12
cyber_fenneko/models/paste.py Executable file
View File

@ -0,0 +1,12 @@
from .entity import Entity
from mongoengine import Document, StringField, DateTimeField, IntField, BooleanField
from datetime import datetime
class Paste(Document):
"""Contains a record of a paste creation on Paste69"""
url = StringField(required=True)
language = StringField(required=True)
chat = Entity()
author = Entity()
message_id = IntField()
created_at = DateTimeField(default=datetime.utcnow)

View File

@ -0,0 +1,52 @@
from .entity import Entity
from mongoengine import Document, StringField, DateTimeField, IntField, BooleanField, EmbeddedDocument, EmbeddedDocumentField
from datetime import datetime
# Arg('theme', type=ArgType.str, description='The theme to use for syntax highlighting'),
# Arg('font', type=ArgType.str, description='The font to use'),
# Arg('shadow_color', type=ArgType.str, description='The color of the shadow'),
# Arg('background', type=ArgType.str, description='The background color'),
# Arg('tab_width', type=ArgType.int, description='The tab width'),
# Arg('line_pad', type=ArgType.int, description='The line padding'),
# Arg('line_offset', type=ArgType.int, description='The line offset'),
# Arg('window_title', type=ArgType.str, description='The window title'),
# Arg('no_line_number', type=ArgType.bool, description='Whether to hide the line numbers'),
# Arg('no_round_corner', type=ArgType.bool, description='Whether to round the corners'),
# Arg('no_window_controls', type=ArgType.bool, description='Whether to hide the window controls'),
# Arg('shadow_blur_radius', type=ArgType.int, description='The shadow blur radius'),
# Arg('shadow_offset_x', type=ArgType.int, description='The shadow offset x'),
# Arg('shadow_offset_y', type=ArgType.int, description='The shadow offset y'),
# Arg('pad_horiz', type=ArgType.int, default=10, description='The horizontal padding'),
# Arg('pad_vert', type=ArgType.int, default=10, description='The vertical padding'),
# Arg('highlight_lines', type=ArgType.str, description='The lines to highlight'),
# Arg('background_image', type=ArgType.str, description='The background image for the padding area as a URL'),
class HighlightSettings(EmbeddedDocument):
"""Stores settings for the highlight command"""
theme = StringField()
font = StringField()
shadow_color = StringField()
background = StringField()
tab_width = IntField()
line_pad = IntField()
line_offset = IntField()
window_title = StringField()
no_line_number = BooleanField()
no_round_corner = BooleanField()
no_window_controls = BooleanField()
shadow_blur_radius = IntField()
shadow_offset_x = IntField()
shadow_offset_y = IntField()
pad_horiz = IntField()
pad_vert = IntField()
highlight_lines = StringField()
background_image = StringField()
class Settings(Document):
"""Stores configuration settings for the bot"""
highlight = EmbeddedDocumentField(HighlightSettings)
meta = {
'collection': 'settings'
}

40
cyber_fenneko/utils/__init__.py Executable file
View File

@ -0,0 +1,40 @@
from telethon.tl.types import TypeUserStatus, UserStatusRecently, UserStatusOnline, UserStatusOffline, UserStatusLastWeek, UserStatusLastMonth, UserStatusEmpty
# Format time (in ms) to a human readable format.
def format_time(ms: float) -> str:
time = str('%.2f', ms)
unit = 'millis'
if time > 1000000:
mins = time / 60000
secs = time % 60000
time = '%d.%.2f' % (mins, secs)
unit = 'mins'
if time > 1000:
secs = time / 1000
millis = time % 1000
time = '%d.%.2f' % (secs, millis)
unit = 'secs'
return f'{time} {unit}'
# Format a boolean as a simple yes/no string.
def format_bool(value: bool) -> str:
return 'Yes' if value else 'No'
# Convert a TypeUserStatus to a string.
def format_user_status(status: TypeUserStatus) -> str:
if isinstance(status, UserStatusRecently):
return 'Recently'
elif isinstance(status, UserStatusOnline):
return 'Online'
elif isinstance(status, UserStatusOffline):
return 'Offline'
elif isinstance(status, UserStatusLastWeek):
return 'Last week'
elif isinstance(status, UserStatusLastMonth):
return 'Last month'
elif isinstance(status, UserStatusEmpty):
return 'Empty'
else:
return 'Unknown'

1
cyber_fenneko/utils/paste.py Normal file → Executable file
View File

@ -9,6 +9,7 @@ def paste(text: str, language: str = 'txt', password = None, burn = False) -> st
'contents': text, 'contents': text,
'password': password, 'password': password,
'burnAfterReading': burn, 'burnAfterReading': burn,
'raw': True,
} }
response = httpx.post(ENDPOINT, json=data) response = httpx.post(ENDPOINT, json=data)

435
poetry.lock generated
View File

@ -1,14 +1,25 @@
# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. # This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand.
[[package]] [[package]]
name = "anyio" name = "annotated-types"
version = "4.0.0" version = "0.6.0"
description = "High level compatibility layer for multiple asynchronous event loop implementations" description = "Reusable constraint types to use with typing.Annotated"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "anyio-4.0.0-py3-none-any.whl", hash = "sha256:cfdb2b588b9fc25ede96d8db56ed50848b0b649dca3dd1df0b11f683bb9e0b5f"}, {file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"},
{file = "anyio-4.0.0.tar.gz", hash = "sha256:f7ed51751b2c2add651e5747c891b47e26d2a21be5d32d9311dfe9692f3e5d7a"}, {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"},
]
[[package]]
name = "anyio"
version = "3.7.1"
description = "High level compatibility layer for multiple asynchronous event loop implementations"
optional = false
python-versions = ">=3.7"
files = [
{file = "anyio-3.7.1-py3-none-any.whl", hash = "sha256:91dee416e570e92c64041bd18b900d1d6fa78dff7048769ce5ac5ddad004fbb5"},
{file = "anyio-3.7.1.tar.gz", hash = "sha256:44a3c9aba0f5defa43261a8b3efb97891f2bd7d804e0e1f56419befa1adfc780"},
] ]
[package.dependencies] [package.dependencies]
@ -16,9 +27,9 @@ idna = ">=2.8"
sniffio = ">=1.1" sniffio = ">=1.1"
[package.extras] [package.extras]
doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)"] doc = ["Sphinx", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme (>=1.2.2)", "sphinxcontrib-jquery"]
test = ["anyio[trio]", "coverage[toml] (>=7)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] test = ["anyio[trio]", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"]
trio = ["trio (>=0.22)"] trio = ["trio (<0.22)"]
[[package]] [[package]]
name = "certifi" name = "certifi"
@ -31,6 +42,47 @@ files = [
{file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"}, {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"},
] ]
[[package]]
name = "colorama"
version = "0.4.6"
description = "Cross-platform colored terminal text."
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
files = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
]
[[package]]
name = "distro"
version = "1.8.0"
description = "Distro - an OS platform information API"
optional = false
python-versions = ">=3.6"
files = [
{file = "distro-1.8.0-py3-none-any.whl", hash = "sha256:99522ca3e365cac527b44bde033f64c6945d90eb9f769703caaec52b09bbd3ff"},
{file = "distro-1.8.0.tar.gz", hash = "sha256:02e111d1dc6a50abb8eed6bf31c3e48ed8b0830d1ea2a1b78c61765c2513fdd8"},
]
[[package]]
name = "dnspython"
version = "2.4.2"
description = "DNS toolkit"
optional = false
python-versions = ">=3.8,<4.0"
files = [
{file = "dnspython-2.4.2-py3-none-any.whl", hash = "sha256:57c6fbaaeaaf39c891292012060beb141791735dbb4004798328fc2c467402d8"},
{file = "dnspython-2.4.2.tar.gz", hash = "sha256:8dcfae8c7460a2f84b4072e26f1c9f4101ca20c071649cb7c34e8b6a93d58984"},
]
[package.extras]
dnssec = ["cryptography (>=2.6,<42.0)"]
doh = ["h2 (>=4.1.0)", "httpcore (>=0.17.3)", "httpx (>=0.24.1)"]
doq = ["aioquic (>=0.9.20)"]
idna = ["idna (>=2.1,<4.0)"]
trio = ["trio (>=0.14,<0.23)"]
wmi = ["wmi (>=1.5.1,<2.0.0)"]
[[package]] [[package]]
name = "h11" name = "h11"
version = "0.14.0" version = "0.14.0"
@ -97,6 +149,77 @@ files = [
{file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
] ]
[[package]]
name = "markdown-it-py"
version = "3.0.0"
description = "Python port of markdown-it. Markdown parsing, done right!"
optional = false
python-versions = ">=3.8"
files = [
{file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"},
{file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"},
]
[package.dependencies]
mdurl = ">=0.1,<1.0"
[package.extras]
benchmarking = ["psutil", "pytest", "pytest-benchmark"]
code-style = ["pre-commit (>=3.0,<4.0)"]
compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"]
linkify = ["linkify-it-py (>=1,<3)"]
plugins = ["mdit-py-plugins"]
profiling = ["gprof2dot"]
rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"]
testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
[[package]]
name = "mdurl"
version = "0.1.2"
description = "Markdown URL utilities"
optional = false
python-versions = ">=3.7"
files = [
{file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
{file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
]
[[package]]
name = "mongoengine"
version = "0.27.0"
description = "MongoEngine is a Python Object-Document Mapper for working with MongoDB."
optional = false
python-versions = ">=3.7"
files = [
{file = "mongoengine-0.27.0-py3-none-any.whl", hash = "sha256:c3523b8f886052f3deb200b3218bcc13e4b781661e3bea38587cc936c80ea358"},
{file = "mongoengine-0.27.0.tar.gz", hash = "sha256:8f38df7834dc4b192d89f2668dcf3091748d12f74d55648ce77b919167a4a49b"},
]
[package.dependencies]
pymongo = ">=3.4,<5.0"
[[package]]
name = "openai"
version = "1.0.0rc1"
description = "Client library for the openai API"
optional = false
python-versions = ">=3.7.1"
files = [
{file = "openai-1.0.0rc1-py3-none-any.whl", hash = "sha256:a2075ef79acdae200798999b33782e99a48a64fd6ca61f7691d5b25a179fdc1c"},
{file = "openai-1.0.0rc1.tar.gz", hash = "sha256:f082b0158529f5d826155b065493994bcdfd66d46045805668a4ad57fdfc0b24"},
]
[package.dependencies]
anyio = ">=3.5.0,<4"
distro = ">=1.7.0,<2"
httpx = ">=0.23.0,<1"
pydantic = ">=1.9.0,<3"
tqdm = ">4"
typing-extensions = ">=4.5,<5"
[package.extras]
datalib = ["numpy (>=1)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)"]
[[package]] [[package]]
name = "pyaes" name = "pyaes"
version = "1.6.1" version = "1.6.1"
@ -118,6 +241,244 @@ files = [
{file = "pyasn1-0.5.0.tar.gz", hash = "sha256:97b7290ca68e62a832558ec3976f15cbf911bf5d7c7039d8b861c2a0ece69fde"}, {file = "pyasn1-0.5.0.tar.gz", hash = "sha256:97b7290ca68e62a832558ec3976f15cbf911bf5d7c7039d8b861c2a0ece69fde"},
] ]
[[package]]
name = "pydantic"
version = "2.4.2"
description = "Data validation using Python type hints"
optional = false
python-versions = ">=3.7"
files = [
{file = "pydantic-2.4.2-py3-none-any.whl", hash = "sha256:bc3ddf669d234f4220e6e1c4d96b061abe0998185a8d7855c0126782b7abc8c1"},
{file = "pydantic-2.4.2.tar.gz", hash = "sha256:94f336138093a5d7f426aac732dcfe7ab4eb4da243c88f891d65deb4a2556ee7"},
]
[package.dependencies]
annotated-types = ">=0.4.0"
pydantic-core = "2.10.1"
typing-extensions = ">=4.6.1"
[package.extras]
email = ["email-validator (>=2.0.0)"]
[[package]]
name = "pydantic-core"
version = "2.10.1"
description = ""
optional = false
python-versions = ">=3.7"
files = [
{file = "pydantic_core-2.10.1-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:d64728ee14e667ba27c66314b7d880b8eeb050e58ffc5fec3b7a109f8cddbd63"},
{file = "pydantic_core-2.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:48525933fea744a3e7464c19bfede85df4aba79ce90c60b94d8b6e1eddd67096"},
{file = "pydantic_core-2.10.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef337945bbd76cce390d1b2496ccf9f90b1c1242a3a7bc242ca4a9fc5993427a"},
{file = "pydantic_core-2.10.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a1392e0638af203cee360495fd2cfdd6054711f2db5175b6e9c3c461b76f5175"},
{file = "pydantic_core-2.10.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0675ba5d22de54d07bccde38997e780044dcfa9a71aac9fd7d4d7a1d2e3e65f7"},
{file = "pydantic_core-2.10.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:128552af70a64660f21cb0eb4876cbdadf1a1f9d5de820fed6421fa8de07c893"},
{file = "pydantic_core-2.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f6e6aed5818c264412ac0598b581a002a9f050cb2637a84979859e70197aa9e"},
{file = "pydantic_core-2.10.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ecaac27da855b8d73f92123e5f03612b04c5632fd0a476e469dfc47cd37d6b2e"},
{file = "pydantic_core-2.10.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b3c01c2fb081fced3bbb3da78510693dc7121bb893a1f0f5f4b48013201f362e"},
{file = "pydantic_core-2.10.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:92f675fefa977625105708492850bcbc1182bfc3e997f8eecb866d1927c98ae6"},
{file = "pydantic_core-2.10.1-cp310-none-win32.whl", hash = "sha256:420a692b547736a8d8703c39ea935ab5d8f0d2573f8f123b0a294e49a73f214b"},
{file = "pydantic_core-2.10.1-cp310-none-win_amd64.whl", hash = "sha256:0880e239827b4b5b3e2ce05e6b766a7414e5f5aedc4523be6b68cfbc7f61c5d0"},
{file = "pydantic_core-2.10.1-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:073d4a470b195d2b2245d0343569aac7e979d3a0dcce6c7d2af6d8a920ad0bea"},
{file = "pydantic_core-2.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:600d04a7b342363058b9190d4e929a8e2e715c5682a70cc37d5ded1e0dd370b4"},
{file = "pydantic_core-2.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39215d809470f4c8d1881758575b2abfb80174a9e8daf8f33b1d4379357e417c"},
{file = "pydantic_core-2.10.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eeb3d3d6b399ffe55f9a04e09e635554012f1980696d6b0aca3e6cf42a17a03b"},
{file = "pydantic_core-2.10.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a7a7902bf75779bc12ccfc508bfb7a4c47063f748ea3de87135d433a4cca7a2f"},
{file = "pydantic_core-2.10.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3625578b6010c65964d177626fde80cf60d7f2e297d56b925cb5cdeda6e9925a"},
{file = "pydantic_core-2.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:caa48fc31fc7243e50188197b5f0c4228956f97b954f76da157aae7f67269ae8"},
{file = "pydantic_core-2.10.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:07ec6d7d929ae9c68f716195ce15e745b3e8fa122fc67698ac6498d802ed0fa4"},
{file = "pydantic_core-2.10.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e6f31a17acede6a8cd1ae2d123ce04d8cca74056c9d456075f4f6f85de055607"},
{file = "pydantic_core-2.10.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d8f1ebca515a03e5654f88411420fea6380fc841d1bea08effb28184e3d4899f"},
{file = "pydantic_core-2.10.1-cp311-none-win32.whl", hash = "sha256:6db2eb9654a85ada248afa5a6db5ff1cf0f7b16043a6b070adc4a5be68c716d6"},
{file = "pydantic_core-2.10.1-cp311-none-win_amd64.whl", hash = "sha256:4a5be350f922430997f240d25f8219f93b0c81e15f7b30b868b2fddfc2d05f27"},
{file = "pydantic_core-2.10.1-cp311-none-win_arm64.whl", hash = "sha256:5fdb39f67c779b183b0c853cd6b45f7db84b84e0571b3ef1c89cdb1dfc367325"},
{file = "pydantic_core-2.10.1-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:b1f22a9ab44de5f082216270552aa54259db20189e68fc12484873d926426921"},
{file = "pydantic_core-2.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8572cadbf4cfa95fb4187775b5ade2eaa93511f07947b38f4cd67cf10783b118"},
{file = "pydantic_core-2.10.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db9a28c063c7c00844ae42a80203eb6d2d6bbb97070cfa00194dff40e6f545ab"},
{file = "pydantic_core-2.10.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e2a35baa428181cb2270a15864ec6286822d3576f2ed0f4cd7f0c1708472aff"},
{file = "pydantic_core-2.10.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05560ab976012bf40f25d5225a58bfa649bb897b87192a36c6fef1ab132540d7"},
{file = "pydantic_core-2.10.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d6495008733c7521a89422d7a68efa0a0122c99a5861f06020ef5b1f51f9ba7c"},
{file = "pydantic_core-2.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14ac492c686defc8e6133e3a2d9eaf5261b3df26b8ae97450c1647286750b901"},
{file = "pydantic_core-2.10.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8282bab177a9a3081fd3d0a0175a07a1e2bfb7fcbbd949519ea0980f8a07144d"},
{file = "pydantic_core-2.10.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:aafdb89fdeb5fe165043896817eccd6434aee124d5ee9b354f92cd574ba5e78f"},
{file = "pydantic_core-2.10.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f6defd966ca3b187ec6c366604e9296f585021d922e666b99c47e78738b5666c"},
{file = "pydantic_core-2.10.1-cp312-none-win32.whl", hash = "sha256:7c4d1894fe112b0864c1fa75dffa045720a194b227bed12f4be7f6045b25209f"},
{file = "pydantic_core-2.10.1-cp312-none-win_amd64.whl", hash = "sha256:5994985da903d0b8a08e4935c46ed8daf5be1cf217489e673910951dc533d430"},
{file = "pydantic_core-2.10.1-cp312-none-win_arm64.whl", hash = "sha256:0d8a8adef23d86d8eceed3e32e9cca8879c7481c183f84ed1a8edc7df073af94"},
{file = "pydantic_core-2.10.1-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:9badf8d45171d92387410b04639d73811b785b5161ecadabf056ea14d62d4ede"},
{file = "pydantic_core-2.10.1-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:ebedb45b9feb7258fac0a268a3f6bec0a2ea4d9558f3d6f813f02ff3a6dc6698"},
{file = "pydantic_core-2.10.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfe1090245c078720d250d19cb05d67e21a9cd7c257698ef139bc41cf6c27b4f"},
{file = "pydantic_core-2.10.1-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e357571bb0efd65fd55f18db0a2fb0ed89d0bb1d41d906b138f088933ae618bb"},
{file = "pydantic_core-2.10.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b3dcd587b69bbf54fc04ca157c2323b8911033e827fffaecf0cafa5a892a0904"},
{file = "pydantic_core-2.10.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c120c9ce3b163b985a3b966bb701114beb1da4b0468b9b236fc754783d85aa3"},
{file = "pydantic_core-2.10.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15d6bca84ffc966cc9976b09a18cf9543ed4d4ecbd97e7086f9ce9327ea48891"},
{file = "pydantic_core-2.10.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5cabb9710f09d5d2e9e2748c3e3e20d991a4c5f96ed8f1132518f54ab2967221"},
{file = "pydantic_core-2.10.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:82f55187a5bebae7d81d35b1e9aaea5e169d44819789837cdd4720d768c55d15"},
{file = "pydantic_core-2.10.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:1d40f55222b233e98e3921df7811c27567f0e1a4411b93d4c5c0f4ce131bc42f"},
{file = "pydantic_core-2.10.1-cp37-none-win32.whl", hash = "sha256:14e09ff0b8fe6e46b93d36a878f6e4a3a98ba5303c76bb8e716f4878a3bee92c"},
{file = "pydantic_core-2.10.1-cp37-none-win_amd64.whl", hash = "sha256:1396e81b83516b9d5c9e26a924fa69164156c148c717131f54f586485ac3c15e"},
{file = "pydantic_core-2.10.1-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:6835451b57c1b467b95ffb03a38bb75b52fb4dc2762bb1d9dbed8de31ea7d0fc"},
{file = "pydantic_core-2.10.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b00bc4619f60c853556b35f83731bd817f989cba3e97dc792bb8c97941b8053a"},
{file = "pydantic_core-2.10.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fa467fd300a6f046bdb248d40cd015b21b7576c168a6bb20aa22e595c8ffcdd"},
{file = "pydantic_core-2.10.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d99277877daf2efe074eae6338453a4ed54a2d93fb4678ddfe1209a0c93a2468"},
{file = "pydantic_core-2.10.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fa7db7558607afeccb33c0e4bf1c9a9a835e26599e76af6fe2fcea45904083a6"},
{file = "pydantic_core-2.10.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aad7bd686363d1ce4ee930ad39f14e1673248373f4a9d74d2b9554f06199fb58"},
{file = "pydantic_core-2.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:443fed67d33aa85357464f297e3d26e570267d1af6fef1c21ca50921d2976302"},
{file = "pydantic_core-2.10.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:042462d8d6ba707fd3ce9649e7bf268633a41018d6a998fb5fbacb7e928a183e"},
{file = "pydantic_core-2.10.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ecdbde46235f3d560b18be0cb706c8e8ad1b965e5c13bbba7450c86064e96561"},
{file = "pydantic_core-2.10.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ed550ed05540c03f0e69e6d74ad58d026de61b9eaebebbaaf8873e585cbb18de"},
{file = "pydantic_core-2.10.1-cp38-none-win32.whl", hash = "sha256:8cdbbd92154db2fec4ec973d45c565e767ddc20aa6dbaf50142676484cbff8ee"},
{file = "pydantic_core-2.10.1-cp38-none-win_amd64.whl", hash = "sha256:9f6f3e2598604956480f6c8aa24a3384dbf6509fe995d97f6ca6103bb8c2534e"},
{file = "pydantic_core-2.10.1-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:655f8f4c8d6a5963c9a0687793da37b9b681d9ad06f29438a3b2326d4e6b7970"},
{file = "pydantic_core-2.10.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e570ffeb2170e116a5b17e83f19911020ac79d19c96f320cbfa1fa96b470185b"},
{file = "pydantic_core-2.10.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64322bfa13e44c6c30c518729ef08fda6026b96d5c0be724b3c4ae4da939f875"},
{file = "pydantic_core-2.10.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:485a91abe3a07c3a8d1e082ba29254eea3e2bb13cbbd4351ea4e5a21912cc9b0"},
{file = "pydantic_core-2.10.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7c2b8eb9fc872e68b46eeaf835e86bccc3a58ba57d0eedc109cbb14177be531"},
{file = "pydantic_core-2.10.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a5cb87bdc2e5f620693148b5f8f842d293cae46c5f15a1b1bf7ceeed324a740c"},
{file = "pydantic_core-2.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25bd966103890ccfa028841a8f30cebcf5875eeac8c4bde4fe221364c92f0c9a"},
{file = "pydantic_core-2.10.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f323306d0556351735b54acbf82904fe30a27b6a7147153cbe6e19aaaa2aa429"},
{file = "pydantic_core-2.10.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0c27f38dc4fbf07b358b2bc90edf35e82d1703e22ff2efa4af4ad5de1b3833e7"},
{file = "pydantic_core-2.10.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f1365e032a477c1430cfe0cf2856679529a2331426f8081172c4a74186f1d595"},
{file = "pydantic_core-2.10.1-cp39-none-win32.whl", hash = "sha256:a1c311fd06ab3b10805abb72109f01a134019739bd3286b8ae1bc2fc4e50c07a"},
{file = "pydantic_core-2.10.1-cp39-none-win_amd64.whl", hash = "sha256:ae8a8843b11dc0b03b57b52793e391f0122e740de3df1474814c700d2622950a"},
{file = "pydantic_core-2.10.1-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:d43002441932f9a9ea5d6f9efaa2e21458221a3a4b417a14027a1d530201ef1b"},
{file = "pydantic_core-2.10.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:fcb83175cc4936a5425dde3356f079ae03c0802bbdf8ff82c035f8a54b333521"},
{file = "pydantic_core-2.10.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:962ed72424bf1f72334e2f1e61b68f16c0e596f024ca7ac5daf229f7c26e4208"},
{file = "pydantic_core-2.10.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2cf5bb4dd67f20f3bbc1209ef572a259027c49e5ff694fa56bed62959b41e1f9"},
{file = "pydantic_core-2.10.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e544246b859f17373bed915182ab841b80849ed9cf23f1f07b73b7c58baee5fb"},
{file = "pydantic_core-2.10.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c0877239307b7e69d025b73774e88e86ce82f6ba6adf98f41069d5b0b78bd1bf"},
{file = "pydantic_core-2.10.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:53df009d1e1ba40f696f8995683e067e3967101d4bb4ea6f667931b7d4a01357"},
{file = "pydantic_core-2.10.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a1254357f7e4c82e77c348dabf2d55f1d14d19d91ff025004775e70a6ef40ada"},
{file = "pydantic_core-2.10.1-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:524ff0ca3baea164d6d93a32c58ac79eca9f6cf713586fdc0adb66a8cdeab96a"},
{file = "pydantic_core-2.10.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f0ac9fb8608dbc6eaf17956bf623c9119b4db7dbb511650910a82e261e6600f"},
{file = "pydantic_core-2.10.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:320f14bd4542a04ab23747ff2c8a778bde727158b606e2661349557f0770711e"},
{file = "pydantic_core-2.10.1-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:63974d168b6233b4ed6a0046296803cb13c56637a7b8106564ab575926572a55"},
{file = "pydantic_core-2.10.1-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:417243bf599ba1f1fef2bb8c543ceb918676954734e2dcb82bf162ae9d7bd514"},
{file = "pydantic_core-2.10.1-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:dda81e5ec82485155a19d9624cfcca9be88a405e2857354e5b089c2a982144b2"},
{file = "pydantic_core-2.10.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:14cfbb00959259e15d684505263d5a21732b31248a5dd4941f73a3be233865b9"},
{file = "pydantic_core-2.10.1-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:631cb7415225954fdcc2a024119101946793e5923f6c4d73a5914d27eb3d3a05"},
{file = "pydantic_core-2.10.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:bec7dd208a4182e99c5b6c501ce0b1f49de2802448d4056091f8e630b28e9a52"},
{file = "pydantic_core-2.10.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:149b8a07712f45b332faee1a2258d8ef1fb4a36f88c0c17cb687f205c5dc6e7d"},
{file = "pydantic_core-2.10.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d966c47f9dd73c2d32a809d2be529112d509321c5310ebf54076812e6ecd884"},
{file = "pydantic_core-2.10.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7eb037106f5c6b3b0b864ad226b0b7ab58157124161d48e4b30c4a43fef8bc4b"},
{file = "pydantic_core-2.10.1-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:154ea7c52e32dce13065dbb20a4a6f0cc012b4f667ac90d648d36b12007fa9f7"},
{file = "pydantic_core-2.10.1-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e562617a45b5a9da5be4abe72b971d4f00bf8555eb29bb91ec2ef2be348cd132"},
{file = "pydantic_core-2.10.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:f23b55eb5464468f9e0e9a9935ce3ed2a870608d5f534025cd5536bca25b1402"},
{file = "pydantic_core-2.10.1-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:e9121b4009339b0f751955baf4543a0bfd6bc3f8188f8056b1a25a2d45099934"},
{file = "pydantic_core-2.10.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:0523aeb76e03f753b58be33b26540880bac5aa54422e4462404c432230543f33"},
{file = "pydantic_core-2.10.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e0e2959ef5d5b8dc9ef21e1a305a21a36e254e6a34432d00c72a92fdc5ecda5"},
{file = "pydantic_core-2.10.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da01bec0a26befab4898ed83b362993c844b9a607a86add78604186297eb047e"},
{file = "pydantic_core-2.10.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f2e9072d71c1f6cfc79a36d4484c82823c560e6f5599c43c1ca6b5cdbd54f881"},
{file = "pydantic_core-2.10.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f36a3489d9e28fe4b67be9992a23029c3cec0babc3bd9afb39f49844a8c721c5"},
{file = "pydantic_core-2.10.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f64f82cc3443149292b32387086d02a6c7fb39b8781563e0ca7b8d7d9cf72bd7"},
{file = "pydantic_core-2.10.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b4a6db486ac8e99ae696e09efc8b2b9fea67b63c8f88ba7a1a16c24a057a0776"},
{file = "pydantic_core-2.10.1.tar.gz", hash = "sha256:0f8682dbdd2f67f8e1edddcbffcc29f60a6182b4901c367fc8c1c40d30bb0a82"},
]
[package.dependencies]
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
[[package]]
name = "pymongo"
version = "4.5.0"
description = "Python driver for MongoDB <http://www.mongodb.org>"
optional = false
python-versions = ">=3.7"
files = [
{file = "pymongo-4.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2d4fa1b01fa7e5b7bb8d312e3542e211b320eb7a4e3d8dc884327039d93cb9e0"},
{file = "pymongo-4.5.0-cp310-cp310-manylinux1_i686.whl", hash = "sha256:dfcd2b9f510411de615ccedd47462dae80e82fdc09fe9ab0f0f32f11cf57eeb5"},
{file = "pymongo-4.5.0-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:3e33064f1984db412b34d51496f4ea785a9cff621c67de58e09fb28da6468a52"},
{file = "pymongo-4.5.0-cp310-cp310-manylinux2014_i686.whl", hash = "sha256:33faa786cc907de63f745f587e9879429b46033d7d97a7b84b37f4f8f47b9b32"},
{file = "pymongo-4.5.0-cp310-cp310-manylinux2014_ppc64le.whl", hash = "sha256:76a262c41c1a7cbb84a3b11976578a7eb8e788c4b7bfbd15c005fb6ca88e6e50"},
{file = "pymongo-4.5.0-cp310-cp310-manylinux2014_s390x.whl", hash = "sha256:0f4b125b46fe377984fbaecf2af40ed48b05a4b7676a2ff98999f2016d66b3ec"},
{file = "pymongo-4.5.0-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:40d5f6e853ece9bfc01e9129b228df446f49316a4252bb1fbfae5c3c9dedebad"},
{file = "pymongo-4.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:152259f0f1a60f560323aacf463a3642a65a25557683f49cfa08c8f1ecb2395a"},
{file = "pymongo-4.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6d64878d1659d2a5bdfd0f0a4d79bafe68653c573681495e424ab40d7b6d6d41"},
{file = "pymongo-4.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1bb3a62395ffe835dbef3a1cbff48fbcce709c78bd1f52e896aee990928432b"},
{file = "pymongo-4.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe48f50fb6348511a3268a893bfd4ab5f263f5ac220782449d03cd05964d1ae7"},
{file = "pymongo-4.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7591a3beea6a9a4fa3080d27d193b41f631130e3ffa76b88c9ccea123f26dc59"},
{file = "pymongo-4.5.0-cp310-cp310-win32.whl", hash = "sha256:3a7166d57dc74d679caa7743b8ecf7dc3a1235a9fd178654dddb2b2a627ae229"},
{file = "pymongo-4.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:21b953da14549ff62ea4ae20889c71564328958cbdf880c64a92a48dda4c9c53"},
{file = "pymongo-4.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ead4f19d0257a756b21ac2e0e85a37a7245ddec36d3b6008d5bfe416525967dc"},
{file = "pymongo-4.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9aff6279e405dc953eeb540ab061e72c03cf38119613fce183a8e94f31be608f"},
{file = "pymongo-4.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd4c8d6aa91d3e35016847cbe8d73106e3d1c9a4e6578d38e2c346bfe8edb3ca"},
{file = "pymongo-4.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08819da7864f9b8d4a95729b2bea5fffed08b63d3b9c15b4fea47de655766cf5"},
{file = "pymongo-4.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a253b765b7cbc4209f1d8ee16c7287c4268d3243070bf72d7eec5aa9dfe2a2c2"},
{file = "pymongo-4.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8027c9063579083746147cf401a7072a9fb6829678076cd3deff28bb0e0f50c8"},
{file = "pymongo-4.5.0-cp311-cp311-win32.whl", hash = "sha256:9d2346b00af524757576cc2406414562cced1d4349c92166a0ee377a2a483a80"},
{file = "pymongo-4.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:c3c3525ea8658ee1192cdddf5faf99b07ebe1eeaa61bf32821126df6d1b8072b"},
{file = "pymongo-4.5.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e5a27f348909235a106a3903fc8e70f573d89b41d723a500869c6569a391cff7"},
{file = "pymongo-4.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9a9a39b7cac81dca79fca8c2a6479ef4c7b1aab95fad7544cc0e8fd943595a2"},
{file = "pymongo-4.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:496c9cbcb4951183d4503a9d7d2c1e3694aab1304262f831d5e1917e60386036"},
{file = "pymongo-4.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23cc6d7eb009c688d70da186b8f362d61d5dd1a2c14a45b890bd1e91e9c451f2"},
{file = "pymongo-4.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fff7d17d30b2cd45afd654b3fc117755c5d84506ed25fda386494e4e0a3416e1"},
{file = "pymongo-4.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6422b6763b016f2ef2beedded0e546d6aa6ba87910f9244d86e0ac7690f75c96"},
{file = "pymongo-4.5.0-cp312-cp312-win32.whl", hash = "sha256:77cfff95c1fafd09e940b3fdcb7b65f11442662fad611d0e69b4dd5d17a81c60"},
{file = "pymongo-4.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:e57d859b972c75ee44ea2ef4758f12821243e99de814030f69a3decb2aa86807"},
{file = "pymongo-4.5.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:2b0176f9233a5927084c79ff80b51bd70bfd57e4f3d564f50f80238e797f0c8a"},
{file = "pymongo-4.5.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:89b3f2da57a27913d15d2a07d58482f33d0a5b28abd20b8e643ab4d625e36257"},
{file = "pymongo-4.5.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:5caee7bd08c3d36ec54617832b44985bd70c4cbd77c5b313de6f7fce0bb34f93"},
{file = "pymongo-4.5.0-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:1d40ad09d9f5e719bc6f729cc6b17f31c0b055029719406bd31dde2f72fca7e7"},
{file = "pymongo-4.5.0-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:076afa0a4a96ca9f77fec0e4a0d241200b3b3a1766f8d7be9a905ecf59a7416b"},
{file = "pymongo-4.5.0-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:3fa3648e4f1e63ddfe53563ee111079ea3ab35c3b09cd25bc22dadc8269a495f"},
{file = "pymongo-4.5.0-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:44ee985194c426ddf781fa784f31ffa29cb59657b2dba09250a4245431847d73"},
{file = "pymongo-4.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b33c17d9e694b66d7e96977e9e56df19d662031483efe121a24772a44ccbbc7e"},
{file = "pymongo-4.5.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3d79ae3bb1ff041c0db56f138c88ce1dfb0209f3546d8d6e7c3f74944ecd2439"},
{file = "pymongo-4.5.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d67225f05f6ea27c8dc57f3fa6397c96d09c42af69d46629f71e82e66d33fa4f"},
{file = "pymongo-4.5.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41771b22dd2822540f79a877c391283d4e6368125999a5ec8beee1ce566f3f82"},
{file = "pymongo-4.5.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a1f26bc1f5ce774d99725773901820dfdfd24e875028da4a0252a5b48dcab5c"},
{file = "pymongo-4.5.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3236cf89d69679eaeb9119c840f5c7eb388a2110b57af6bb6baf01a1da387c18"},
{file = "pymongo-4.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e1f61355c821e870fb4c17cdb318669cfbcf245a291ce5053b41140870c3e5cc"},
{file = "pymongo-4.5.0-cp37-cp37m-win32.whl", hash = "sha256:49dce6957598975d8b8d506329d2a3a6c4aee911fa4bbcf5e52ffc6897122950"},
{file = "pymongo-4.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:f2227a08b091bd41df5aadee0a5037673f691e2aa000e1968b1ea2342afc6880"},
{file = "pymongo-4.5.0-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:435228d3c16a375274ac8ab9c4f9aef40c5e57ddb8296e20ecec9e2461da1017"},
{file = "pymongo-4.5.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:8e559116e4128630ad3b7e788e2e5da81cbc2344dee246af44471fa650486a70"},
{file = "pymongo-4.5.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:840eaf30ccac122df260b6005f9dfae4ac287c498ee91e3e90c56781614ca238"},
{file = "pymongo-4.5.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:b4fe46b58010115514b842c669a0ed9b6a342017b15905653a5b1724ab80917f"},
{file = "pymongo-4.5.0-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:a8127437ebc196a6f5e8fddd746bd0903a400dc6b5ae35df672dd1ccc7170a2a"},
{file = "pymongo-4.5.0-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:2988ef5e6b360b3ff1c6d55c53515499de5f48df31afd9f785d788cdacfbe2d3"},
{file = "pymongo-4.5.0-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:e249190b018d63c901678053b4a43e797ca78b93fb6d17633e3567d4b3ec6107"},
{file = "pymongo-4.5.0-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:1240edc1a448d4ada4bf1a0e55550b6292420915292408e59159fd8bbdaf8f63"},
{file = "pymongo-4.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b6d2a56fc2354bb6378f3634402eec788a8f3facf0b3e7d468db5f2b5a78d763"},
{file = "pymongo-4.5.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2a0aade2b11dc0c326ccd429ee4134d2d47459ff68d449c6d7e01e74651bd255"},
{file = "pymongo-4.5.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:74c0da07c04d0781490b2915e7514b1adb265ef22af039a947988c331ee7455b"},
{file = "pymongo-4.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3754acbd7efc7f1b529039fcffc092a15e1cf045e31f22f6c9c5950c613ec4d"},
{file = "pymongo-4.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:631492573a1bef2f74f9ac0f9d84e0ce422c251644cd81207530af4aa2ee1980"},
{file = "pymongo-4.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e2654d1278384cff75952682d17c718ecc1ad1d6227bb0068fd826ba47d426a5"},
{file = "pymongo-4.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:168172ef7856e20ec024fe2a746bfa895c88b32720138e6438fd765ebd2b62dd"},
{file = "pymongo-4.5.0-cp38-cp38-win32.whl", hash = "sha256:b25f7bea162b3dbec6d33c522097ef81df7c19a9300722fa6853f5b495aecb77"},
{file = "pymongo-4.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:b520aafc6cb148bac09ccf532f52cbd31d83acf4d3e5070d84efe3c019a1adbf"},
{file = "pymongo-4.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8543253adfaa0b802bfa88386db1009c6ebb7d5684d093ee4edc725007553d21"},
{file = "pymongo-4.5.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:bc5d8c3647b8ae28e4312f1492b8f29deebd31479cd3abaa989090fb1d66db83"},
{file = "pymongo-4.5.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:505f8519c4c782a61d94a17b0da50be639ec462128fbd10ab0a34889218fdee3"},
{file = "pymongo-4.5.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:53f2dda54d76a98b43a410498bd12f6034b2a14b6844ca08513733b2b20b7ad8"},
{file = "pymongo-4.5.0-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:9c04b9560872fa9a91251030c488e0a73bce9321a70f991f830c72b3f8115d0d"},
{file = "pymongo-4.5.0-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:58a63a26a1e3dc481dd3a18d6d9f8bd1d576cd1ffe0d479ba7dd38b0aeb20066"},
{file = "pymongo-4.5.0-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:f076b779aa3dc179aa3ed861be063a313ed4e48ae9f6a8370a9b1295d4502111"},
{file = "pymongo-4.5.0-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:1b1d7d9aabd8629a31d63cd106d56cca0e6420f38e50563278b520f385c0d86e"},
{file = "pymongo-4.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37df8f6006286a5896d1cbc3efb8471ced42e3568d38e6cb00857277047b0d63"},
{file = "pymongo-4.5.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:56320c401f544d762fc35766936178fbceb1d9261cd7b24fbfbc8fb6f67aa8a5"},
{file = "pymongo-4.5.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bbd705d5f3c3d1ff2d169e418bb789ff07ab3c70d567cc6ba6b72b04b9143481"},
{file = "pymongo-4.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80a167081c75cf66b32f30e2f1eaee9365af935a86dbd76788169911bed9b5d5"},
{file = "pymongo-4.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c42748ccc451dfcd9cef6c5447a7ab727351fd9747ad431db5ebb18a9b78a4d"},
{file = "pymongo-4.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf62da7a4cdec9a4b2981fcbd5e08053edffccf20e845c0b6ec1e77eb7fab61d"},
{file = "pymongo-4.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b5bbb87fa0511bd313d9a2c90294c88db837667c2bda2ea3fa7a35b59fd93b1f"},
{file = "pymongo-4.5.0-cp39-cp39-win32.whl", hash = "sha256:465fd5b040206f8bce7016b01d7e7f79d2fcd7c2b8e41791be9632a9df1b4999"},
{file = "pymongo-4.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:63d8019eee119df308a075b8a7bdb06d4720bf791e2b73d5ab0e7473c115d79c"},
{file = "pymongo-4.5.0.tar.gz", hash = "sha256:681f252e43b3ef054ca9161635f81b730f4d8cadd28b3f2b2004f5a72f853982"},
]
[package.dependencies]
dnspython = ">=1.16.0,<3.0.0"
[package.extras]
aws = ["pymongo-auth-aws (<2.0.0)"]
encryption = ["certifi", "pymongo[aws]", "pymongocrypt (>=1.6.0,<2.0.0)"]
gssapi = ["pykerberos", "winkerberos (>=0.5.0)"]
ocsp = ["certifi", "cryptography (>=2.5)", "pyopenssl (>=17.2.0)", "requests (<3.0.0)", "service-identity (>=18.1.0)"]
snappy = ["python-snappy"]
zstd = ["zstandard"]
[[package]] [[package]]
name = "python-dotenv" name = "python-dotenv"
version = "1.0.0" version = "1.0.0"
@ -158,23 +519,63 @@ files = [
] ]
[[package]] [[package]]
name = "telethon" name = "Telethon"
version = "1.30.3" version = "2.0.0a0"
description = "Full-featured Telegram client library for Python 3" description = "Full-featured Telegram client library"
optional = false optional = false
python-versions = ">=3.5" python-versions = ">=3.8"
files = []
develop = false
[package.dependencies]
markdown-it-py = ">=3.0,<4.0"
pyaes = ">=1.6,<2.0"
rsa = ">=4.9,<5.0"
[package.extras]
cryptg = ["cryptg (>=0.4,<1.0)"]
dev = ["black (>=23.3.0,<23.4.0)", "isort (>=5.12,<6.0)", "mypy (>=1.3,<2.0)", "pytest (>=7.3,<8.0)", "pytest-asyncio (>=0.21,<1.0)", "ruff (>=0.0.292,<0.1.0)"]
doc = ["sphinx_rtd_theme (>=1.2,<2.0)", "types-docutils (>=0.20,<1.0)"]
[package.source]
type = "git"
url = "https://github.com/LonamiWebs/Telethon"
reference = "v2"
resolved_reference = "6e88264b284a33bc0ad3dfe543e3ec2ec8191ccc"
subdirectory = "client"
[[package]]
name = "tqdm"
version = "4.66.1"
description = "Fast, Extensible Progress Meter"
optional = false
python-versions = ">=3.7"
files = [ files = [
{file = "Telethon-1.30.3.tar.gz", hash = "sha256:313e40fa06667b19ced13b379d9988167a8319bc0eb90bf39347cff46919a351"}, {file = "tqdm-4.66.1-py3-none-any.whl", hash = "sha256:d302b3c5b53d47bce91fea46679d9c3c6508cf6332229aa1e7d8653723793386"},
{file = "tqdm-4.66.1.tar.gz", hash = "sha256:d88e651f9db8d8551a62556d3cff9e3034274ca5d66e93197cf2490e2dcb69c7"},
] ]
[package.dependencies] [package.dependencies]
pyaes = "*" colorama = {version = "*", markers = "platform_system == \"Windows\""}
rsa = "*"
[package.extras] [package.extras]
cryptg = ["cryptg"] dev = ["pytest (>=6)", "pytest-cov", "pytest-timeout", "pytest-xdist"]
notebook = ["ipywidgets (>=6)"]
slack = ["slack-sdk"]
telegram = ["requests"]
[[package]]
name = "typing-extensions"
version = "4.8.0"
description = "Backported and Experimental Type Hints for Python 3.8+"
optional = false
python-versions = ">=3.8"
files = [
{file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"},
{file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"},
]
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.11" python-versions = "^3.11"
content-hash = "9ef099a5cfddbb3a84d27506f528e2edca10562fad5dabeb22bd64d49d9c1b04" content-hash = "9018cdd99fd16a737946674c19bc23ffd394c3a63f7e90c6d7db606d314ff8cc"

4
pyproject.toml Normal file → Executable file
View File

@ -13,7 +13,9 @@ python = "^3.11"
telethon = "^1.30.3" telethon = "^1.30.3"
python-dotenv = "^1.0.0" python-dotenv = "^1.0.0"
httpx = "^0.25.0" httpx = "^0.25.0"
openai = {version = "^1.0.0b3", allow-prereleases = true}
telemongo = {path = "../telethon-session-mongo", develop=true}
mongoengine = "^0.27.0"
[build-system] [build-system]
requires = ["poetry-core"] requires = ["poetry-core"]

95
requirements.txt Normal file → Executable file
View File

@ -4,6 +4,9 @@ anyio==4.0.0 ; python_version >= "3.11" and python_version < "4.0" \
certifi==2023.7.22 ; python_version >= "3.11" and python_version < "4.0" \ certifi==2023.7.22 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \ --hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \
--hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9 --hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9
dnspython==2.4.2 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:57c6fbaaeaaf39c891292012060beb141791735dbb4004798328fc2c467402d8 \
--hash=sha256:8dcfae8c7460a2f84b4072e26f1c9f4101ca20c071649cb7c34e8b6a93d58984
h11==0.14.0 ; python_version >= "3.11" and python_version < "4.0" \ h11==0.14.0 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \
--hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761
@ -16,11 +19,96 @@ httpx==0.25.0 ; python_version >= "3.11" and python_version < "4.0" \
idna==3.4 ; python_version >= "3.11" and python_version < "4.0" \ idna==3.4 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \
--hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2 --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2
mongoengine==0.27.0 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:8f38df7834dc4b192d89f2668dcf3091748d12f74d55648ce77b919167a4a49b \
--hash=sha256:c3523b8f886052f3deb200b3218bcc13e4b781661e3bea38587cc936c80ea358
pyaes==1.6.1 ; python_version >= "3.11" and python_version < "4.0" \ pyaes==1.6.1 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:02c1b1405c38d3c370b085fb952dd8bea3fadcee6411ad99f312cc129c536d8f --hash=sha256:02c1b1405c38d3c370b085fb952dd8bea3fadcee6411ad99f312cc129c536d8f
pyasn1==0.5.0 ; python_version >= "3.11" and python_version < "4" \ pyasn1==0.5.0 ; python_version >= "3.11" and python_version < "4" \
--hash=sha256:87a2121042a1ac9358cabcaf1d07680ff97ee6404333bacca15f76aa8ad01a57 \ --hash=sha256:87a2121042a1ac9358cabcaf1d07680ff97ee6404333bacca15f76aa8ad01a57 \
--hash=sha256:97b7290ca68e62a832558ec3976f15cbf911bf5d7c7039d8b861c2a0ece69fde --hash=sha256:97b7290ca68e62a832558ec3976f15cbf911bf5d7c7039d8b861c2a0ece69fde
pymongo==4.5.0 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:076afa0a4a96ca9f77fec0e4a0d241200b3b3a1766f8d7be9a905ecf59a7416b \
--hash=sha256:08819da7864f9b8d4a95729b2bea5fffed08b63d3b9c15b4fea47de655766cf5 \
--hash=sha256:0a1f26bc1f5ce774d99725773901820dfdfd24e875028da4a0252a5b48dcab5c \
--hash=sha256:0f4b125b46fe377984fbaecf2af40ed48b05a4b7676a2ff98999f2016d66b3ec \
--hash=sha256:1240edc1a448d4ada4bf1a0e55550b6292420915292408e59159fd8bbdaf8f63 \
--hash=sha256:152259f0f1a60f560323aacf463a3642a65a25557683f49cfa08c8f1ecb2395a \
--hash=sha256:168172ef7856e20ec024fe2a746bfa895c88b32720138e6438fd765ebd2b62dd \
--hash=sha256:1b1d7d9aabd8629a31d63cd106d56cca0e6420f38e50563278b520f385c0d86e \
--hash=sha256:1d40ad09d9f5e719bc6f729cc6b17f31c0b055029719406bd31dde2f72fca7e7 \
--hash=sha256:21b953da14549ff62ea4ae20889c71564328958cbdf880c64a92a48dda4c9c53 \
--hash=sha256:23cc6d7eb009c688d70da186b8f362d61d5dd1a2c14a45b890bd1e91e9c451f2 \
--hash=sha256:2988ef5e6b360b3ff1c6d55c53515499de5f48df31afd9f785d788cdacfbe2d3 \
--hash=sha256:2a0aade2b11dc0c326ccd429ee4134d2d47459ff68d449c6d7e01e74651bd255 \
--hash=sha256:2b0176f9233a5927084c79ff80b51bd70bfd57e4f3d564f50f80238e797f0c8a \
--hash=sha256:2d4fa1b01fa7e5b7bb8d312e3542e211b320eb7a4e3d8dc884327039d93cb9e0 \
--hash=sha256:3236cf89d69679eaeb9119c840f5c7eb388a2110b57af6bb6baf01a1da387c18 \
--hash=sha256:33faa786cc907de63f745f587e9879429b46033d7d97a7b84b37f4f8f47b9b32 \
--hash=sha256:37df8f6006286a5896d1cbc3efb8471ced42e3568d38e6cb00857277047b0d63 \
--hash=sha256:3a7166d57dc74d679caa7743b8ecf7dc3a1235a9fd178654dddb2b2a627ae229 \
--hash=sha256:3d79ae3bb1ff041c0db56f138c88ce1dfb0209f3546d8d6e7c3f74944ecd2439 \
--hash=sha256:3e33064f1984db412b34d51496f4ea785a9cff621c67de58e09fb28da6468a52 \
--hash=sha256:3fa3648e4f1e63ddfe53563ee111079ea3ab35c3b09cd25bc22dadc8269a495f \
--hash=sha256:40d5f6e853ece9bfc01e9129b228df446f49316a4252bb1fbfae5c3c9dedebad \
--hash=sha256:41771b22dd2822540f79a877c391283d4e6368125999a5ec8beee1ce566f3f82 \
--hash=sha256:435228d3c16a375274ac8ab9c4f9aef40c5e57ddb8296e20ecec9e2461da1017 \
--hash=sha256:44ee985194c426ddf781fa784f31ffa29cb59657b2dba09250a4245431847d73 \
--hash=sha256:465fd5b040206f8bce7016b01d7e7f79d2fcd7c2b8e41791be9632a9df1b4999 \
--hash=sha256:496c9cbcb4951183d4503a9d7d2c1e3694aab1304262f831d5e1917e60386036 \
--hash=sha256:49dce6957598975d8b8d506329d2a3a6c4aee911fa4bbcf5e52ffc6897122950 \
--hash=sha256:4c42748ccc451dfcd9cef6c5447a7ab727351fd9747ad431db5ebb18a9b78a4d \
--hash=sha256:505f8519c4c782a61d94a17b0da50be639ec462128fbd10ab0a34889218fdee3 \
--hash=sha256:53f2dda54d76a98b43a410498bd12f6034b2a14b6844ca08513733b2b20b7ad8 \
--hash=sha256:56320c401f544d762fc35766936178fbceb1d9261cd7b24fbfbc8fb6f67aa8a5 \
--hash=sha256:58a63a26a1e3dc481dd3a18d6d9f8bd1d576cd1ffe0d479ba7dd38b0aeb20066 \
--hash=sha256:5caee7bd08c3d36ec54617832b44985bd70c4cbd77c5b313de6f7fce0bb34f93 \
--hash=sha256:631492573a1bef2f74f9ac0f9d84e0ce422c251644cd81207530af4aa2ee1980 \
--hash=sha256:63d8019eee119df308a075b8a7bdb06d4720bf791e2b73d5ab0e7473c115d79c \
--hash=sha256:6422b6763b016f2ef2beedded0e546d6aa6ba87910f9244d86e0ac7690f75c96 \
--hash=sha256:681f252e43b3ef054ca9161635f81b730f4d8cadd28b3f2b2004f5a72f853982 \
--hash=sha256:6d64878d1659d2a5bdfd0f0a4d79bafe68653c573681495e424ab40d7b6d6d41 \
--hash=sha256:74c0da07c04d0781490b2915e7514b1adb265ef22af039a947988c331ee7455b \
--hash=sha256:7591a3beea6a9a4fa3080d27d193b41f631130e3ffa76b88c9ccea123f26dc59 \
--hash=sha256:76a262c41c1a7cbb84a3b11976578a7eb8e788c4b7bfbd15c005fb6ca88e6e50 \
--hash=sha256:77cfff95c1fafd09e940b3fdcb7b65f11442662fad611d0e69b4dd5d17a81c60 \
--hash=sha256:8027c9063579083746147cf401a7072a9fb6829678076cd3deff28bb0e0f50c8 \
--hash=sha256:80a167081c75cf66b32f30e2f1eaee9365af935a86dbd76788169911bed9b5d5 \
--hash=sha256:840eaf30ccac122df260b6005f9dfae4ac287c498ee91e3e90c56781614ca238 \
--hash=sha256:8543253adfaa0b802bfa88386db1009c6ebb7d5684d093ee4edc725007553d21 \
--hash=sha256:89b3f2da57a27913d15d2a07d58482f33d0a5b28abd20b8e643ab4d625e36257 \
--hash=sha256:8e559116e4128630ad3b7e788e2e5da81cbc2344dee246af44471fa650486a70 \
--hash=sha256:9aff6279e405dc953eeb540ab061e72c03cf38119613fce183a8e94f31be608f \
--hash=sha256:9c04b9560872fa9a91251030c488e0a73bce9321a70f991f830c72b3f8115d0d \
--hash=sha256:9d2346b00af524757576cc2406414562cced1d4349c92166a0ee377a2a483a80 \
--hash=sha256:a253b765b7cbc4209f1d8ee16c7287c4268d3243070bf72d7eec5aa9dfe2a2c2 \
--hash=sha256:a8127437ebc196a6f5e8fddd746bd0903a400dc6b5ae35df672dd1ccc7170a2a \
--hash=sha256:b25f7bea162b3dbec6d33c522097ef81df7c19a9300722fa6853f5b495aecb77 \
--hash=sha256:b33c17d9e694b66d7e96977e9e56df19d662031483efe121a24772a44ccbbc7e \
--hash=sha256:b4fe46b58010115514b842c669a0ed9b6a342017b15905653a5b1724ab80917f \
--hash=sha256:b520aafc6cb148bac09ccf532f52cbd31d83acf4d3e5070d84efe3c019a1adbf \
--hash=sha256:b5bbb87fa0511bd313d9a2c90294c88db837667c2bda2ea3fa7a35b59fd93b1f \
--hash=sha256:b6d2a56fc2354bb6378f3634402eec788a8f3facf0b3e7d468db5f2b5a78d763 \
--hash=sha256:bbd705d5f3c3d1ff2d169e418bb789ff07ab3c70d567cc6ba6b72b04b9143481 \
--hash=sha256:bc5d8c3647b8ae28e4312f1492b8f29deebd31479cd3abaa989090fb1d66db83 \
--hash=sha256:c3c3525ea8658ee1192cdddf5faf99b07ebe1eeaa61bf32821126df6d1b8072b \
--hash=sha256:c9a9a39b7cac81dca79fca8c2a6479ef4c7b1aab95fad7544cc0e8fd943595a2 \
--hash=sha256:cd4c8d6aa91d3e35016847cbe8d73106e3d1c9a4e6578d38e2c346bfe8edb3ca \
--hash=sha256:cf62da7a4cdec9a4b2981fcbd5e08053edffccf20e845c0b6ec1e77eb7fab61d \
--hash=sha256:d67225f05f6ea27c8dc57f3fa6397c96d09c42af69d46629f71e82e66d33fa4f \
--hash=sha256:dfcd2b9f510411de615ccedd47462dae80e82fdc09fe9ab0f0f32f11cf57eeb5 \
--hash=sha256:e1f61355c821e870fb4c17cdb318669cfbcf245a291ce5053b41140870c3e5cc \
--hash=sha256:e249190b018d63c901678053b4a43e797ca78b93fb6d17633e3567d4b3ec6107 \
--hash=sha256:e2654d1278384cff75952682d17c718ecc1ad1d6227bb0068fd826ba47d426a5 \
--hash=sha256:e57d859b972c75ee44ea2ef4758f12821243e99de814030f69a3decb2aa86807 \
--hash=sha256:e5a27f348909235a106a3903fc8e70f573d89b41d723a500869c6569a391cff7 \
--hash=sha256:ead4f19d0257a756b21ac2e0e85a37a7245ddec36d3b6008d5bfe416525967dc \
--hash=sha256:f076b779aa3dc179aa3ed861be063a313ed4e48ae9f6a8370a9b1295d4502111 \
--hash=sha256:f1bb3a62395ffe835dbef3a1cbff48fbcce709c78bd1f52e896aee990928432b \
--hash=sha256:f2227a08b091bd41df5aadee0a5037673f691e2aa000e1968b1ea2342afc6880 \
--hash=sha256:f3754acbd7efc7f1b529039fcffc092a15e1cf045e31f22f6c9c5950c613ec4d \
--hash=sha256:fe48f50fb6348511a3268a893bfd4ab5f263f5ac220782449d03cd05964d1ae7 \
--hash=sha256:fff7d17d30b2cd45afd654b3fc117755c5d84506ed25fda386494e4e0a3416e1
python-dotenv==1.0.0 ; python_version >= "3.11" and python_version < "4.0" \ python-dotenv==1.0.0 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba \ --hash=sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba \
--hash=sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a --hash=sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a
@ -30,5 +118,8 @@ rsa==4.9 ; python_version >= "3.11" and python_version < "4" \
sniffio==1.3.0 ; python_version >= "3.11" and python_version < "4.0" \ sniffio==1.3.0 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101 \ --hash=sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101 \
--hash=sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384 --hash=sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384
telethon==1.30.3 ; python_version >= "3.11" and python_version < "4.0" \ telemongo==0.2.2 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:313e40fa06667b19ced13b379d9988167a8319bc0eb90bf39347cff46919a351 --hash=sha256:02dce5c4918a305f6b75766107382fd2af4a477d05ddb512e617eacac8130a48 \
--hash=sha256:ef4a383b8c25c62a3b3f640fe4cd9a4d3c1fa0ab0b22d51e047f9f6c924c6795
telethon==1.31.1 ; python_version >= "3.11" and python_version < "4.0" \
--hash=sha256:299567c307818e0ecd1ecb208c2f4269be4ea84fdea49b5061c36362dc92abbd

0
tests/__init__.py Normal file → Executable file
View File