From 1a9ed07a02c8ba8dba105e3e27f548b3dc05fbc1 Mon Sep 17 00:00:00 2001 From: Chris W Date: Tue, 31 Oct 2023 02:05:43 -0600 Subject: [PATCH] things are working, and all is well --- .env.example | 0 .gitignore | 0 README.md | 0 cyber_fenneko/__init__.py | 20 +- cyber_fenneko/__main__.py | 9 +- cyber_fenneko/bot.py | 32 +- cyber_fenneko/commands/ask.py | 81 ++++ cyber_fenneko/commands/cache.py | 21 ++ cyber_fenneko/commands/help.py | 0 cyber_fenneko/commands/highlight.py | 60 +-- cyber_fenneko/commands/jsondump.py | 4 +- cyber_fenneko/commands/paste.py | 32 +- cyber_fenneko/commands/ping.py | 1 - cyber_fenneko/commands/settings.py | 64 ++++ cyber_fenneko/commands/user.py | 112 ++++++ cyber_fenneko/internal/arg_parser.py | 51 ++- cyber_fenneko/internal/command.py | 29 +- cyber_fenneko/internal/command_context.py | 5 +- cyber_fenneko/internal/constants.py | 3 + cyber_fenneko/internal/utils.py | 0 cyber_fenneko/middleware/caching.py | 26 ++ cyber_fenneko/models/entity.py | 18 + cyber_fenneko/models/paste.py | 12 + cyber_fenneko/models/settings.py | 52 +++ cyber_fenneko/utils/__init__.py | 40 ++ cyber_fenneko/utils/paste.py | 1 + poetry.lock | 435 +++++++++++++++++++++- pyproject.toml | 4 +- requirements.txt | 95 ++++- tests/__init__.py | 0 30 files changed, 1131 insertions(+), 76 deletions(-) mode change 100644 => 100755 .env.example mode change 100644 => 100755 .gitignore mode change 100644 => 100755 README.md mode change 100644 => 100755 cyber_fenneko/__init__.py mode change 100644 => 100755 cyber_fenneko/__main__.py mode change 100644 => 100755 cyber_fenneko/bot.py create mode 100755 cyber_fenneko/commands/ask.py create mode 100755 cyber_fenneko/commands/cache.py mode change 100644 => 100755 cyber_fenneko/commands/help.py mode change 100644 => 100755 cyber_fenneko/commands/highlight.py mode change 100644 => 100755 cyber_fenneko/commands/jsondump.py mode change 100644 => 100755 cyber_fenneko/commands/paste.py mode change 100644 => 100755 cyber_fenneko/commands/ping.py create mode 100644 cyber_fenneko/commands/settings.py create mode 100755 cyber_fenneko/commands/user.py mode change 100644 => 100755 cyber_fenneko/internal/arg_parser.py mode change 100644 => 100755 cyber_fenneko/internal/command.py mode change 100644 => 100755 cyber_fenneko/internal/command_context.py mode change 100644 => 100755 cyber_fenneko/internal/constants.py mode change 100644 => 100755 cyber_fenneko/internal/utils.py create mode 100755 cyber_fenneko/middleware/caching.py create mode 100755 cyber_fenneko/models/entity.py create mode 100755 cyber_fenneko/models/paste.py create mode 100644 cyber_fenneko/models/settings.py create mode 100755 cyber_fenneko/utils/__init__.py mode change 100644 => 100755 cyber_fenneko/utils/paste.py mode change 100644 => 100755 pyproject.toml mode change 100644 => 100755 requirements.txt mode change 100644 => 100755 tests/__init__.py diff --git a/.env.example b/.env.example old mode 100644 new mode 100755 diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/cyber_fenneko/__init__.py b/cyber_fenneko/__init__.py old mode 100644 new mode 100755 index 1eafe85..2dc545a --- a/cyber_fenneko/__init__.py +++ b/cyber_fenneko/__init__.py @@ -1,6 +1,7 @@ import os +from mongoengine import connect +from telemongo import MongoSession from telethon import TelegramClient -from telethon.sessions import SQLiteSession from dotenv import load_dotenv from cyber_fenneko.bot import Bot @@ -12,11 +13,24 @@ api_id = os.environ.get('APP_ID') api_hash = os.environ.get('APP_HASH') phone_number = os.environ.get('TG_PHONE') -session = SQLiteSession('fenneko-' + phone_number) -client = TelegramClient(session, api_id, api_hash) +db_host = os.environ.setdefault('DB_HOST', 'localhost') +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) +# 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 # We just need the files to be imported, nothing else # This is a bit hacky, but it works diff --git a/cyber_fenneko/__main__.py b/cyber_fenneko/__main__.py old mode 100644 new mode 100755 index a2e7b8c..a2480a0 --- a/cyber_fenneko/__main__.py +++ b/cyber_fenneko/__main__.py @@ -1,11 +1,8 @@ -from telethon.events import NewMessage +from telethon.events import NewMessage, Raw from . import client, bot, phone_number -async def new_message_handler(event: NewMessage): - print(event) - -client.add_event_handler(bot.on_new_message, NewMessage) -# client.add_event_handler(new_message_handler, NewMessage) +client.add_event_handler(bot._on_raw, Raw) +client.add_event_handler(bot._on_new_message, NewMessage) with client: client.start(phone_number) diff --git a/cyber_fenneko/bot.py b/cyber_fenneko/bot.py old mode 100644 new mode 100755 index 0bd76e2..e026059 --- a/cyber_fenneko/bot.py +++ b/cyber_fenneko/bot.py @@ -1,5 +1,7 @@ import logging +from typing import Dict from telethon import TelegramClient +from telethon.tl.types import TypeUpdate from telethon.tl.custom.message import Message from cyber_fenneko.internal.constants import GLOBAL_ARGS 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 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): self.commands = {} self.command_aliases = {} + self.update_handlers = {} self.client = client self.logger = logging.getLogger('cyber_fenneko.bot') self.default_prefix = '.' @@ -17,13 +27,22 @@ class Bot: def set_default_prefix(self, prefix: str): 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 decorator(func): # Set some defaults kwargs.setdefault('prefix', self.default_prefix) command = Command(func, cmd, **kwargs) - command.args = GLOBAL_ARGS + command.args # Check if a command with the same name already exists if command.command in self.commands: @@ -42,7 +61,14 @@ class Bot: return func # we still want the function to be normally accessible 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() if not message_text: return @@ -63,7 +89,7 @@ class Bot: text = message_text[len(command_text) + 1:].strip() try: - args, text = parse_args(text, cmd.args) + args, text = parse_args(self.client, text, cmd.args) except ValueError as e: await event.respond(f'Error: {e}') return diff --git a/cyber_fenneko/commands/ask.py b/cyber_fenneko/commands/ask.py new file mode 100755 index 0000000..8afc04e --- /dev/null +++ b/cyber_fenneko/commands/ask.py @@ -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') \ No newline at end of file diff --git a/cyber_fenneko/commands/cache.py b/cyber_fenneko/commands/cache.py new file mode 100755 index 0000000..2fc8474 --- /dev/null +++ b/cyber_fenneko/commands/cache.py @@ -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})') \ No newline at end of file diff --git a/cyber_fenneko/commands/help.py b/cyber_fenneko/commands/help.py old mode 100644 new mode 100755 diff --git a/cyber_fenneko/commands/highlight.py b/cyber_fenneko/commands/highlight.py old mode 100644 new mode 100755 index fd307c6..405db73 --- a/cyber_fenneko/commands/highlight.py +++ b/cyber_fenneko/commands/highlight.py @@ -1,9 +1,11 @@ import time import httpx -from io import BytesIO +from tempfile import NamedTemporaryFile from urllib.parse import urlencode 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 ..internal.command_context import CommandContext from ..internal.arg_parser import Arg, ArgType @@ -85,29 +87,35 @@ async def highlight(bot, ctx: CommandContext): else: 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: # Inkify returns an image, we just need to build the URL query = OrderedDict( code=code_block, - language=ctx.args['language'], - theme=ctx.args['theme'], - font=ctx.args['font'], - shadow_color=ctx.args['shadow_color'], - background=ctx.args['background'], - tab_width=ctx.args['tab_width'], - line_pad=ctx.args['line_pad'], - line_offset=ctx.args['line_offset'], - window_title=ctx.args['window_title'], - no_line_number=ctx.args['no_line_number'], - no_round_corner=ctx.args['no_round_corner'], - no_window_controls=ctx.args['no_window_controls'], - shadow_blur_radius=ctx.args['shadow_blur_radius'], - shadow_offset_x=ctx.args['shadow_offset_x'], - shadow_offset_y=ctx.args['shadow_offset_y'], - pad_horiz=ctx.args['pad_horiz'], - pad_vert=ctx.args['pad_vert'], - highlight_lines=ctx.args['highlight_lines'], - background_image=ctx.args['background_image'], + language=ctx.args['language'] or settings.highlight.theme, + theme=ctx.args['theme'] or settings.highlight.theme, + font=ctx.args['font'] or settings.highlight.font, + shadow_color=ctx.args['shadow_color'] or settings.highlight.shadow_color, + background=ctx.args['background'] or settings.highlight.background, + tab_width=ctx.args['tab_width'] or settings.highlight.tab_width, + line_pad=ctx.args['line_pad'] or settings.highlight.line_pad, + line_offset=ctx.args['line_offset'] or settings.highlight.line_offset, + window_title=ctx.args['window_title'] or settings.highlight.window_title, + no_line_number=ctx.args['no_line_number'] or settings.highlight.no_line_number, + no_round_corner=ctx.args['no_round_corner'] or settings.highlight.no_round_corner, + no_window_controls=ctx.args['no_window_controls'] or settings.highlight.no_window_controls, + shadow_blur_radius=ctx.args['shadow_blur_radius'] or settings.highlight.shadow_blur_radius, + shadow_offset_x=ctx.args['shadow_offset_x'] or settings.highlight.shadow_offset_x, + shadow_offset_y=ctx.args['shadow_offset_y'] or settings.highlight.shadow_offset_y, + pad_horiz=ctx.args['pad_horiz'] or settings.highlight.pad_horiz, + pad_vert=ctx.args['pad_vert'] or settings.highlight.pad_vert, + highlight_lines=ctx.args['highlight_lines'] or settings.highlight.highlight_lines, + background_image=ctx.args['background_image'] or settings.highlight.background_image, ) # 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 url = f'{ENDPOINT_URL}/generate?{urlencode(query)}' - print(url) res = httpx.get(url) if res.status_code != 200: await ctx.event.respond(f'Error: {res.status_code}') 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 - await ctx.event.respond(file=img) \ No newline at end of file + # Send the image + await ctx.event.respond(file=f.name) \ No newline at end of file diff --git a/cyber_fenneko/commands/jsondump.py b/cyber_fenneko/commands/jsondump.py old mode 100644 new mode 100755 index 12d542e..ca76173 --- a/cyber_fenneko/commands/jsondump.py +++ b/cyber_fenneko/commands/jsondump.py @@ -1,5 +1,6 @@ import time import json +from telethon.tl.types import MessageEntityPre from .. import bot from ..internal.command_context import CommandContext 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) else: # 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) diff --git a/cyber_fenneko/commands/paste.py b/cyber_fenneko/commands/paste.py old mode 100644 new mode 100755 index 421cca7..edaf928 --- a/cyber_fenneko/commands/paste.py +++ b/cyber_fenneko/commands/paste.py @@ -1,7 +1,10 @@ +import re import time import httpx from telethon.tl.types import MessageEntityPre from telethon.tl.custom.message import Message + +from cyber_fenneko.models.paste import Paste from .. import bot from ..internal.command_context import CommandContext 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' + @bot.command( 'paste', description='Send the contents of the replied to message to a pastebin', 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): @@ -22,9 +32,9 @@ async def paste(bot, ctx: CommandContext): if message is None: await ctx.event.respond('You must reply to a message to use this command') return - + # Get the message text - text = message.text + text = message.text if ctx.args['raw'] else message.message if text is None: await ctx.event.respond('You must reply to a text message to use this command') return @@ -32,21 +42,23 @@ async def paste(bot, ctx: CommandContext): # Get the language language = ctx.args['language'] - contents = '' + contents = None # Check if the message has entities; any pre entities will be used as the contents if message.entities is not None: for entity in message.entities: - if isinstance(entity, MessageEntityPre): - contents += text[entity.offset:entity.offset + entity.length] - contents += '\n\n' + if entity.CONSTRUCTOR_ID == MessageEntityPre.CONSTRUCTOR_ID: + if entity.language is not None: + language = entity.language + contents = text[entity.offset:entity.offset + entity.length] + contents = re.sub(r'```\n?', '', contents) break - + if not contents: contents = text json = paste_util(contents, language) url = json['url'] - + # Respond with the paste URL - await ctx.event.respond(f'Created paste: {url}', link_preview=False) \ No newline at end of file + await ctx.event.respond(f'Created paste: {url}', link_preview=False) diff --git a/cyber_fenneko/commands/ping.py b/cyber_fenneko/commands/ping.py old mode 100644 new mode 100755 index 6fc3161..efaae54 --- a/cyber_fenneko/commands/ping.py +++ b/cyber_fenneko/commands/ping.py @@ -1,7 +1,6 @@ import time from .. import bot from ..internal.command_context import CommandContext -from ..internal.arg_parser import Arg, ArgType @bot.command( 'ping', diff --git a/cyber_fenneko/commands/settings.py b/cyber_fenneko/commands/settings.py new file mode 100644 index 0000000..2e2f2c4 --- /dev/null +++ b/cyber_fenneko/commands/settings.py @@ -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') diff --git a/cyber_fenneko/commands/user.py b/cyber_fenneko/commands/user.py new file mode 100755 index 0000000..fa39e50 --- /dev/null +++ b/cyber_fenneko/commands/user.py @@ -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') \ No newline at end of file diff --git a/cyber_fenneko/internal/arg_parser.py b/cyber_fenneko/internal/arg_parser.py old mode 100644 new mode 100755 index d917c42..db5bde7 --- a/cyber_fenneko/internal/arg_parser.py +++ b/cyber_fenneko/internal/arg_parser.py @@ -2,8 +2,10 @@ import logging from enum import Enum 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') @@ -29,6 +31,9 @@ class Arg: # Special designation for global args 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.type = type @@ -37,8 +42,25 @@ class Arg: self.default = default self.description = description 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. 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}"') arg_value = arg_value[1:-1] 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: # if the arg is a boolean, we need to check if the value is true or false 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 # so we stop parsing + tokens.insert(0, token) break # Check if any required args are missing diff --git a/cyber_fenneko/internal/command.py b/cyber_fenneko/internal/command.py old mode 100644 new mode 100755 index 8ca9318..01aa8df --- a/cyber_fenneko/internal/command.py +++ b/cyber_fenneko/internal/command.py @@ -51,6 +51,14 @@ class Command: self.description = description 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): return self.func(*args, **kwargs) @@ -85,14 +93,27 @@ class Command: help_string += f'`{arg.name}' if 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' - for arg in args: + for arg in command_args: help_string += f'`{arg.name}' if 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' return help_string - \ No newline at end of file + + 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})' \ No newline at end of file diff --git a/cyber_fenneko/internal/command_context.py b/cyber_fenneko/internal/command_context.py old mode 100644 new mode 100755 index 0f8643f..1444e31 --- a/cyber_fenneko/internal/command_context.py +++ b/cyber_fenneko/internal/command_context.py @@ -53,4 +53,7 @@ class CommandContext: async def reply(self, *args, **kwargs): """Reply to the message that triggered this command.""" - await self.message.reply(*args, **kwargs) \ No newline at end of file + await self.message.reply(*args, **kwargs) + + def __repr__(self) -> str: + return f'CommandContext(raw_text={self.raw_text}, text={self.text}, args={self.args})' \ No newline at end of file diff --git a/cyber_fenneko/internal/constants.py b/cyber_fenneko/internal/constants.py old mode 100644 new mode 100755 index 34fceef..ac57502 --- a/cyber_fenneko/internal/constants.py +++ b/cyber_fenneko/internal/constants.py @@ -1,5 +1,8 @@ +import os from .arg_parser import Arg, ArgType +OPENAI_API_KEY = os.getenv('OPENAI_API_KEY') + # Args that exist on every command GLOBAL_ARGS = [ Arg("delete", type=ArgType.bool, aliases=['d', 'del'], default=False, description="Delete the message that triggered this command", global_arg=True) diff --git a/cyber_fenneko/internal/utils.py b/cyber_fenneko/internal/utils.py old mode 100644 new mode 100755 diff --git a/cyber_fenneko/middleware/caching.py b/cyber_fenneko/middleware/caching.py new file mode 100755 index 0000000..fb6106f --- /dev/null +++ b/cyber_fenneko/middleware/caching.py @@ -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 \ No newline at end of file diff --git a/cyber_fenneko/models/entity.py b/cyber_fenneko/models/entity.py new file mode 100755 index 0000000..e37d091 --- /dev/null +++ b/cyber_fenneko/models/entity.py @@ -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' + ] + } \ No newline at end of file diff --git a/cyber_fenneko/models/paste.py b/cyber_fenneko/models/paste.py new file mode 100755 index 0000000..057a4a5 --- /dev/null +++ b/cyber_fenneko/models/paste.py @@ -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) \ No newline at end of file diff --git a/cyber_fenneko/models/settings.py b/cyber_fenneko/models/settings.py new file mode 100644 index 0000000..85c1522 --- /dev/null +++ b/cyber_fenneko/models/settings.py @@ -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' + } diff --git a/cyber_fenneko/utils/__init__.py b/cyber_fenneko/utils/__init__.py new file mode 100755 index 0000000..036d580 --- /dev/null +++ b/cyber_fenneko/utils/__init__.py @@ -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' \ No newline at end of file diff --git a/cyber_fenneko/utils/paste.py b/cyber_fenneko/utils/paste.py old mode 100644 new mode 100755 index e0886b6..18a945f --- a/cyber_fenneko/utils/paste.py +++ b/cyber_fenneko/utils/paste.py @@ -9,6 +9,7 @@ def paste(text: str, language: str = 'txt', password = None, burn = False) -> st 'contents': text, 'password': password, 'burnAfterReading': burn, + 'raw': True, } response = httpx.post(ENDPOINT, json=data) diff --git a/poetry.lock b/poetry.lock index 04c4751..f30da0d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,14 +1,25 @@ # This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. [[package]] -name = "anyio" -version = "4.0.0" -description = "High level compatibility layer for multiple asynchronous event loop implementations" +name = "annotated-types" +version = "0.6.0" +description = "Reusable constraint types to use with typing.Annotated" optional = false python-versions = ">=3.8" files = [ - {file = "anyio-4.0.0-py3-none-any.whl", hash = "sha256:cfdb2b588b9fc25ede96d8db56ed50848b0b649dca3dd1df0b11f683bb9e0b5f"}, - {file = "anyio-4.0.0.tar.gz", hash = "sha256:f7ed51751b2c2add651e5747c891b47e26d2a21be5d32d9311dfe9692f3e5d7a"}, + {file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"}, + {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] @@ -16,9 +27,9 @@ idna = ">=2.8" sniffio = ">=1.1" [package.extras] -doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] -trio = ["trio (>=0.22)"] +doc = ["Sphinx", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme (>=1.2.2)", "sphinxcontrib-jquery"] +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)"] [[package]] name = "certifi" @@ -31,6 +42,47 @@ files = [ {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]] name = "h11" version = "0.14.0" @@ -97,6 +149,77 @@ files = [ {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]] name = "pyaes" version = "1.6.1" @@ -118,6 +241,244 @@ files = [ {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 " +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]] name = "python-dotenv" version = "1.0.0" @@ -158,23 +519,63 @@ files = [ ] [[package]] -name = "telethon" -version = "1.30.3" -description = "Full-featured Telegram client library for Python 3" +name = "Telethon" +version = "2.0.0a0" +description = "Full-featured Telegram client library" 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 = [ - {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] -pyaes = "*" -rsa = "*" +colorama = {version = "*", markers = "platform_system == \"Windows\""} [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] lock-version = "2.0" python-versions = "^3.11" -content-hash = "9ef099a5cfddbb3a84d27506f528e2edca10562fad5dabeb22bd64d49d9c1b04" +content-hash = "9018cdd99fd16a737946674c19bc23ffd394c3a63f7e90c6d7db606d314ff8cc" diff --git a/pyproject.toml b/pyproject.toml old mode 100644 new mode 100755 index 6e3abf0..f59b623 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,9 @@ python = "^3.11" telethon = "^1.30.3" python-dotenv = "^1.0.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] requires = ["poetry-core"] diff --git a/requirements.txt b/requirements.txt old mode 100644 new mode 100755 index f51c101..cf417f0 --- a/requirements.txt +++ b/requirements.txt @@ -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" \ --hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \ --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" \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --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" \ --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ --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" \ --hash=sha256:02c1b1405c38d3c370b085fb952dd8bea3fadcee6411ad99f312cc129c536d8f pyasn1==0.5.0 ; python_version >= "3.11" and python_version < "4" \ --hash=sha256:87a2121042a1ac9358cabcaf1d07680ff97ee6404333bacca15f76aa8ad01a57 \ --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" \ --hash=sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba \ --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" \ --hash=sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101 \ --hash=sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384 -telethon==1.30.3 ; python_version >= "3.11" and python_version < "4.0" \ - --hash=sha256:313e40fa06667b19ced13b379d9988167a8319bc0eb90bf39347cff46919a351 +telemongo==0.2.2 ; python_version >= "3.11" and python_version < "4.0" \ + --hash=sha256:02dce5c4918a305f6b75766107382fd2af4a477d05ddb512e617eacac8130a48 \ + --hash=sha256:ef4a383b8c25c62a3b3f640fe4cd9a4d3c1fa0ab0b22d51e047f9f6c924c6795 +telethon==1.31.1 ; python_version >= "3.11" and python_version < "4.0" \ + --hash=sha256:299567c307818e0ecd1ecb208c2f4269be4ea84fdea49b5061c36362dc92abbd diff --git a/tests/__init__.py b/tests/__init__.py old mode 100644 new mode 100755