diff --git a/.vscode/settings.json b/.vscode/settings.json index 2458869..eb464aa 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,6 +3,6 @@ "python.linting.banditEnabled": true, "python.linting.enabled": true, "[python]": { - "editor.defaultFormatter": "ms-python.autopep8" + "editor.defaultFormatter": "ms-python.python" } } \ No newline at end of file diff --git a/MeowerBot/API.py b/MeowerBot/API.py index c9ab29a..54c89c6 100644 --- a/MeowerBot/API.py +++ b/MeowerBot/API.py @@ -1,45 +1,355 @@ -import requests -from urllib.parse import urljoin +from urllib.parse import urljoin +from httpx import AsyncClient, Auth +import ujson as json +from .types import generic +from .types.api.reports import ReportRequest, Report, AdminNotesResponse, PagedRequest +from .types.generic import Post +from .types.api.chats import Chats, ChatGroup +from .types.api.user import User, Relationship +from typing import Literal +from httpx import Response class MeowerAPI: base_uri = "https://api.meower.org/" def __init__(self, username): + self.headers = {"username": username, "user-agent": 'Mozilla/5.0 (Android 14; Mobile; rv:109.0) Gecko/118.0 Firefox/118.0'} + self.client = AsyncClient(headers=self.headers, base_url=self.base_uri, follow_redirects=True) + + + + + async def login(self, token): + self.client.headers.update({"token": token}) + + async def admin_get_reports(self, timeout=None) -> ReportRequest: + resp = await self.client.get("/admin/reports", timeout=timeout, params={"autoget": None}) + + if resp.status_code == 404: + raise RuntimeError("[API] 404 Not found") + + return ReportRequest.from_json( + resp.text + ) + + async def admin_get_report(self, uuid: generic.UUID) -> Report: + resp = await self.client.get(f"/admin/reports/{uuid}/", params={"autoget": None}) + + if resp.status_code == 403: + raise RuntimeError("[API] 403 Found: You are not allowed to look at reports") + + + if resp.status_code == 404: + raise RuntimeError("[API] 404 Not found") + + return Report.from_json(resp.text) + + async def admin_edit_report(self, uuid: generic.UUID, status: Literal["no_action_taken", "action_taken"]) -> Report: + resp = await self.client.patch(f"/admin/reports/{uuid}", json={"status": status}) + + if resp.status_code == 403: + raise RuntimeError("[API] 403 Found: You are not allowed to edit reports") + + if resp.status_code == 404: + raise RuntimeError("[API] 404 Not found") + + return Report.from_json(resp.text) + + async def admin_escalate_report(self, uuid: generic.UUID) -> Report: + resp = await self.client.post(f"/admin/reports/{uuid}/escalate/") + if resp.status_code == 403: + raise RuntimeError("[API] 403 Found: You are not allowed to edit reports") + + if resp.status_code == 404: + raise RuntimeError("[API] 404 Not found") + + return Report.from_json(resp.text) + + async def admin_fetch_note(self, indentifier: str) -> AdminNotesResponse: + resp = await self.client.get(f"/admin/notes/{indentifier}", params={"autoget": None}) + + if resp.status_code == 403: + raise RuntimeError("[API] 403 Found: You are not allowed to look at notes") + + if resp.status_code == 404: + raise RuntimeError("[API] 404 Not found") + + return AdminNotesResponse.from_json(resp.text) + + async def admin_create_note(self, indentifier: str, notes: str) -> AdminNotesResponse: + resp = await self.client.put(f"/admin/notes/{indentifier}", json={"notes": notes}) + if resp.status_code == 403: + raise RuntimeError("[API] 403 Found: You are not allowed to edit/create notes") + + if resp.status_code == 404: + raise RuntimeError("[API] 404 Not found") + + return AdminNotesResponse.from_json(resp.text) + + async def admin_get_post(self, uuid: generic.UUID) -> Post: + resp = await self.client.get(f"/admin/posts/{uuid}", params={"autoget": None}) + if resp.status_code == 403: + raise RuntimeError("[API] 403 Found: You are not allowed to look at posts") + + + if resp.status_code == 404: + raise RuntimeError("[API] 404 Not found") + + return Post.from_json(resp.text) + + async def admin_delete_post(self, uuid: generic.UUID) -> Post: + resp = await self.client.delete(f"/admin/posts/{uuid}") + if resp.status_code == 403: + raise RuntimeError("[API] 403 Found: You are not allowed to delete posts") + + + if resp.status_code == 404: + raise RuntimeError("[API] 404 Not found") + + return Post.from_json(resp.text) + + async def admin_restore_deleted_post(self, uuid: generic.UUID) -> Post: + resp = await self.client.post(f"/admin/posts/{uuid}/restore") + if resp.status_code == 403: + raise RuntimeError("[API] 403 Found: You are not allowed to restore posts") + + if resp.status_code == 404: + raise RuntimeError("[API] 404 Not found") + + return Post.from_json(resp.text) + + + + async def get_chats(self) -> Chats: + resp = await self.client.get(f"/chats/", params={"autoget": None}) + + if resp.status_code == 401: + raise RuntimeError("[API] No Token or username supplied! This is required to send authenticated API requests") + + return Chats.from_json(resp.text) + + async def create_chat(self, nickname: str) -> ChatGroup: + resp = await self.client.post(f"/chats/", json={"nickname": nickname}) + + if resp.status_code == 401: + raise RuntimeError(json.parse(resp.text)["type"]) + + return ChatGroup.from_json(resp.text) + + async def get_chat(self, uuid: generic.UUID) -> ChatGroup: + resp = await self.client.get(f"/chats/{uuid}", params={"autoget": None}) + + if resp.status_code == 401: + raise RuntimeError("[API] No Token or username supplied! This is required to send authenticated API requests") + + + if resp.status_code == 404: + raise RuntimeError("[API] 404 Chat Not found") + + return ChatGroup.from_json(resp.text) + + async def update_chat(self, uuid: generic.UUID, nickname: str) -> ChatGroup: + resp = await self.client.patch(f"/chats/{uuid}", josn={"nickname": nickname}) + + if resp.status_code == 429: + raise RuntimeError("[API] Ratelimited: Updating chat") + + + if resp.status_code == 401: + raise RuntimeError("[API] No Auth to do this action") + + + if resp.status_code == 404: + raise RuntimeError("[API] 404 Chat Not found") + + + return ChatGroup.from_json(resp.text) + + async def leave_chat(self, uuid: generic.UUID) -> dict: + resp = await self.client.delete(f"/chats/{uuid}") + + + if resp.status_code == 429: + raise RuntimeError("[API] Ratelimited: Updating chat") + + + if resp.status_code == 401: + raise RuntimeError("[API] No Auth to do this action") + + + if resp.status_code == 404: + raise RuntimeError("[API] 404 Chat Not found") + + return {"error": False} + + async def add_user_to_chat(self, uuid: generic.UUID, username: str) -> ChatGroup: + resp = await self.client.put(f"/chats/{uuid}/members/{username}") + + if resp.status_code == 429: + raise RuntimeError("[API] Ratelimited: Updating chat") + + + if resp.status_code == 401: + raise RuntimeError("[API] No Auth to do this action") + + + if resp.status_code == 404: + raise RuntimeError("[API] 404 Chat Not found") + + return ChatGroup.from_json(resp.text) + + async def transfer_chat_ownership(self, uuid: generic.UUID, username: str) -> ChatGroup: + resp = await self.client.post(f"/chats/{uuid}/members/{username}/transfer") + + if resp.status_code == 429: + raise RuntimeError("[API] Ratelimited: Updating chat") + - self.session = requests.session() - self.session.headers.update({"usename": username}) + if resp.status_code == 401: + raise RuntimeError("[API] No Auth to do this action") - def login(self, token): - self.session.headers.update({"token": token}) - def get_page(self, page=1, chatid="home"): - if chatid == "home": - return self.session.get( - urljoin(self.base_uri, "/home?autoget&page={0}".format(page)) - ).json() + if resp.status_code == 404: + raise RuntimeError("[API] 404 Chat Not found") + + return ChatGroup.from_json(resp.text) + + async def get_posts(self, chat: str | generic.UUID, page: int = 1) -> PagedRequest[Post]: + if chat == "home": + resp = await self.client.get(f"/home/", params={"page": page, "autoget": None}) + else: + resp = await self.client.get(f"/posts/{chat}", params={"page": page, "autoget": None}) + + if resp.status_code == 401: + raise RuntimeError("[API] No Auth to do this action") + + + if resp.status_code == 404: + raise RuntimeError("[API] 404 Chat Not found") + + + return PagedRequest[Post].from_json(resp.text) + + async def send_post(self, chat: str | generic.UUID, content: str) -> Post: + if chat == "home": + resp = await self.client.post(f"/home/", json={"content": content}) else: - return self.session.get( - urljoin( - self.base_uri, "/posts/{0}?autoget&page={1}".format(chatid, page) - ) - ).json() - - def get_user(self, username): - return self.session.get( - urljoin(self.base_uri, "/users/{0}".format(username)) - ).json() - - def get_user_posts(self, username, page=1): - return self.session.get( - urljoin( - self.base_uri, - "/users/{0}/posts?autoget&page={1}".format(username, page), - ) - ).json() - - def statistics(self): - return self.session.get(urljoin(self.base_uri, "statistics")).json() - - def status(self): - return self.session.get(urljoin(self.base_uri, "/status")).json() + resp = await self.client.post(f"/posts/{chat}", json={"content": content}) + + print(resp.text, resp.status_code) + if resp.status_code == 429: + raise RuntimeError("[API] Ratelimited: Sending posts") + + + if resp.status_code == 401: + raise RuntimeError("[API] No Auth to do this action") + + + if resp.status_code == 404: + raise RuntimeError("[API] 404 Chat Not found") + + print(resp.text) + return Post.from_json(resp.text) + + async def get_post(self, uuid: generic.UUID) -> Post: + resp = await self.client.get(f"/posts", params={"id": uuid}) + + + if resp.status_code == 404: + raise RuntimeError("[API] 404 Post Not found") + + return Post.from_json(resp.text) + + async def update_post(self, uuid: generic.UUID, content: str) -> Post: + resp = await self.client.patch(f"/posts", params={"id": uuid}, json={"content": content}) + + if resp.status_code == 429: + raise RuntimeError("[API] Ratelimited: Sending posts") + + + if resp.status_code == 401: + raise RuntimeError("[API] No Auth to do this action") + + + if resp.status_code == 404: + raise RuntimeError("[API] 404 Post Not found") + + return Post.from_json(resp.text) + + async def delete_post(self, uuid: generic.UUID) -> Post: + resp = await self.client.patch(f"/posts", params={"id": uuid}) + + if resp.status_code == 429: + raise RuntimeError("[API] Ratelimited: Deleting posts") + + + if resp.status_code == 401: + raise RuntimeError("[API] No Auth to do this action") + + + if resp.status_code == 404: + raise RuntimeError("[API] 404 Post Not found") + + return Post.from_json(resp.text) + + async def get_inbox(self) -> PagedRequest[Post]: + resp = await self.client.get("/inbox", params={"autoget": None}) + + if resp.status_code == 401: + raise RuntimeError("[API] No Auth to do this action") + + return PagedRequest[Post].from_json(resp.text) + + async def search_users(self, query: str, page: int = 1 ) -> PagedRequest[User]: + resp = await self.client.get("/search/users", params={"q": query, "p": page,"autoget": None},) + + return PagedRequest[User].from_json(resp.text) + + async def search_home(self, query: str, page: int = 1) -> PagedRequest[Post]: + resp = await self.client.get("/search/home", params={"q": query, "p": page, "autoget": None}) + return PagedRequest[Post].from_json(resp.text) + + # TODO: Implement wrapper for https://github.com/meower-media-co/Meower-Server/blob/better-moderation/rest_api/admin.py#L74-L1564 + # TODO: https://github.com/meower-media-co/Meower-Server/blob/better-moderation/rest_api/users.py + + async def _get_user(self, username, url, json=None, page=1, query = None, params=None): + resp: Response = await self.client.get(urljoin(f"/users/{username}/", url), json=json, params={"q": query, "p": page, **params}) + if resp.status_code == 404: + raise RuntimeError("[API] User does not exist") + + if resp.status_code == 401: + raise RuntimeError("[API] No Auth to do this action") + + + if resp.status_code == 429: + raise RuntimeError("[API] Ratelimited: Updating chat") + + if resp.status_code == 403: + raise RuntimeError("[API] Blocked from doing this action") + + return resp._text + + async def get_user_posts(self, username, query, page = 1) -> PagedRequest[Post]: + return PagedRequest[Post].from_json(await self._get_user(username, "posts", query=query, page=page, params={"autoget": None})) + + async def get_user_relationship(self, username) -> Relationship: + return Relationship.from_json(await self._get_user(username, "relationship")) + + async def edit_user_relationship(self, username, state: Literal[0, 1, 2]) -> Relationship: + resp = await self.client.patch(f"/users/{username}/relationship", json={"state": state}) + + if resp.status_code == 404: + raise RuntimeError("[API] User does not exist") + + if resp.status_code == 401: + raise RuntimeError("[API] No Auth to do this action") + + + + + + return Relationship.from_json(resp.text) + + async def dm_user(self, username) -> ChatGroup: + return ChatGroup.from_json(self._get_user(username, 'dm')) diff --git a/MeowerBot/Bot.py b/MeowerBot/Bot.py index 26d1db0..a3b2502 100644 --- a/MeowerBot/Bot.py +++ b/MeowerBot/Bot.py @@ -1,470 +1,342 @@ -import threading import shlex +from .cl import Client +import traceback +from .command import AppCommand +from .context import Context, Post, PartialUser, User, PartialChat +import logging +from .API import MeowerAPI +import asyncio +from enum import StrEnum -from .cl import CloudLink -import sys +class cbids(StrEnum): + error = "error" + __raw__ = "__raw__" + login = "login" + close = "close" + ulist = "ulist" + message = "message" + raw_message = "raw_message" + direct = "direct" + statuscode = "statuscode" +print(str(cbids.error)) +callbacks = [i for i in cbids] + +class Bot(Client): + messages = [] + message_condition = asyncio.Condition() + + + """ + A class that holds all of the networking for a meower bot to function and run + """ + __bridges__ = [ + "Discord", + "Revower", + "revolt" + ] + -import json -import traceback -import requests + BOT_NO_PMSG_RESPONSE = [ + "I:500 | Bot", + "I: 500 | Bot" + ] + ulist = None + @property + def latency(self): + return self.ws.latency -import time + async def _t_ping(self): + while True: + try: + await asyncio.sleep(5) -from .command import AppCommand -from .context import CTX + await self.sendPacket({"cmd": "ping", "val": ""}) + self.logger.debug(msg="Sent ping") + except Exception as e: + await self._error(e) + break -import time -import logging + def __init__(self, prefix=None): #type: ignore + super().__init__() + self.callbacks = {str(i): [] for i in callbacks} + self.callbacks["__raw__"] = [] + self.ulist = [] -from .API import MeowerAPI + # to be used in start + self.username = None + self.password = None + + self.commands = {} + self.prefix = prefix + self.logger = logging.getLogger("MeowerBot") + self.server = None + + self.cogs = {} + # Interface + + def event(self, func): + """ + Creates a callback that takes over the original functionality of the bot. + throws an error if the function name is not a valid callback + + throws: + - TypeError + + """ + if func.__name__ not in callbacks: + raise TypeError(f"{func.__name__} is not a valid callback") + + setattr(self, func.__name__, func) + + def listen(self, callback=None): + """ + Does the same thing as @link Bot.event but does not replace the bots original functionality, most usefull for librarys + throws an error if the function name is not a valid callback + + throws: + - TypeError + """ + def inner(func): + callback = callback if callback is not None else func.__name__ + + if func.__name__ not in callbacks: + raise TypeError(f"{func.__name__} is not a valid listener") + + self.callbacks[callback].append(func) + + return func + return inner + + + def subcommand(self, name=None, args=0, aliases = None): + def inner(func): + + cmd = AppCommand(func, name=name, args=args) + cmd.register_class(self.connected) + + self.commands = AppCommand.add_command(self.commands, cmd) + + + return cmd #dont want mb to register this as a root command + return inner + + def update_commands(self): + for cog in self.cogs: + cog.update_commands() + + self.commands = self.commands.update(cog.__commands__) + + + + async def error(self, err: Exception): + raise err + + async def __raw__(self, packet: dict): pass + async def login(self, token: str): pass + async def close(self): pass + async def ulist(self, ulist): pass + + async def message(self, message: Post): + message = await self.handle_bridges(message) + + if not message.data.startswith(self.prefix): + return + + message.data = message.data.removeprefix(self.prefix) + + await self.run_commands(message) + + async def statuscode(self, status, listerner): + pass + + async def raw_message(self, data: dict): pass + async def direct(self, data: dict): pass + + + async def _run_event(self, event: cbids, *args, **kwargs): + events = [getattr(self, str(event))] + for i in self.callbacks[str(event)]: + if type(i) is list: + events.extend(i) + elif callable(i): # Check if the element is callable + events.append(i) + + err = await asyncio.gather(*[i(*args, **kwargs) for i in events if callable(i)], return_exceptions=True) + for i in err: + if i is not None: + if isinstance(i, Exception) and event != cbids.error: + await self._error(i) + + + # websocket + + async def handle_bridges(self, message: Post): + fetch = False + if isinstance(message.user, User): + fetch = True + + if message.user.username in self.__bridges__ and ":" in message.data: + split = message.data.split(": ", 1) + message.data = split[1] + message.user = PartialUser(split[0], self) + if fetch: + message.user = await message.user.fetch() + + + + if message.data.startswith(self.prefix + "#0000"): + message.data = message.data.replace("#0000", "") + + return message + + def get_context(self, message: Post): + return Context(message, self) -from websocket._exceptions import WebSocketConnectionClosedException, WebSocketException + async def run_commands(self, message: Post): -import sys + args = shlex.split(str(message)) -if sys.version_info >= (3, 11): - from enum import StrEnum -else: - from backports.strenum import StrEnum + try: + await self.commands[args[0]].run_cmd(self.get_context(message), *args[1:]) + except Exception as e: + await self._error(e) -from typing import Union + def command(self, name=None, args=0, aliases = None): + def inner(func): -class cbids(StrEnum): - error = "error" - __raw__ = "__raw__" - login = "login" - close = "close" - statuscode = "statuscode" - ulist = "ulist" - message = "message" - raw_message = "raw_message" - chat_list = "chat_list" - direct = "direct" - -class Bot: - """ - A class that holds all of the networking for a meower bot to function and run - - """ - __bridges__ = [ - "Discord", - "Revower", - "revolt" - ] + cmd = AppCommand(func, name=name, args=args) + cmd.register_class(self) - BOT_TAKEN_LISTENERS = [ - "__meowerbot__send_ip", - "__meowerbot__send_message", - "__meowerbot__login", - "__meowerbot__cloudlink_trust", - ] - - BOT_NO_PMSG_RESPONSE = [ - "I:500 | Bot", - "I: 500 | Bot" - ] - - def _t_ping(self): - while True: - time.sleep(60) - - self.wss.sendPacket({"cmd": "ping", "val": ""}) - - def __init__(self, prefix=None, autoreload: int or None = None ): #type: ignore - self.wss = CloudLink() - self.callbacks = {} - self._last_to = "Home" - - self.wss.callback( - "on_packet", self._debug_fix - ) # self._debug_fix catches all errors - self.wss.callback("on_error", self.__handle_error__) # handle uncought errors - self.wss.callback("on_close", self.__handle_close__) # Websocket disconnected - self.wss.callback( - "on_connect", self.__handle_on_connect__ - ) # signing in and stuff like that - - # to be used in start - self.username = None - self.password = None - self.logger_in = False - - if autoreload: - self.autoreload = True - self.autoreload_time = min(autoreload, 1) - self.autoreload_original = min(autoreload, 1) - else: - self.autoreload = False - self.autoreload_time = 0 - self.autoreload_original = 0 - - self.commands = {} - self.prefix = prefix - self._t_ping_thread = threading.Thread(target=self._t_ping, daemon=True) # (: - self.logger = logging.getLogger("MeowerBot") - self.bad_exit = False - self.server = None - - self.cogs = {} - - def run_cb(self, cbid, args=(), kwargs=None): # cq: ignore - if cbid not in self.callbacks: - return # ignore - - if not kwargs: - kwargs = {} - - if cbid == "error" and isinstance(args[0], KeyboardInterrupt()): - self.logger.error("KeyboardInterrupt") - self.bad_exit = True - self.stop() - return - - kwargs["bot"] = self - for callback in self.callbacks[cbid]: - try: - callback( - *args, **kwargs - ) # multi callback per id is supported (unlike cloudlink 0.1.7.3 LOL) - except Exception as e: # cq ignore - - self.logger.error(traceback.format_exc()) - self.run_cb("error", args=(e,)) - - def __handle_error__(self, e): - self.run_cb("error", args=(e,)) - if type(e) == WebSocketConnectionClosedException and self.autoreload: - self.__handle_close__() - return - - if (type(e)) == KeyboardInterrupt: - #kill all bot threads - self.bad_exit = True - - self.wss = None # effectively kill the bot - self.__handle_close__( ) - return - - def _debug_fix(self, packet): - packet = json.loads(packet) # Server bug workaround - - try: - self.__handle_packet__(packet) - except BaseException as e: # cq: skip #IDC ABOUT GENERAL EXCP - self.__handle_error__(e) - self.logger.error(traceback.format_exc()) - self.run_cb("error", args=(e, )) - - try: - self.run_cb("__raw__", args=(packet, )) # raw packets - except BaseException as e: # cq: skip #IDC ABOUT GENERAL EXCP - self.__handle_error__(e) - self.logger.error(traceback.format_exc()) - self.run_cb("error", args=(e, )) - - def __handle_on_connect__(self): - self.wss.sendPacket( - { - "cmd": "direct", - "val": {"cmd": "type", "val": "py"}, - } - ) - self.wss.sendPacket( - { - "cmd": "direct", - "val": "meower", - "listener": "__meowerbot__cloudlink_trust", - } - ) - - def command(self, aname=None, args=0): - def inner(func): - if aname is None: - name = func.__name__ - else: - name = aname - - cmd = AppCommand(func, name=name, args=args) - - info = cmd.info() - info[cmd.name]["command"] = cmd - - self.commands.update(info) - - return cmd #allow subcommands without a cog - - return inner - - def register_cog(self, cog): - info = cog.get_info() - self.cogs[cog.__class__.__name__] = cog - self.commands.update(info) - - def deregister_cog(self, cogname): - for cmd in self.cogs[cogname].get_info().values(): - del self.commands[cmd.name] - del self.cogs[cogname] - - def _handle_status(self, status, listener): - if status == "I:112 | Trusted Access enabled": - return - - if self.logger_in: - self.logger_in = False - - if status != "I:100 | OK": - raise RuntimeError("CloudLink Trust Failed") - - auth_packet = { - "cmd": "direct", - "val": { - "cmd": "authpswd", - "val": {"username": self.username, "pswd": self._password}, - }, - "listener": "__meowerbot__login", - } - self.wss.sendPacket(auth_packet) - - elif listener == "__meowerbot__login": - if status == "E:104 | Internal": - requests.post( - "https://webhooks.meower.org/post/home", - json={ - "post": "ERROR: MeowerBot.py Webhooks Logging\n\n Account Softlocked.", - "username": self.username, - }, - timeout=5 - ) - print("CRITICAL ERROR! ACCOUNT SOFTLOCKED!!!!.", file=sys.__stdout__) - self.bad_exit = True - del self.wss - - return - - if status != "I:100 | OK": - raise RuntimeError("Password Or Username Is Incorrect") - - time.sleep(0.5) - self.run_cb("login", args=(), kwargs={}) - - elif listener == "__meowerbot__send_message": - if status == "I:100 | OK": - self.autoreload_time = self.autoreload_original - return - - raise RuntimeError("Post Failed to send") - - def callback(self, callback, cbid: Union[Union[cbids, None], str] =None): - """Connects a callback ID to a callback - """ - if cbid is None: - cbid = callback.__name__ - - if cbid not in self.callbacks: - self.callbacks[cbid] = [] - self.callbacks[cbid].append(callback) - - def __handle_close__(self, *args, **kwargs): - if self.autoreload: - self.autoreload = False #to stop race condisons - self.logger_in = True - self.autoreload_time *= 1.2 - - - time.sleep(self.autoreload_time) - self.autoreload = True #reset this, as i set it to false above. - - self.wss.state = 0 #type: ignore - self.wss.client(self.server) #type: ignore - return #dont want the close callback to be called here - - self.run_cb("close", args=args, kwargs=kwargs) - - def handle_bridges(self, packet): - if packet["val"]["u"] in self.__bridges__ and ": " in packet["val"]["p"]: - split = packet["val"]["p"].split(": ", 1) - packet["val"]["p"] = split[1] - packet["val"]["u"] = split[0] - - if packet["val"]["p"].startswith(self.prefix+"#0000"): - packet["val"]["p"] = packet["val"]["p"].replace("#0000", "") - - return packet + self.subcommand = AppCommand.add_command(self.commands, cmd) + - def __handle_packet__(self, packet): - if packet["cmd"] == "statuscode": + return cmd + return inner + - self._handle_status(packet["val"], packet.get("listener", None)) - listener = packet.get("listener", None) - return self.run_cb("statuscode", args=(packet["val"], listener)) + async def _connect(self): + await self.sendPacket({ "cmd": "direct", "val": "meower", "listener": "send_tkey" }) + + await self.sendPacket({"cmd": "direct", "val": { + "cmd": "type", "val": "py" + }}) + + + async with self.message_condition: + await self.sendPacket({ + "cmd": "direct", + "val": { + "cmd": "authpswd", + "val": { + "username": str(self.username).strip(), + "pswd": str(self.password).strip() + } + }, + "listener": "mb.py_login" + }) + + while True: + + await self.message_condition.wait() + + if self._packets[-1].get("listener") != "mb.py_login": + continue + + if self._packets[-1]["cmd"] == "statuscode" and self._packets[-1]["val"] != "I: 100 | OK": + raise Exception(f"Wrong Username or Password!\n {self._packets[-1]["val"]}") + + if not (self._packets[-1]["cmd"] == "direct" and "payload" in self._packets[-1]["val"].keys()): + continue + + break + + await self.api.login(self._packets[-1]['val']['payload']['token']) + + await self._run_event(cbids.login, self._packets[-1]['val']['payload']['token']) + + + + + + + async def _disconnect(self): + + await self._run_event(cbids.close) + + def get_chat(self, id): + return PartialChat(id, self) + + async def _message(self, message): + if (message.get("listener")) != "mb_login": + self.logger.debug(message) + match message["cmd"]: + case "statuscode": + return await self._run_event(cbids.statuscode, message["val"], message.get("listener")) + + case "ulist": + self.ulist = message["val"].split(";") + + return await self._run_event(cbids.ulist, self.ulist) + + case "direct": + if "post_origin" in message["val"]: # post + await self._run_event(cbids.__raw__, message["val"]) + post = Post(self, message["val"], chat=message["val"]["post_origin"]) + async with self.message_condition: + self.messages.append(post) + self.message_condition.notify_all() + + await self._run_event(cbids.message, post) + else: + return await self._run_event(cbids.direct, message) + - elif packet["cmd"] == "ulist": - self.run_cb("ulist", self.wss.statedata["ulist"]["usernames"]) + + if (message["cmd"] == "pmsg") and (message["val"] not in self.BOT_NO_PMSG_RESPONSE): + self.wss.sendPacket({ + "cmd": "pmsg", + "val": "I:500 | Bot", + "id": message["origin"] + }) - elif packet["cmd"] == "direct" and "post_origin" in packet["val"]: - packet = self.handle_bridges(packet) - ctx = CTX(packet["val"], self) - if "message" in self.callbacks: - self.run_cb("message", args=(ctx.message,)) - else: - if ctx.user.username == self.username: - return - if not ctx.message.data.startswith(self.prefix): - return + - ctx.message.data = ctx.message.data.split(self.prefix, 1)[1] + async def _error(self, error): - self.run_command(ctx.message) + await self._run_event(cbids.error, error) - self.run_cb("raw_message", args=(packet["val"],)) - elif packet["cmd"] == "direct": - listener = packet.get("listener") + async def start(self, username, password, server="wss://server.meower.org", ): + """ + Runs The bot (Blocking) + """ + self.username = username + self.password = password - if listener == "mb_get_chat_list": - self.run_cb("chat_list", args=(packet["val"]["payload"], listener)) - elif listener == "__meowerbot__login": - self.api.login(packet['val']['payload']['token']) - self.run_cb("direct", args=(packet["val"], listener)) + asyncio.create_task(self._t_ping()) + if self.prefix is None: + self.prefix = "@" + self.username + self.logger = logging.getLogger(f"MeowerBot {self.username}") + self.server = server + + self.api = MeowerAPI(username=username) + + + await self.connect(server) + + def run(self, username, password, server="wss://server.meower.org", ): + """ + Runs the bot (Blocking) + """ + loop = asyncio.get_event_loop() + fut = loop.create_task( self.start(username, password, server=server) ) + loop.run_forever() - - else: - listener = packet.get("listener") - self.run_cb(packet["cmd"], args=(packet["val"], listener)) - - if (packet["cmd"] == "pmsg") and (packet["val"] not in self.BOT_NO_PMSG_RESPONSE): - self.wss.sendPacket({ - "cmd": "pmsg", - "val": "I:500 | Bot", - "id": packet["origin"] - }) - - def run_command(self, message): - args = shlex.split(str(message)) - - try: - self.commands[args[0]]["command"].run_cmd(message.ctx, *args[1:]) - except KeyError as e: - self.logger.error(traceback.format_exc()) - self.run_cb("error", args=(e,)) - - def send_msg(self, msg, to="home"): - self._last_to = to - self._last_sent = msg - try: - if to == "home": - self.wss.sendPacket( - { - "cmd": "direct", - "val": {"cmd": "post_home", "val": msg}, - "listener": "__meowerbot__send_message", - } - ) - else: - self.wss.sendPacket( - { - "cmd": "direct", - "val": {"cmd": "post_chat", "val": {"chatid": to, "p": msg}}, - "listener": "__meowerbot__send_message", - } - ) - #socket is closed, use webhooks - except WebSocketException as e: - self.run_cb(cbid="error", args=(e,)) - - def send_typing(self, to="home"): - if to == "home": - self.wss.sendPacket( - { - "cmd": "direct", - "val": { - "cmd": "set_chat_state", - "val": { - "chatid": "livechat", - "state": 101, - }, - }, - } - ) - else: - self.wss.sendPacket( - { - "cmd": "direct", - "val": { - "cmd": "set_chat_state", - "val": { - "chatid": to, - "state": 100, - }, - }, - } - ) - - def enter_chat(self, chatid="livechat"): - self.wss.sendPacket( - { - "cmd": "direct", - "val": { - "cmd": "set_chat_state", - "val": { - "chatid": chatid, - "state": 1, - }, - }, - } - ) - - def create_chat(self, name): - """ - Unstable, use at your own risk - - comes with callbacks: chat_list - """ - self.wss.sendPacket({ - "cmd": "direct", - "val": { - "cmd": "create_chat", - "val": name - }, - "listener": "mb_create_chat" - }) - - time.sleep(secs=0.5) - - self.wss.sendPacket({ - "cmd": "direct", - "val": { - "cmd": "get_chat_list", - "val": { - "page": 1 - } - }, - "listener": "mb_get_chat_list" - }) - - def run(self, username, password, server="wss://server.meower.org"): - """ - Runs The bot (Blocking) - """ - self.username = username - self._password = password - self.logger_in = True - - self._t_ping_thread.start() - if self.prefix is None: - self.prefix = "@" + self.username - self.logger = logging.getLogger(f"MeowerBot {self.username}") - self.server = server - self.api = MeowerAPI(username=username) - self.wss.client(server) - - if self.bad_exit: - raise BaseException("Bot Account Softlocked") diff --git a/MeowerBot/_Commands.py b/MeowerBot/_Commands.py deleted file mode 100644 index 7e36334..0000000 --- a/MeowerBot/_Commands.py +++ /dev/null @@ -1,5 +0,0 @@ -import warnings - -warnings.warn("MeowerBot._Command has been moved to MeowerBot.command") - -from .command import * diff --git a/MeowerBot/__init__.py b/MeowerBot/__init__.py index 7ff7fec..3029a22 100644 --- a/MeowerBot/__init__.py +++ b/MeowerBot/__init__.py @@ -5,12 +5,12 @@ """ -__version__ = "2.6.2" +__version__ = "3.0.0" # Public library imports from . import Bot as botm -from .Bot import Bot +from .Bot import Bot, cbids -__all__ = ["__version__", "Bot", "botm"] +__all__ = ["__version__", "Bot", "botm", "cbids"] diff --git a/MeowerBot/cl/__init__.py b/MeowerBot/cl/__init__.py index 13cb868..ca75078 100644 --- a/MeowerBot/cl/__init__.py +++ b/MeowerBot/cl/__init__.py @@ -1 +1,120 @@ -from .cloudlink import * +import websockets +import orjson +import json +import asyncio +import random +import time +class Client: + ws: websockets.WebSocketClientProtocol + message_condition: asyncio.Condition + _packets: list + + def __init__(self): + self.ws = None + self._packets = [] + self.message_condition = asyncio.Condition() + pass + + async def _connect(self): + pass + + async def _disconnect(self): + pass + + async def _message(self, message): + pass + + async def _error(self, error): + pass + + async def sendPacket(self, message): + await self.ws.send(json.dumps(message)) + + async def _wait_for_packet(self, conditions, expected_count=None, timeout=None): + """ + Wait for multiple JSON packets, each meeting a specific condition, in the bot's messages list. + Args: + - conditions (list of dict): A list of dictionaries, each representing a condition to check for. + - expected_count (int): Optional. The number of conditions to wait for. If None, wait for all conditions. + - timeout (float): Optional. Maximum time to wait in seconds for the specified conditions. If None, it will wait indefinitely. + Returns: + - A list of messages that meet the specified conditions, or None if timeout is reached. + """ + + + start_time = time.time() + received_packets = [] + + while True: + async with self.message_condition: + await self.message_condition.wait() + for condition in conditions: + if expected_count is not None and len(received_packets) >= expected_count: + return received_packets + found = False + for message in self._packets: + if all(message.get(key) == value for key, value in condition.items()): + received_packets.append(message) + found = True + break + elif message["cmd"] == "statuscode": + return ([None]*expected_count - 1) + [message] + if not found: + break + + if expected_count is None and len(received_packets) == len(conditions): + return received_packets + if timeout is not None and time.time() - start_time >= timeout: + return None + + async def send_statuscode_request(self, packet, timeout = 0): + if packet.get("listener") == None: + # This does not need to be sucure lmao + packet["listener"] = random.random() # nosec + + await self.sendPacket(packet) + return (await self._wait_for_packet({"listener": packet["listener"]}, expected_count=1, timeout=timeout))[0] + + async def close(self, reason=None): + await self.ws.close(reason=reason) + + async def connect(self, server): + loop = asyncio.get_event_loop() + async for websocket in websockets.connect(server, ping_interval = None): # Meower uses its own implementation, crashes the connection if left on. + try: + + self.ws = websocket + try: + t = loop.create_task(self._connect()) + except Exception as e: + await self._error(e) + + async for message in websocket: + try: + data = json.loads(message) + async with self.message_condition._lock: + self._packets.append(data) + self.message_condition.notify_all() + self._packets = self._packets[:50] + + + await self._message(data) + + + except websockets.ConnectionClosed: + await self._disconnect() + + except Exception as e: + + await self._error(e) + + except websockets.ConnectionClosed: + await self._disconnect() + pass + + except Exception as e: + await self._error(e) + + await self._disconnect() + + diff --git a/MeowerBot/cl/cloudlink.py b/MeowerBot/cl/cloudlink.py deleted file mode 100644 index 8209213..0000000 --- a/MeowerBot/cl/cloudlink.py +++ /dev/null @@ -1,237 +0,0 @@ -# type: ignore - -#!/usr/bin/env python3 - - - -version = "0.1.7.4" - -# Server based on https://github.com/Pithikos/python-websocket-server -# Client based on https://github.com/websocket-client/websocket-client - -""" -CloudLink by MikeDEV, ShowierData9978 -Please see https://github.com/MikeDev101/cloudlink for more details. -0BSD License -Copyright (C) 2020-2022 MikeDEV Software, Co. -Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. -THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -Modified for use in MeowerBot.py by ShowierData9978 - -- stripped everything server related -- made lib use logging insted of print -""" - -import json -import threading -import websocket as ws_client # type: ignore -import logging -import logging as log - -""" -Code formatting -(Type):(Code) | (Description) -Type: Letter - I - Info - E - Error -Code: Number, defines the code -Description: String, Describes the code -""" - - -class API: - def __init__(self, logging=None): - self.logging = logging or log.getLogger("CloudLink") - self.logging.debug("CloudLink API initialized") - - self.callback_function = { - "error": self._on_error_client, # type: ignore - "connection": self._on_connection_client, # type: ignore - "closed_connection": self._closed_connection_client, # type: ignore - "packet": self._on_packet_client, # type: ignore - } - - self.statedata = {} - - def client(self, ip="ws://127.0.0.1:3000/"): # Runs CloudLink in client mode. - try: - - # Change the link state to 2 (Client mode) - self.wss = ws_client.WebSocketApp( - ip, - on_message=self._on_packet_client, # type: ignore - on_error=self._on_error_client, # type: ignore - on_open=self._on_connection_client, # type: ignore - on_close=self._closed_connection_client, # type: ignore - ) - - # Format dict for storing this mode's specific data - self.statedata = { - "ulist": {"usernames": []}, - } - - # Run the client - self.wss.run_forever() - except BaseException as e: - self.logging.error(f"Error at client: {e}") - self._on_error_client(self.wss, e) - - def stop(self, abrupt=False): # Stops CloudLink (not sure if working) - self.wss.close() - - def callback( - self, callback_id, function - ): # Add user-friendly callbacks for CloudLink to be useful as a module - try: - if callback_id in self.callback_function: - self.callback_function[callback_id] = function - - self.logging.debug(f"Binded callback {callback_id}.") - else: - self.logging.error( - f"Error: Callback {callback_id} is not a valid callback id!" - ) - except BaseException as e: - self.logging.error(f"Error at callback: {e}") - self._on_error_client(self.wss, e) - - def sendPacket( - self, msg - ): # User-friendly message sender for both server and client. - try: - - self.logging.debug(f"Sending {json.dumps(msg)}") - self.wss.send(json.dumps(msg)) - except BaseException as e: - self.logging.error(f"Error on sendPacket (client): {e}") - self._on_error_client(self.wss, e) - - def getUsernames(self): # Returns the username list. - return self.statedata["ulist"]["usernames"] - - -class CloudLink(API): - def __init__(self): # Initializes CloudLink - self.wss = None # Websocket Object - self.userlist = [] # Stores usernames set on link - self.callback_function = { # For linking external code, use with functions - "on_connect": None, # Handles new connections (server) or when connected to a server (client) - "on_error": None, # Error reporter - "on_packet": None, # Packet handler - "on_close": None, # Runs code when disconnected (client) or server stops (server) - } - - self.statedata = {} # Place to store other garbage for modes - self.logging = logging.getLogger("Cloudlink") - - self.logging.info(f"CloudLink v{str(version)}") # Report version number - - @staticmethod - def _is_json(data): # Checks if something is JSON - if type(data) is dict: - return True - try: - tmp = json.loads(data) - return True - except Exception as e: - return False - - def _on_connection_client(self, ws): # Client-side connection handler - try: - - self.logging.info("Connected") - self.wss.send( - json.dumps({"cmd": "direct", "val": {"cmd": "type", "val": "py"}}) - ) # Specify to the server that the client is based on Python - if not self.callback_function["on_connect"] is None: - - def run(*args): - try: - self.callback_function["on_connect"]() - except BaseException as e: - self.logging.error(f"Error on _on_connection_client: {e}") - self._on_error_client(self.wss, error) - - threading.Thread(target=run).start() - except BaseException as e: - self.logging.info(f"Error on _on_connection_client: {e}") - self._on_error_client(self.wss, e) - - - def _on_packet_client(self, ws, message): # Client-side packet handler - try: - - self.logging.debug(f"New packet: {message}") - - tmp = json.loads(message) - if (("cmd" in tmp) and (tmp["cmd"] == "ulist")) and ("val" in tmp): - self.statedata["ulist"]["usernames"] = str(tmp["val"]).split(";") - del self.statedata["ulist"]["usernames"][ - len(self.statedata["ulist"]["usernames"]) - 1 - ] - - self.logging.info( - f"Username list: {str(self.statedata['ulist']['usernames'])}" - ) - - if not self.callback_function["on_packet"] == None: - - def run(*args): - try: - self.callback_function["on_packet"](message) - except BaseException as e: - - self.logging.error(f"Error on _on_packet_client: {e}") - self._on_error_client(self.wss, e) - - threading.Thread(target=run).start() - except BaseException as e: - self.logging.error(f"Error on _on_packet_client: {e}") - self._on_error_client(self.wss, e) - - def _on_error_client(self, ws, error): # Client-side error handler - try: - - self.logging.error(f"Error: {error}") - if not self.callback_function["on_error"] is None: - - def run(*args): - try: - self.callback_function["on_error"](error) - except BaseException as e: - self.logging.error(f"Error on _on_error_client: {e}") - - self._on_error_client(self.wss, e) - - threading.Thread(target=run).start() - except BaseException as e: - - self.logging.error(f"Error on _on_error_client: {e}") - self._on_error_client(self.wss, e) - - def _closed_connection_client( - self, ws, close_status_code, close_msg - ): # Client-side closed connection handler - try: - - self.logging.info( - f"Closed, status: {close_status_code} with code {close_msg}" - ) - if not self.callback_function["on_close"] is None: - - def run(*args): - try: - self.callback_function["on_close"]() - except BaseException as e: - - self.logging.error(f"Error on _closed_connection_client: {e}") - self._on_error_client(self.wss, e) - - threading.Thread(target=run).start() - except BaseException as e: - self.logging.error(f"Error on _closed_connection_client: {e}") - self._on_error_client(self.wss, e) diff --git a/MeowerBot/cog.py b/MeowerBot/cog.py index fa3caa9..6268344 100644 --- a/MeowerBot/cog.py +++ b/MeowerBot/cog.py @@ -3,19 +3,30 @@ class Cog: - __commands__ = None + commands = None __instence__ = None def __init__(self) -> None: + if isinstance(self.__instence__, Cog): + return + + self.__class__.__instence__ = self commands = {} + for command in self.__dir__(): attr = getattr(self, command) if isinstance(attr, AppCommand): attr.register_class(self) commands.update(attr.info()) - self.__commands__ = commands + self.commands = commands + + def update_commands(self): + for command in self.__dir__(): + attr = getattr(self, command) + if isinstance(attr, AppCommand): + self.commands = AppCommand.add_command(self.commands, attr) def __new__(cls, *args, **kwargs): if cls.__instence__ is None: diff --git a/MeowerBot/command.py b/MeowerBot/command.py index 8c96c55..1319a58 100644 --- a/MeowerBot/command.py +++ b/MeowerBot/command.py @@ -7,118 +7,115 @@ class AppCommand: - connected = None + connected = None - def __init__(self, func, name=None, args=0, is_subcommand=False): - if name is None: - name = func.__name__ + @staticmethod + def add_command(obj: dict, command: "AppCommand", ignore_subcommands = True): + if command.is_subcommand and ignore_subcommands: + return obj - self.name = name - self.func = func - self.args_num = args + for alias in command.alias + [command.name]: + obj[alias] = command - spec = inspect.signature(func) + + - # Get the names and annotations of the arguments - self.args = [ - (param.name, param.annotation) - for param in spec.parameters.values() - if param.name not in ["self", "ctx"] - ] + return obj + - # Check if the function has an arbitrary number of positional arguments - self.has_unamed_args = any( - param.kind == inspect.Parameter.VAR_POSITIONAL for param in spec.parameters.values() - ) + def __init__(self, func, alias = None, name=None, args=0, is_subcommand=False): + if name is None: + name = func.__name__ + + if alias is None: + alias = [] - self.is_subcommand = is_subcommand + self.name = name + self.func = func + self.args_num = args + self.alias = alias + spec = inspect.signature(func) - # Get the names, annotations, and default values of the keyword-only arguments - self.optional_args = [ - (param.name, param.annotation, param.default) - for param in spec.parameters.values() - if param.kind == inspect.Parameter.KEYWORD_ONLY - ] + # Get the names and annotations of the arguments + self.args = [ + (param.name, param.annotation) + for param in spec.parameters.values() + if param.name not in ["self", "ctx"] + ] - # Set the namespace based on whether the command is a subcommand or not - self.namespace = self.is_subcommand if type(self.is_subcommand) is str else self.name + # Check if the function has an arbitrary number of positional arguments + self.has_unamed_args = any( + param.kind == inspect.Parameter.VAR_POSITIONAL for param in spec.parameters.values() + ) + self.is_subcommand = is_subcommand - self.subcommands = {} + # Get the names, annotations, and default values of the keyword-only arguments + self.optional_args = [ + (param.name, param.annotation, param.default) + for param in spec.parameters.values() + if param.kind == inspect.Parameter.KEYWORD_ONLY + ] - def __call__(self, *args): - raise RuntimeError("AppCommand is not callable") + # Set the namespace based on whether the command is a subcommand or not + self.namespace = self.is_subcommand if type(self.is_subcommand) is str else self.name - def register_class(self, con): - self.connected = con - for subcommand in self.subcommands.values(): - subcommand.register_class(con) + self.subcommands = {} + def __call__(self, *args): + raise RuntimeError("AppCommand is not callable") + def register_class(self, con): + self.connected = con - def subcommand(self, name=None, args=0): - def inner(func): + for subcommand in self.subcommands.values(): + subcommand.register_class(con) - cmd = AppCommand(func, name=name, args=args) - cmd.register_class(self.connected) - self.subcommands.update(cmd.info()) + def subcommand(self, name=None, args=0, aliases = None): + def inner(func): - return func #dont want mb to register this as a root command - return inner - + cmd = AppCommand(func, name=name, args=args) + cmd.register_class(self.connected) - def run_cmd(self, ctx, *args): - - try: - self.subcommands[args[0]]["command"].run_cmd(ctx, *args[1:]) - return - except KeyError: - #print(f"KeyError: {args}") - #print(f"Subcommands: {self.subcommands}") - logger.debug(f"Cant find subcommand {args[0]}") + self.subcommand = AppCommand.add_command(self.subcommands, cmd) + self.connected.update_commands() - except IndexError: - logger.debug(traceback.format_exc()) - - if not self.args_num == 0: - args = args[:self.args_num] + return cmd #dont want mb to register this as a root command + return inner + - if self.connected is None: - self.func(ctx, *args) - else: - self.func(self.connected, ctx, *args) + async def run_cmd(self, ctx, *args): + + try: + await self.subcommands[args[0]]["command"].run_cmd(ctx, *args[1:]) + return + except KeyError: + #print(f"KeyError: {args}") + #print(f"Subcommands: {self.subcommands}") + logger.debug(f"Cant find subcommand {args[0]}") + except IndexError: + pass - def info(self): - return { - self.name: { - "args": self.args, - "args_num": self.args_num, - "optional_args": self.optional_args, - "has_unamed_args": self.has_unamed_args, - "subcommands": self.subcommands, - "command": self, - "func": self.func, + except IndexError: + logger.debug(traceback.format_exc()) + + if not self.args_num == 0: + args = args[:self.args_num] - } - } + + await self.func(ctx, *args) + -class _Command(AppCommand): - def __init__(self, func, *args, name=None, **kwargs): - super().__init__(func, *args, name=name, **kwargs) - warnings.warn( - "MeowerBot.command._Command has been renamed to MeowerBot.command.AppCommand" - ) - def command(name=None, args=0): - def inner(func): + def inner(func): - cmd = AppCommand(func, name=name, args=args) + cmd = AppCommand(func, name=name, args=args) - return cmd + return cmd - return inner + return inner diff --git a/MeowerBot/context.py b/MeowerBot/context.py index 3695cb6..05ae688 100644 --- a/MeowerBot/context.py +++ b/MeowerBot/context.py @@ -1,61 +1,93 @@ from datetime import datetime -import typing from typing import TYPE_CHECKING if TYPE_CHECKING: from .Bot import Bot -import weakref -import requests +from .types.api.chats import ChatGroup +from .types.api.user import User as RawUser +from .types.generic import Post +class PartialChat: + def __init__(self, id, bot: "Bot"): + self.id = id + self.bot: "Bot" = bot -class User: - def __init__(self, bot, username): - self.username = username - - self.bot = bot - self._raw = self.bot.api.get_user(self.username) + async def send_msg(self, message) -> Post: + return await Post(self.bot, (await (self.bot.api.send_post(self.id, message))).to_dict(), self) - self.level = self._raw["lvl"] - self.pfp = self._raw["pfp_data"] - self.quote = self._raw["quote"] + async def fetch(self): + return Chat(await self.bot.api.get_chat(self.id)) - +class Chat(PartialChat): + def __init__(self, data: ChatGroup, bot): + super().__init__(data._id, bot) - def ping(self, msg, to="home"): - self.bot.send_msg(f"@{self.username} {msg}", to=to) + self.created = data.created + self.deleted = data.deleted + self.last_active = data.last_active + self.members = data.members + + self.owner = data.owner + self.type = data.type + self.nickname = data.nickname - def __str__(self): - return str(self.__dict__) +class PartialUser: + def __init__(self, username, bot: "Bot"): + self.username = username + self.bot = bot + async def fetch(self): + return User(self.username, RawUser.from_json(await self.bot.api._get_user(self.username, ""))) + +class User(PartialUser): + def __init__(self, username, bot, data: RawUser): + super().__init__(username, bot) + + self.data: RawUser = data + + self.banned = self.data.banned + self.created = self.data.created + self.flags = self.data.flags + self.last_seen = self.data.last_seen + self.data.lower_username = self.data.lower_username + self.lvl = self.data.lvl + self.name = self.data.name + self.permissions = self.data.permissions + self.pfp_data = self.data.pfp_data + self.quote = self.data.quote + self.id = self.data.uuid + class Post: - def __init__(self, bot, _raw): + def __init__(self, bot, _raw, chat): self.bot = bot self._raw = _raw - self.user = User(bot, self._raw["u"]) + self.user: PartialUser = PartialUser(bot, self._raw["u"]) - self.chat = self._raw["post_origin"] + self.chat: PartialChat = PartialChat(chat, bot) self.data = self._raw["p"] self._id = self._raw["post_id"] self.type = self._raw["type"] self.date = datetime.fromtimestamp(self._raw["t"]["e"]) - self.ctx: CTX = None # type: ignore def __str__(self): return str(self.data) + + async def reply(self, message): + self.chat.send_msg(f"@{self.user.username} [{self.id}] {message}") -class CTX: +class Context: def __init__(self, post, bot): - self.message = Post(bot, post) + self.message = post self.user = self.message.user self.bot = bot - self.message.ctx = weakref.proxy(self) # type: ignore - def send_msg(self, msg): - self.bot.send_msg(msg, to=self.message.chat) + async def send_msg(self, msg): + await self.message.chat.send_msg(msg) + + async def reply(self, msg): + await self.message.reply(msg) - def reply(self, msg): - self.user.ping(msg, to=self.message.chat) diff --git a/MeowerBot/ext/discord.py b/MeowerBot/ext/discord.py index 1415d84..b6d428e 100644 --- a/MeowerBot/ext/discord.py +++ b/MeowerBot/ext/discord.py @@ -1,25 +1,22 @@ from MeowerBot import Bot - - - class DiscBotMeower(Bot): - def __init__(self, prefix=None, autoreload: int or None = None): - super().__init__(prefix, autoreload) - - self.callback(self.on_message, "message") - self.callback(self.on_login, "login") - self.callback(self.on_disconnect, "close") - self.callback(self.on_error, "error") - self.callback(self.on_raw_message, "raw_message") - self.callback(self.on_pmsg, "pmsg") - self.callback(self.on_ulist, "ulist") - self.callback(self.on_statuscode, "statuscode") - self.callback(self.on_chatlist, "chatlist") - self.callback(self.on_raw_packet, "__raw__") - - def on_message(self, msg): + def __init__(self, prefix=None, autoreload: int or None = None): + super().__init__(prefix, autoreload) + + self.callback(self.on_message, "message") + self.callback(self.on_login, "login") + self.callback(self.on_disconnect, "close") + self.callback(self.on_error, "error") + self.callback(self.on_raw_message, "raw_message") + self.callback(self.on_pmsg, "pmsg") + self.callback(self.on_ulist, "ulist") + self.callback(self.on_statuscode, "statuscode") + self.callback(self.on_chatlist, "chatlist") + self.callback(self.on_raw_packet, "__raw__") + + async def on_message(self, msg): if ctx.user.username == self.username: return if not ctx.message.data.startswith(self.prefix): @@ -27,47 +24,47 @@ def on_message(self, msg): ctx.message.data = ctx.message.data.split(self.prefix, 1)[1] - self.run_command(ctx.message) + await self.run_command(ctx.message) + + async def on_login(self): + pass - def on_login(self): - pass + async def on_disconnect(self): + pass - def on_disconnect(self): - pass + async def on_error(self, err): + pass - def on_error(self, err): - pass + async def on_raw_message(self, msg): + pass - def on_raw_message(self, msg): - pass + async def on_pmsg(self, msg): + pass - def on_pmsg(self, msg): - pass + async def on_ulist(self, ulist): + pass - def on_ulist(self, ulist): - pass + async def on_statuscode(self, status, listener): + pass - def on_statuscode(self, status, listener): - pass + async def on_chatlist(self, chatlist, listener): + pass - def on_chatlist(self, chatlist, listener): - pass + async def on_raw_packet(self, packet): + pass - def on_raw_packet(self, packet): - pass + def watch(self, event=None): + def decorator(func): + if event is None: + event = func.__name__ + self.callback(func, event) + return func + return decorator - def watch(self, event=None): - def decorator(func): - if event is None: - event = func.__name__ - self.callback(func, event) - return func - return decorator - - def event(self, event=None): - def decorator(func): - if event is None: - event = func.__name__ - setattr(self, event, func) - return func - return decorator \ No newline at end of file + def event(self, event=None): + def decorator(func): + if event is None: + event = func.__name__ + setattr(self, event, func) + return func + return decorator diff --git a/MeowerBot/ext/help.py b/MeowerBot/ext/help.py index 0f328af..d110561 100644 --- a/MeowerBot/ext/help.py +++ b/MeowerBot/ext/help.py @@ -72,7 +72,7 @@ def handle_command(self, name, cmd: AppCommand): if cmd.func.__doc__ is not None: self.page += f"\n\t{cmd.func.__doc__}" - + self.page += "\n" @@ -85,15 +85,15 @@ def handle_command(self, name, cmd: AppCommand): self.page += "\n" @command(name="help") - def help(self, ctx, page: int=0): + async def help(self, ctx, page: int=0): if page >= len(self.pages): page = len(self.pages) - 1 - ctx.send_msg(self.pages[page]) + await ctx.send_msg(self.pages[page]) - def _login(self, bot): + async def _login(self, bot): self.generate_help() #generate help on login, bugfix for default prefix and people being dumb \ No newline at end of file diff --git a/tests/__init__.py b/MeowerBot/types/__init__.py similarity index 100% rename from tests/__init__.py rename to MeowerBot/types/__init__.py diff --git a/MeowerBot/types/api/__init__.py b/MeowerBot/types/api/__init__.py new file mode 100644 index 0000000..13ddce1 --- /dev/null +++ b/MeowerBot/types/api/__init__.py @@ -0,0 +1,20 @@ +from dataclasses import dataclass, field +from dataclasses_json import config, dataclass_json +from typing import List, TypeVar, Generic, Optional, NewType + + +from ..generic import Post, UUID +from .reports import PagedRequest +from .user import User + +class Inbox(PagedRequest[Post]): pass +class PostList(PagedRequest[Post]): pass +class UserList(PagedRequest[User]): pass + +@dataclass_json +@dataclass +class Statistics: + chats: int + error: bool + posts: int + users: int diff --git a/MeowerBot/types/api/chats.py b/MeowerBot/types/api/chats.py new file mode 100644 index 0000000..7d87897 --- /dev/null +++ b/MeowerBot/types/api/chats.py @@ -0,0 +1,21 @@ +from dataclasses import dataclass, field +from dataclasses_json import config, dataclass_json +from typing import List, TypeVar, Generic, Optional, NewType + + +from ..generic import Post, UUID +from .reports import PagedRequest + +@dataclass_json +@dataclass +class ChatGroup: + _id: str + created: int + deleted: bool + last_active: int + members: List[str] + nickname: Optional[str] + owner: Optional[str] + type: int + +class Chats(PagedRequest[ChatGroup]): pass diff --git a/MeowerBot/types/api/reports.py b/MeowerBot/types/api/reports.py new file mode 100644 index 0000000..b8d149c --- /dev/null +++ b/MeowerBot/types/api/reports.py @@ -0,0 +1,55 @@ +from dataclasses import dataclass, field +from dataclasses_json import config, dataclass_json +from typing import List, TypeVar, Generic, Optional, NewType + + +from ..generic import Post, UUID + +T = TypeVar("T") + +@dataclass_json +@dataclass +class PagedRequest(Generic[T]): + error: bool + page: int = field(metadata=config(field_name="page#")) + pages: int + + index: Optional[List[UUID]] + autoget: Optional[List[T]] + + + +@dataclass_json +@dataclass +class ReportDetails: + comment: str + reason: str + time: int + user: str + +@dataclass_json +@dataclass +class Report: + _id: UUID + content: Post + escalated: bool + reports: List[ReportDetails] + status: str + type_: str = field(metadata=config(field_name="type")) + + + +class ReportRequest(PagedRequest): + autoget: List[Report] + +from dataclasses import dataclass +from dataclasses_json import dataclass_json + +@dataclass_json +@dataclass +class AdminNotesResponse: + _id: str + notes: str + last_modified_by: str + last_modified_at: int + error: bool diff --git a/MeowerBot/types/api/user.py b/MeowerBot/types/api/user.py new file mode 100644 index 0000000..981b244 --- /dev/null +++ b/MeowerBot/types/api/user.py @@ -0,0 +1,70 @@ + +from dataclasses import dataclass, field +from dataclasses_json import config, dataclass_json +from ..generic import UUID, BitFlag + +class UserFlags: + SYSTEM = 1 + DELETED = 2 + PROTECTED = 4 + + +class Permissions: + SYSADMIN = 1 + + VIEW_REPORTS = 2 + EDIT_REPORTS = 4 + + VIEW_NOTES = 8 + EDIT_NOTES = 16 + + VIEW_POSTS = 32 + DELETE_POSTS = 64 + + VIEW_ALTS = 128 + SEND_ALERTS = 256 + KICK_USERS = 512 + CLEAR_USER_QUOTES = 1024 + VIEW_BAN_STATES = 2048 + EDIT_BAN_STATES = 4096 + DELETE_USERS = 8192 + + VIEW_IPS = 16384 + BLOCK_IPS = 32768 + + VIEW_CHATS = 65536 + EDIT_CHATS = 131072 + + SEND_ANNOUNCEMENTS = 262144 + + +class Restrictions: + HOME_POSTS = 1 + CHAT_POSTS = 2 + NEW_CHATS = 4 + EDITING_CHAT_NICKNAMES = 8 + EDITING_QUOTE = 16 + + +@dataclass_json +@dataclass +class User: + name: str = field(metadata=config(field_name="_id")) + banned: bool + created: int + error: bool + flags: BitFlag + last_seen: int + lower_username: str + lvl: int + permissions: BitFlag + pfp_data: int + quote: str + uuid: UUID + +@dataclass_json +@dataclass +class Relationship: + username: str + state: int + updated_at: int \ No newline at end of file diff --git a/MeowerBot/types/generic.py b/MeowerBot/types/generic.py new file mode 100644 index 0000000..4b4c93b --- /dev/null +++ b/MeowerBot/types/generic.py @@ -0,0 +1,33 @@ +from dataclasses import dataclass, field +from dataclasses_json import config, dataclass_json +from typing import List +from dataclasses import dataclass, field +from dataclasses_json import config, dataclass_json +from typing import List, TypeVar, Generic, Optional, NewType + +T = TypeVar("T") +UUID = NewType("UUID", str) +BitFlag = NewType("BitFlag", int) + +@dataclass_json +@dataclass +class Timestamp: + d: str + e: int + h: str + mi: str + mo: str + s: str + y: str + +@dataclass_json +@dataclass +class Post: + _id: UUID + isDeleted: bool + p: str + post_id: UUID + post_origin: str + t: Timestamp + type: int + u: str \ No newline at end of file diff --git a/SECURITY.md b/SECURITY.md index 1b235f0..e8ced35 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -6,7 +6,8 @@ | Version | Supported | | ------- | ------------------ | -| 2.x.x | :white_check_mark: | +| 3.x.x | :white_check_mark: | +| 2.x.x | :x: | | 1.x.x | :x: | diff --git a/poetry.lock b/poetry.lock index 2895508..4cd7d03 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,15 +1,25 @@ # This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. [[package]] -name = "backports-strenum" -version = "1.2.4" -description = "Base class for creating enumerated constants that are also subclasses of str" +name = "anyio" +version = "4.0.0" +description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false -python-versions = ">=3.8, <4" +python-versions = ">=3.8" files = [ - {file = "backports.strenum-1.2.4.tar.gz", hash = "sha256:87b67fd1413af3ce959b565d84ddef99776cdd97a62e2fd2d0550cdacc210dee"}, + {file = "anyio-4.0.0-py3-none-any.whl", hash = "sha256:cfdb2b588b9fc25ede96d8db56ed50848b0b649dca3dd1df0b11f683bb9e0b5f"}, + {file = "anyio-4.0.0.tar.gz", hash = "sha256:f7ed51751b2c2add651e5747c891b47e26d2a21be5d32d9311dfe9692f3e5d7a"}, ] +[package.dependencies] +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)"] + [[package]] name = "bandit" version = "1.7.5" @@ -44,90 +54,6 @@ files = [ {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"}, ] -[[package]] -name = "charset-normalizer" -version = "3.1.0" -description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -optional = false -python-versions = ">=3.7.0" -files = [ - {file = "charset-normalizer-3.1.0.tar.gz", hash = "sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-win32.whl", hash = "sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448"}, - {file = "charset_normalizer-3.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-win32.whl", hash = "sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909"}, - {file = "charset_normalizer-3.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-win32.whl", hash = "sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974"}, - {file = "charset_normalizer-3.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-win32.whl", hash = "sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0"}, - {file = "charset_normalizer-3.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-win32.whl", hash = "sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1"}, - {file = "charset_normalizer-3.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b"}, - {file = "charset_normalizer-3.1.0-py3-none-any.whl", hash = "sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d"}, -] - [[package]] name = "colorama" version = "0.4.6" @@ -139,6 +65,21 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "dataclasses-json" +version = "0.6.1" +description = "Easily serialize dataclasses to and from JSON." +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "dataclasses_json-0.6.1-py3-none-any.whl", hash = "sha256:1bd8418a61fe3d588bb0079214d7fb71d44937da40742b787256fd53b26b6c80"}, + {file = "dataclasses_json-0.6.1.tar.gz", hash = "sha256:a53c220c35134ce08211a1057fd0e5bf76dc5331627c6b241cacbc570a89faae"}, +] + +[package.dependencies] +marshmallow = ">=3.18.0,<4.0.0" +typing-inspect = ">=0.4.0,<1" + [[package]] name = "gitdb" version = "4.0.10" @@ -155,18 +96,76 @@ smmap = ">=3.0.1,<6" [[package]] name = "gitpython" -version = "3.1.32" +version = "3.1.38" description = "GitPython is a Python library used to interact with Git repositories" optional = false python-versions = ">=3.7" files = [ - {file = "GitPython-3.1.32-py3-none-any.whl", hash = "sha256:e3d59b1c2c6ebb9dfa7a184daf3b6dd4914237e7488a1730a6d8f6f5d0b4187f"}, - {file = "GitPython-3.1.32.tar.gz", hash = "sha256:8d9b8cb1e80b9735e8717c9362079d3ce4c6e5ddeebedd0361b228c3a67a62f6"}, + {file = "GitPython-3.1.38-py3-none-any.whl", hash = "sha256:9e98b672ffcb081c2c8d5aa630d4251544fb040fb158863054242f24a2a2ba30"}, + {file = "GitPython-3.1.38.tar.gz", hash = "sha256:4d683e8957c8998b58ddb937e3e6cd167215a180e1ffd4da769ab81c620a89fe"}, ] [package.dependencies] gitdb = ">=4.0.1,<5" +[package.extras] +test = ["black", "coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest", "pytest-cov", "pytest-instafail", "pytest-subtests", "pytest-sugar"] + +[[package]] +name = "h11" +version = "0.14.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.7" +files = [ + {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, + {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, +] + +[[package]] +name = "httpcore" +version = "0.18.0" +description = "A minimal low-level HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpcore-0.18.0-py3-none-any.whl", hash = "sha256:adc5398ee0a476567bf87467063ee63584a8bce86078bf748e48754f60202ced"}, + {file = "httpcore-0.18.0.tar.gz", hash = "sha256:13b5e5cd1dca1a6636a6aaea212b19f4f85cd88c366a2b82304181b769aab3c9"}, +] + +[package.dependencies] +anyio = ">=3.0,<5.0" +certifi = "*" +h11 = ">=0.13,<0.15" +sniffio = "==1.*" + +[package.extras] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] + +[[package]] +name = "httpx" +version = "0.25.0" +description = "The next generation HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpx-0.25.0-py3-none-any.whl", hash = "sha256:181ea7f8ba3a82578be86ef4171554dd45fec26a02556a744db029a0a27b7100"}, + {file = "httpx-0.25.0.tar.gz", hash = "sha256:47ecda285389cb32bb2691cc6e069e3ab0205956f681c5b2ad2325719751d875"}, +] + +[package.dependencies] +certifi = "*" +httpcore = ">=0.18.0,<0.19.0" +idna = "*" +sniffio = "*" + +[package.extras] +brotli = ["brotli", "brotlicffi"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] + [[package]] name = "idna" version = "3.4" @@ -178,15 +177,34 @@ files = [ {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, ] +[[package]] +name = "jedi" +version = "0.19.1" +description = "An autocompletion tool for Python that can be used for text editors." +optional = false +python-versions = ">=3.6" +files = [ + {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"}, + {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"}, +] + +[package.dependencies] +parso = ">=0.8.3,<0.9.0" + +[package.extras] +docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] +qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] +testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] + [[package]] name = "markdown-it-py" -version = "2.2.0" +version = "3.0.0" description = "Python port of markdown-it. Markdown parsing, done right!" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "markdown-it-py-2.2.0.tar.gz", hash = "sha256:7c9a5e412688bc771c67432cbfebcdd686c93ce6484913dccf06cb5a0bea35a1"}, - {file = "markdown_it_py-2.2.0-py3-none-any.whl", hash = "sha256:5a35f8d1870171d9acc47b99612dc146129b631baf04970128b568f190d0cc30"}, + {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] @@ -199,9 +217,29 @@ compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0 linkify = ["linkify-it-py (>=1,<3)"] plugins = ["mdit-py-plugins"] profiling = ["gprof2dot"] -rtd = ["attrs", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +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 = "marshmallow" +version = "3.20.1" +description = "A lightweight library for converting complex datatypes to and from native Python datatypes." +optional = false +python-versions = ">=3.8" +files = [ + {file = "marshmallow-3.20.1-py3-none-any.whl", hash = "sha256:684939db93e80ad3561392f47be0230743131560a41c5110684c16e21ade0a5c"}, + {file = "marshmallow-3.20.1.tar.gz", hash = "sha256:5d2371bbe42000f2b3fb5eaa065224df7d8f8597bc19a1bbfa5bfe7fba8da889"}, +] + +[package.dependencies] +packaging = ">=17.0" + +[package.extras] +dev = ["flake8 (==6.0.0)", "flake8-bugbear (==23.7.10)", "mypy (==1.4.1)", "pre-commit (>=2.4,<4.0)", "pytest", "pytz", "simplejson", "tox"] +docs = ["alabaster (==0.7.13)", "autodocsumm (==0.2.11)", "sphinx (==7.0.1)", "sphinx-issues (==3.0.1)", "sphinx-version-warning (==1.1.2)"] +lint = ["flake8 (==6.0.0)", "flake8-bugbear (==23.7.10)", "mypy (==1.4.1)", "pre-commit (>=2.4,<4.0)"] +tests = ["pytest", "pytz", "simplejson"] + [[package]] name = "mdurl" version = "0.1.2" @@ -213,6 +251,102 @@ files = [ {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, ] +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "orjson" +version = "3.9.9" +description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" +optional = false +python-versions = ">=3.8" +files = [ + {file = "orjson-3.9.9-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:f28090060a31f4d11221f9ba48b2273b0d04b702f4dcaa197c38c64ce639cc51"}, + {file = "orjson-3.9.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8038ba245d0c0a6337cfb6747ea0c51fe18b0cf1a4bc943d530fd66799fae33d"}, + {file = "orjson-3.9.9-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:543b36df56db195739c70d645ecd43e49b44d5ead5f8f645d2782af118249b37"}, + {file = "orjson-3.9.9-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8e7877256b5092f1e4e48fc0f1004728dc6901e7a4ffaa4acb0a9578610aa4ce"}, + {file = "orjson-3.9.9-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12b83e0d8ba4ca88b894c3e00efc59fe6d53d9ffb5dbbb79d437a466fc1a513d"}, + {file = "orjson-3.9.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ef06431f021453a47a9abb7f7853f04f031d31fbdfe1cc83e3c6aadde502cce"}, + {file = "orjson-3.9.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0a1a4d9e64597e550428ba091e51a4bcddc7a335c8f9297effbfa67078972b5c"}, + {file = "orjson-3.9.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:879d2d1f6085c9c0831cec6716c63aaa89e41d8e036cabb19a315498c173fcc6"}, + {file = "orjson-3.9.9-cp310-none-win32.whl", hash = "sha256:d3f56e41bc79d30fdf077073072f2377d2ebf0b946b01f2009ab58b08907bc28"}, + {file = "orjson-3.9.9-cp310-none-win_amd64.whl", hash = "sha256:ab7bae2b8bf17620ed381e4101aeeb64b3ba2a45fc74c7617c633a923cb0f169"}, + {file = "orjson-3.9.9-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:31d676bc236f6e919d100fb85d0a99812cff1ebffaa58106eaaec9399693e227"}, + {file = "orjson-3.9.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:678ffb5c0a6b1518b149cc328c610615d70d9297e351e12c01d0beed5d65360f"}, + {file = "orjson-3.9.9-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a71b0cc21f2c324747bc77c35161e0438e3b5e72db6d3b515310457aba743f7f"}, + {file = "orjson-3.9.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae72621f216d1d990468291b1ec153e1b46e0ed188a86d54e0941f3dabd09ee8"}, + {file = "orjson-3.9.9-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:512e5a41af008e76451f5a344941d61f48dddcf7d7ddd3073deb555de64596a6"}, + {file = "orjson-3.9.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f89dc338a12f4357f5bf1b098d3dea6072fb0b643fd35fec556f4941b31ae27"}, + {file = "orjson-3.9.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:957a45fb201c61b78bcf655a16afbe8a36c2c27f18a998bd6b5d8a35e358d4ad"}, + {file = "orjson-3.9.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d1c01cf4b8e00c7e98a0a7cf606a30a26c32adf2560be2d7d5d6766d6f474b31"}, + {file = "orjson-3.9.9-cp311-none-win32.whl", hash = "sha256:397a185e5dd7f8ebe88a063fe13e34d61d394ebb8c70a443cee7661b9c89bda7"}, + {file = "orjson-3.9.9-cp311-none-win_amd64.whl", hash = "sha256:24301f2d99d670ded4fb5e2f87643bc7428a54ba49176e38deb2887e42fe82fb"}, + {file = "orjson-3.9.9-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:bd55ea5cce3addc03f8fb0705be0cfed63b048acc4f20914ce5e1375b15a293b"}, + {file = "orjson-3.9.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b28c1a65cd13fff5958ab8b350f0921121691464a7a1752936b06ed25c0c7b6e"}, + {file = "orjson-3.9.9-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b97a67c47840467ccf116136450c50b6ed4e16a8919c81a4b4faef71e0a2b3f4"}, + {file = "orjson-3.9.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:75b805549cbbcb963e9c9068f1a05abd0ea4c34edc81f8d8ef2edb7e139e5b0f"}, + {file = "orjson-3.9.9-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5424ecbafe57b2de30d3b5736c5d5835064d522185516a372eea069b92786ba6"}, + {file = "orjson-3.9.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d2cd6ef4726ef1b8c63e30d8287225a383dbd1de3424d287b37c1906d8d2855"}, + {file = "orjson-3.9.9-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c959550e0705dc9f59de8fca1a316da0d9b115991806b217c82931ac81d75f74"}, + {file = "orjson-3.9.9-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ece2d8ed4c34903e7f1b64fb1e448a00e919a4cdb104fc713ad34b055b665fca"}, + {file = "orjson-3.9.9-cp312-none-win_amd64.whl", hash = "sha256:f708ca623287186e5876256cb30599308bce9b2757f90d917b7186de54ce6547"}, + {file = "orjson-3.9.9-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:335406231f9247f985df045f0c0c8f6b6d5d6b3ff17b41a57c1e8ef1a31b4d04"}, + {file = "orjson-3.9.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d9b5440a5d215d9e1cfd4aee35fd4101a8b8ceb8329f549c16e3894ed9f18b5"}, + {file = "orjson-3.9.9-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e98ca450cb4fb176dd572ce28c6623de6923752c70556be4ef79764505320acb"}, + {file = "orjson-3.9.9-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3bf6ca6bce22eb89dd0650ef49c77341440def966abcb7a2d01de8453df083a"}, + {file = "orjson-3.9.9-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eb50d869b3c97c7c5187eda3759e8eb15deb1271d694bc5d6ba7040db9e29036"}, + {file = "orjson-3.9.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fcf06c69ccc78e32d9f28aa382ab2ab08bf54b696dbe00ee566808fdf05da7d"}, + {file = "orjson-3.9.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9a4402e7df1b5c9a4c71c7892e1c8f43f642371d13c73242bda5964be6231f95"}, + {file = "orjson-3.9.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b20becf50d4aec7114dc902b58d85c6431b3a59b04caa977e6ce67b6fee0e159"}, + {file = "orjson-3.9.9-cp38-none-win32.whl", hash = "sha256:1f352117eccac268a59fedac884b0518347f5e2b55b9f650c2463dd1e732eb61"}, + {file = "orjson-3.9.9-cp38-none-win_amd64.whl", hash = "sha256:c4eb31a8e8a5e1d9af5aa9e247c2a52ad5cf7e968aaa9aaefdff98cfcc7f2e37"}, + {file = "orjson-3.9.9-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:4a308aeac326c2bafbca9abbae1e1fcf682b06e78a54dad0347b760525838d85"}, + {file = "orjson-3.9.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e159b97f5676dcdac0d0f75ec856ef5851707f61d262851eb41a30e8fadad7c9"}, + {file = "orjson-3.9.9-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f692e7aabad92fa0fff5b13a846fb586b02109475652207ec96733a085019d80"}, + {file = "orjson-3.9.9-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cffb77cf0cd3cbf20eb603f932e0dde51b45134bdd2d439c9f57924581bb395b"}, + {file = "orjson-3.9.9-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c63eca397127ebf46b59c9c1fb77b30dd7a8fc808ac385e7a58a7e64bae6e106"}, + {file = "orjson-3.9.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06f0c024a75e8ba5d9101facb4fb5a028cdabe3cdfe081534f2a9de0d5062af2"}, + {file = "orjson-3.9.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8cba20c9815c2a003b8ca4429b0ad4aa87cb6649af41365821249f0fd397148e"}, + {file = "orjson-3.9.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:906cac73b7818c20cf0f6a7dde5a6f009c52aecc318416c7af5ea37f15ca7e66"}, + {file = "orjson-3.9.9-cp39-none-win32.whl", hash = "sha256:50232572dd300c49f134838c8e7e0917f29a91f97dbd608d23f2895248464b7f"}, + {file = "orjson-3.9.9-cp39-none-win_amd64.whl", hash = "sha256:920814e02e3dd7af12f0262bbc18b9fe353f75a0d0c237f6a67d270da1a1bb44"}, + {file = "orjson-3.9.9.tar.gz", hash = "sha256:02e693843c2959befdd82d1ebae8b05ed12d1cb821605d5f9fe9f98ca5c9fd2b"}, +] + +[[package]] +name = "packaging" +version = "23.2" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, +] + +[[package]] +name = "parso" +version = "0.8.3" +description = "A Python Parser" +optional = false +python-versions = ">=3.6" +files = [ + {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, + {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, +] + +[package.extras] +qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] +testing = ["docopt", "pytest (<6.0.0)"] + [[package]] name = "pbr" version = "5.11.1" @@ -226,13 +360,13 @@ files = [ [[package]] name = "pygments" -version = "2.15.1" +version = "2.16.1" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.7" files = [ - {file = "Pygments-2.15.1-py3-none-any.whl", hash = "sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1"}, - {file = "Pygments-2.15.1.tar.gz", hash = "sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c"}, + {file = "Pygments-2.16.1-py3-none-any.whl", hash = "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692"}, + {file = "Pygments-2.16.1.tar.gz", hash = "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29"}, ] [package.extras] @@ -240,102 +374,101 @@ plugins = ["importlib-metadata"] [[package]] name = "pyyaml" -version = "6.0" +version = "6.0.1" description = "YAML parser and emitter for Python" optional = false python-versions = ">=3.6" files = [ - {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, - {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, - {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, - {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, - {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, - {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, - {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, - {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, - {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, - {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, - {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, - {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, - {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, - {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, - {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, - {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, - {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, - {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, - {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, - {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, ] -[[package]] -name = "requests" -version = "2.31.0" -description = "Python HTTP for Humans." -optional = false -python-versions = ">=3.7" -files = [ - {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, - {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, -] - -[package.dependencies] -certifi = ">=2017.4.17" -charset-normalizer = ">=2,<4" -idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<3" - -[package.extras] -socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] - [[package]] name = "rich" -version = "13.3.5" +version = "13.6.0" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false python-versions = ">=3.7.0" files = [ - {file = "rich-13.3.5-py3-none-any.whl", hash = "sha256:69cdf53799e63f38b95b9bf9c875f8c90e78dd62b2f00c13a911c7a3b9fa4704"}, - {file = "rich-13.3.5.tar.gz", hash = "sha256:2d11b9b8dd03868f09b4fffadc84a6a8cda574e40dc90821bd845720ebb8e89c"}, + {file = "rich-13.6.0-py3-none-any.whl", hash = "sha256:2b38e2fe9ca72c9a00170a1a2d20c63c790d0e10ef1fe35eba76e1e7b1d7d245"}, + {file = "rich-13.6.0.tar.gz", hash = "sha256:5c14d22737e6d5084ef4771b62d5d4363165b403455a30a1c8ca39dc7b644bef"}, ] [package.dependencies] -markdown-it-py = ">=2.2.0,<3.0.0" +markdown-it-py = ">=2.2.0" pygments = ">=2.13.0,<3.0.0" -typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.9\""} [package.extras] jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "smmap" -version = "5.0.0" +version = "5.0.1" description = "A pure Python implementation of a sliding window memory map manager" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "smmap-5.0.0-py3-none-any.whl", hash = "sha256:2aba19d6a040e78d8b09de5c57e96207b09ed71d8e55ce0959eeee6c8e190d94"}, - {file = "smmap-5.0.0.tar.gz", hash = "sha256:c840e62059cd3be204b0c9c9f74be2c09d5648eddd4580d9314c3ecde0b30936"}, + {file = "smmap-5.0.1-py3-none-any.whl", hash = "sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da"}, + {file = "smmap-5.0.1.tar.gz", hash = "sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62"}, +] + +[[package]] +name = "sniffio" +version = "1.3.0" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +files = [ + {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, + {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, ] [[package]] @@ -354,49 +487,180 @@ pbr = ">=2.0.0,<2.1.0 || >2.1.0" [[package]] name = "typing-extensions" -version = "4.6.2" -description = "Backported and Experimental Type Hints for Python 3.7+" +version = "4.8.0" +description = "Backported and Experimental Type Hints for Python 3.8+" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.6.2-py3-none-any.whl", hash = "sha256:3a8b36f13dd5fdc5d1b16fe317f5668545de77fa0b8e02006381fd49d731ab98"}, - {file = "typing_extensions-4.6.2.tar.gz", hash = "sha256:06006244c70ac8ee83fa8282cb188f697b8db25bc8b4df07be1873c43897060c"}, + {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"}, + {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, ] [[package]] -name = "urllib3" -version = "2.0.2" -description = "HTTP library with thread-safe connection pooling, file post, and more." +name = "typing-inspect" +version = "0.9.0" +description = "Runtime inspection utilities for typing module." optional = false -python-versions = ">=3.7" +python-versions = "*" files = [ - {file = "urllib3-2.0.2-py3-none-any.whl", hash = "sha256:d055c2f9d38dc53c808f6fdc8eab7360b6fdbbde02340ed25cfbcd817c62469e"}, - {file = "urllib3-2.0.2.tar.gz", hash = "sha256:61717a1095d7e155cdb737ac7bb2f4324a858a1e2e6466f6d03ff630ca68d3cc"}, + {file = "typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f"}, + {file = "typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78"}, ] -[package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] -secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] -socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] -zstd = ["zstandard (>=0.18.0)"] +[package.dependencies] +mypy-extensions = ">=0.3.0" +typing-extensions = ">=3.7.4" [[package]] -name = "websocket-client" -version = "1.5.2" -description = "WebSocket client for Python with low level API options" +name = "ujson" +version = "5.8.0" +description = "Ultra fast JSON encoder and decoder for Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "websocket-client-1.5.2.tar.gz", hash = "sha256:c7d67c13b928645f259d9b847ab5b57fd2d127213ca41ebd880de1f553b7c23b"}, - {file = "websocket_client-1.5.2-py3-none-any.whl", hash = "sha256:f8c64e28cd700e7ba1f04350d66422b6833b82a796b525a51e740b8cc8dab4b1"}, + {file = "ujson-5.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f4511560d75b15ecb367eef561554959b9d49b6ec3b8d5634212f9fed74a6df1"}, + {file = "ujson-5.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9399eaa5d1931a0ead49dce3ffacbea63f3177978588b956036bfe53cdf6af75"}, + {file = "ujson-5.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4e7bb7eba0e1963f8b768f9c458ecb193e5bf6977090182e2b4f4408f35ac76"}, + {file = "ujson-5.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40931d7c08c4ce99adc4b409ddb1bbb01635a950e81239c2382cfe24251b127a"}, + {file = "ujson-5.8.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d53039d39de65360e924b511c7ca1a67b0975c34c015dd468fca492b11caa8f7"}, + {file = "ujson-5.8.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bdf04c6af3852161be9613e458a1fb67327910391de8ffedb8332e60800147a2"}, + {file = "ujson-5.8.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a70f776bda2e5072a086c02792c7863ba5833d565189e09fabbd04c8b4c3abba"}, + {file = "ujson-5.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f26629ac531d712f93192c233a74888bc8b8212558bd7d04c349125f10199fcf"}, + {file = "ujson-5.8.0-cp310-cp310-win32.whl", hash = "sha256:7ecc33b107ae88405aebdb8d82c13d6944be2331ebb04399134c03171509371a"}, + {file = "ujson-5.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:3b27a8da7a080add559a3b73ec9ebd52e82cc4419f7c6fb7266e62439a055ed0"}, + {file = "ujson-5.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:193349a998cd821483a25f5df30b44e8f495423840ee11b3b28df092ddfd0f7f"}, + {file = "ujson-5.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ddeabbc78b2aed531f167d1e70387b151900bc856d61e9325fcdfefb2a51ad8"}, + {file = "ujson-5.8.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ce24909a9c25062e60653073dd6d5e6ec9d6ad7ed6e0069450d5b673c854405"}, + {file = "ujson-5.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27a2a3c7620ebe43641e926a1062bc04e92dbe90d3501687957d71b4bdddaec4"}, + {file = "ujson-5.8.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b852bdf920fe9f84e2a2c210cc45f1b64f763b4f7d01468b33f7791698e455e"}, + {file = "ujson-5.8.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:20768961a6a706170497129960762ded9c89fb1c10db2989c56956b162e2a8a3"}, + {file = "ujson-5.8.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e0147d41e9fb5cd174207c4a2895c5e24813204499fd0839951d4c8784a23bf5"}, + {file = "ujson-5.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e3673053b036fd161ae7a5a33358ccae6793ee89fd499000204676baafd7b3aa"}, + {file = "ujson-5.8.0-cp311-cp311-win32.whl", hash = "sha256:a89cf3cd8bf33a37600431b7024a7ccf499db25f9f0b332947fbc79043aad879"}, + {file = "ujson-5.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:3659deec9ab9eb19e8646932bfe6fe22730757c4addbe9d7d5544e879dc1b721"}, + {file = "ujson-5.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:102bf31c56f59538cccdfec45649780ae00657e86247c07edac434cb14d5388c"}, + {file = "ujson-5.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:299a312c3e85edee1178cb6453645217ba23b4e3186412677fa48e9a7f986de6"}, + {file = "ujson-5.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2e385a7679b9088d7bc43a64811a7713cc7c33d032d020f757c54e7d41931ae"}, + {file = "ujson-5.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad24ec130855d4430a682c7a60ca0bc158f8253ec81feed4073801f6b6cb681b"}, + {file = "ujson-5.8.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:16fde596d5e45bdf0d7de615346a102510ac8c405098e5595625015b0d4b5296"}, + {file = "ujson-5.8.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6d230d870d1ce03df915e694dcfa3f4e8714369cce2346686dbe0bc8e3f135e7"}, + {file = "ujson-5.8.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:9571de0c53db5cbc265945e08f093f093af2c5a11e14772c72d8e37fceeedd08"}, + {file = "ujson-5.8.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:7cba16b26efe774c096a5e822e4f27097b7c81ed6fb5264a2b3f5fd8784bab30"}, + {file = "ujson-5.8.0-cp312-cp312-win32.whl", hash = "sha256:48c7d373ff22366eecfa36a52b9b55b0ee5bd44c2b50e16084aa88b9de038916"}, + {file = "ujson-5.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:5ac97b1e182d81cf395ded620528c59f4177eee024b4b39a50cdd7b720fdeec6"}, + {file = "ujson-5.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2a64cc32bb4a436e5813b83f5aab0889927e5ea1788bf99b930fad853c5625cb"}, + {file = "ujson-5.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e54578fa8838ddc722539a752adfce9372474114f8c127bb316db5392d942f8b"}, + {file = "ujson-5.8.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9721cd112b5e4687cb4ade12a7b8af8b048d4991227ae8066d9c4b3a6642a582"}, + {file = "ujson-5.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d9707e5aacf63fb919f6237d6490c4e0244c7f8d3dc2a0f84d7dec5db7cb54c"}, + {file = "ujson-5.8.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0be81bae295f65a6896b0c9030b55a106fb2dec69ef877253a87bc7c9c5308f7"}, + {file = "ujson-5.8.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ae7f4725c344bf437e9b881019c558416fe84ad9c6b67426416c131ad577df67"}, + {file = "ujson-5.8.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9ab282d67ef3097105552bf151438b551cc4bedb3f24d80fada830f2e132aeb9"}, + {file = "ujson-5.8.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:94c7bd9880fa33fcf7f6d7f4cc032e2371adee3c5dba2922b918987141d1bf07"}, + {file = "ujson-5.8.0-cp38-cp38-win32.whl", hash = "sha256:bf5737dbcfe0fa0ac8fa599eceafae86b376492c8f1e4b84e3adf765f03fb564"}, + {file = "ujson-5.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:11da6bed916f9bfacf13f4fc6a9594abd62b2bb115acfb17a77b0f03bee4cfd5"}, + {file = "ujson-5.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:69b3104a2603bab510497ceabc186ba40fef38ec731c0ccaa662e01ff94a985c"}, + {file = "ujson-5.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9249fdefeb021e00b46025e77feed89cd91ffe9b3a49415239103fc1d5d9c29a"}, + {file = "ujson-5.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2873d196725a8193f56dde527b322c4bc79ed97cd60f1d087826ac3290cf9207"}, + {file = "ujson-5.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a4dafa9010c366589f55afb0fd67084acd8added1a51251008f9ff2c3e44042"}, + {file = "ujson-5.8.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a42baa647a50fa8bed53d4e242be61023bd37b93577f27f90ffe521ac9dc7a3"}, + {file = "ujson-5.8.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f3554eaadffe416c6f543af442066afa6549edbc34fe6a7719818c3e72ebfe95"}, + {file = "ujson-5.8.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:fb87decf38cc82bcdea1d7511e73629e651bdec3a43ab40985167ab8449b769c"}, + {file = "ujson-5.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:407d60eb942c318482bbfb1e66be093308bb11617d41c613e33b4ce5be789adc"}, + {file = "ujson-5.8.0-cp39-cp39-win32.whl", hash = "sha256:0fe1b7edaf560ca6ab023f81cbeaf9946a240876a993b8c5a21a1c539171d903"}, + {file = "ujson-5.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:3f9b63530a5392eb687baff3989d0fb5f45194ae5b1ca8276282fb647f8dcdb3"}, + {file = "ujson-5.8.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:efeddf950fb15a832376c0c01d8d7713479fbeceaed1eaecb2665aa62c305aec"}, + {file = "ujson-5.8.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d8283ac5d03e65f488530c43d6610134309085b71db4f675e9cf5dff96a8282"}, + {file = "ujson-5.8.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb0142f6f10f57598655340a3b2c70ed4646cbe674191da195eb0985a9813b83"}, + {file = "ujson-5.8.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07d459aca895eb17eb463b00441986b021b9312c6c8cc1d06880925c7f51009c"}, + {file = "ujson-5.8.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d524a8c15cfc863705991d70bbec998456a42c405c291d0f84a74ad7f35c5109"}, + {file = "ujson-5.8.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d6f84a7a175c75beecde53a624881ff618e9433045a69fcfb5e154b73cdaa377"}, + {file = "ujson-5.8.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b748797131ac7b29826d1524db1cc366d2722ab7afacc2ce1287cdafccddbf1f"}, + {file = "ujson-5.8.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e72ba76313d48a1a3a42e7dc9d1db32ea93fac782ad8dde6f8b13e35c229130"}, + {file = "ujson-5.8.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f504117a39cb98abba4153bf0b46b4954cc5d62f6351a14660201500ba31fe7f"}, + {file = "ujson-5.8.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a8c91b6f4bf23f274af9002b128d133b735141e867109487d17e344d38b87d94"}, + {file = "ujson-5.8.0.tar.gz", hash = "sha256:78e318def4ade898a461b3d92a79f9441e7e0e4d2ad5419abed4336d702c7425"}, ] -[package.extras] -docs = ["Sphinx (>=3.4)", "sphinx-rtd-theme (>=0.5)"] -optional = ["python-socks", "wsaccel"] -test = ["websockets"] +[[package]] +name = "websockets" +version = "11.0.3" +description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "websockets-11.0.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3ccc8a0c387629aec40f2fc9fdcb4b9d5431954f934da3eaf16cdc94f67dbfac"}, + {file = "websockets-11.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d67ac60a307f760c6e65dad586f556dde58e683fab03323221a4e530ead6f74d"}, + {file = "websockets-11.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84d27a4832cc1a0ee07cdcf2b0629a8a72db73f4cf6de6f0904f6661227f256f"}, + {file = "websockets-11.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffd7dcaf744f25f82190856bc26ed81721508fc5cbf2a330751e135ff1283564"}, + {file = "websockets-11.0.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7622a89d696fc87af8e8d280d9b421db5133ef5b29d3f7a1ce9f1a7bf7fcfa11"}, + {file = "websockets-11.0.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bceab846bac555aff6427d060f2fcfff71042dba6f5fca7dc4f75cac815e57ca"}, + {file = "websockets-11.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:54c6e5b3d3a8936a4ab6870d46bdd6ec500ad62bde9e44462c32d18f1e9a8e54"}, + {file = "websockets-11.0.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:41f696ba95cd92dc047e46b41b26dd24518384749ed0d99bea0a941ca87404c4"}, + {file = "websockets-11.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:86d2a77fd490ae3ff6fae1c6ceaecad063d3cc2320b44377efdde79880e11526"}, + {file = "websockets-11.0.3-cp310-cp310-win32.whl", hash = "sha256:2d903ad4419f5b472de90cd2d40384573b25da71e33519a67797de17ef849b69"}, + {file = "websockets-11.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:1d2256283fa4b7f4c7d7d3e84dc2ece74d341bce57d5b9bf385df109c2a1a82f"}, + {file = "websockets-11.0.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e848f46a58b9fcf3d06061d17be388caf70ea5b8cc3466251963c8345e13f7eb"}, + {file = "websockets-11.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aa5003845cdd21ac0dc6c9bf661c5beddd01116f6eb9eb3c8e272353d45b3288"}, + {file = "websockets-11.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b58cbf0697721120866820b89f93659abc31c1e876bf20d0b3d03cef14faf84d"}, + {file = "websockets-11.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:660e2d9068d2bedc0912af508f30bbeb505bbbf9774d98def45f68278cea20d3"}, + {file = "websockets-11.0.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c1f0524f203e3bd35149f12157438f406eff2e4fb30f71221c8a5eceb3617b6b"}, + {file = "websockets-11.0.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:def07915168ac8f7853812cc593c71185a16216e9e4fa886358a17ed0fd9fcf6"}, + {file = "websockets-11.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b30c6590146e53149f04e85a6e4fcae068df4289e31e4aee1fdf56a0dead8f97"}, + {file = "websockets-11.0.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:619d9f06372b3a42bc29d0cd0354c9bb9fb39c2cbc1a9c5025b4538738dbffaf"}, + {file = "websockets-11.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:01f5567d9cf6f502d655151645d4e8b72b453413d3819d2b6f1185abc23e82dd"}, + {file = "websockets-11.0.3-cp311-cp311-win32.whl", hash = "sha256:e1459677e5d12be8bbc7584c35b992eea142911a6236a3278b9b5ce3326f282c"}, + {file = "websockets-11.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:e7837cb169eca3b3ae94cc5787c4fed99eef74c0ab9506756eea335e0d6f3ed8"}, + {file = "websockets-11.0.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9f59a3c656fef341a99e3d63189852be7084c0e54b75734cde571182c087b152"}, + {file = "websockets-11.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2529338a6ff0eb0b50c7be33dc3d0e456381157a31eefc561771ee431134a97f"}, + {file = "websockets-11.0.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:34fd59a4ac42dff6d4681d8843217137f6bc85ed29722f2f7222bd619d15e95b"}, + {file = "websockets-11.0.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:332d126167ddddec94597c2365537baf9ff62dfcc9db4266f263d455f2f031cb"}, + {file = "websockets-11.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6505c1b31274723ccaf5f515c1824a4ad2f0d191cec942666b3d0f3aa4cb4007"}, + {file = "websockets-11.0.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f467ba0050b7de85016b43f5a22b46383ef004c4f672148a8abf32bc999a87f0"}, + {file = "websockets-11.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:9d9acd80072abcc98bd2c86c3c9cd4ac2347b5a5a0cae7ed5c0ee5675f86d9af"}, + {file = "websockets-11.0.3-cp37-cp37m-win32.whl", hash = "sha256:e590228200fcfc7e9109509e4d9125eace2042fd52b595dd22bbc34bb282307f"}, + {file = "websockets-11.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:b16fff62b45eccb9c7abb18e60e7e446998093cdcb50fed33134b9b6878836de"}, + {file = "websockets-11.0.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fb06eea71a00a7af0ae6aefbb932fb8a7df3cb390cc217d51a9ad7343de1b8d0"}, + {file = "websockets-11.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8a34e13a62a59c871064dfd8ffb150867e54291e46d4a7cf11d02c94a5275bae"}, + {file = "websockets-11.0.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4841ed00f1026dfbced6fca7d963c4e7043aa832648671b5138008dc5a8f6d99"}, + {file = "websockets-11.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a073fc9ab1c8aff37c99f11f1641e16da517770e31a37265d2755282a5d28aa"}, + {file = "websockets-11.0.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:68b977f21ce443d6d378dbd5ca38621755f2063d6fdb3335bda981d552cfff86"}, + {file = "websockets-11.0.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1a99a7a71631f0efe727c10edfba09ea6bee4166a6f9c19aafb6c0b5917d09c"}, + {file = "websockets-11.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:bee9fcb41db2a23bed96c6b6ead6489702c12334ea20a297aa095ce6d31370d0"}, + {file = "websockets-11.0.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4b253869ea05a5a073ebfdcb5cb3b0266a57c3764cf6fe114e4cd90f4bfa5f5e"}, + {file = "websockets-11.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:1553cb82942b2a74dd9b15a018dce645d4e68674de2ca31ff13ebc2d9f283788"}, + {file = "websockets-11.0.3-cp38-cp38-win32.whl", hash = "sha256:f61bdb1df43dc9c131791fbc2355535f9024b9a04398d3bd0684fc16ab07df74"}, + {file = "websockets-11.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:03aae4edc0b1c68498f41a6772d80ac7c1e33c06c6ffa2ac1c27a07653e79d6f"}, + {file = "websockets-11.0.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:777354ee16f02f643a4c7f2b3eff8027a33c9861edc691a2003531f5da4f6bc8"}, + {file = "websockets-11.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8c82f11964f010053e13daafdc7154ce7385ecc538989a354ccc7067fd7028fd"}, + {file = "websockets-11.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3580dd9c1ad0701169e4d6fc41e878ffe05e6bdcaf3c412f9d559389d0c9e016"}, + {file = "websockets-11.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f1a3f10f836fab6ca6efa97bb952300b20ae56b409414ca85bff2ad241d2a61"}, + {file = "websockets-11.0.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df41b9bc27c2c25b486bae7cf42fccdc52ff181c8c387bfd026624a491c2671b"}, + {file = "websockets-11.0.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:279e5de4671e79a9ac877427f4ac4ce93751b8823f276b681d04b2156713b9dd"}, + {file = "websockets-11.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1fdf26fa8a6a592f8f9235285b8affa72748dc12e964a5518c6c5e8f916716f7"}, + {file = "websockets-11.0.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:69269f3a0b472e91125b503d3c0b3566bda26da0a3261c49f0027eb6075086d1"}, + {file = "websockets-11.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:97b52894d948d2f6ea480171a27122d77af14ced35f62e5c892ca2fae9344311"}, + {file = "websockets-11.0.3-cp39-cp39-win32.whl", hash = "sha256:c7f3cb904cce8e1be667c7e6fef4516b98d1a6a0635a58a57528d577ac18a128"}, + {file = "websockets-11.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:c792ea4eabc0159535608fc5658a74d1a81020eb35195dd63214dcf07556f67e"}, + {file = "websockets-11.0.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f2e58f2c36cc52d41f2659e4c0cbf7353e28c8c9e63e30d8c6d3494dc9fdedcf"}, + {file = "websockets-11.0.3-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de36fe9c02995c7e6ae6efe2e205816f5f00c22fd1fbf343d4d18c3d5ceac2f5"}, + {file = "websockets-11.0.3-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0ac56b661e60edd453585f4bd68eb6a29ae25b5184fd5ba51e97652580458998"}, + {file = "websockets-11.0.3-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e052b8467dd07d4943936009f46ae5ce7b908ddcac3fda581656b1b19c083d9b"}, + {file = "websockets-11.0.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:42cc5452a54a8e46a032521d7365da775823e21bfba2895fb7b77633cce031bb"}, + {file = "websockets-11.0.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e6316827e3e79b7b8e7d8e3b08f4e331af91a48e794d5d8b099928b6f0b85f20"}, + {file = "websockets-11.0.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8531fdcad636d82c517b26a448dcfe62f720e1922b33c81ce695d0edb91eb931"}, + {file = "websockets-11.0.3-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c114e8da9b475739dde229fd3bc6b05a6537a88a578358bc8eb29b4030fac9c9"}, + {file = "websockets-11.0.3-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e063b1865974611313a3849d43f2c3f5368093691349cf3c7c8f8f75ad7cb280"}, + {file = "websockets-11.0.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:92b2065d642bf8c0a82d59e59053dd2fdde64d4ed44efe4870fa816c1232647b"}, + {file = "websockets-11.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0ee68fe502f9031f19d495dae2c268830df2760c0524cbac5d759921ba8c8e82"}, + {file = "websockets-11.0.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcacf2c7a6c3a84e720d1bb2b543c675bf6c40e460300b628bab1b1efc7c034c"}, + {file = "websockets-11.0.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b67c6f5e5a401fc56394f191f00f9b3811fe843ee93f4a70df3c389d1adf857d"}, + {file = "websockets-11.0.3-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d5023a4b6a5b183dc838808087033ec5df77580485fc533e7dab2567851b0a4"}, + {file = "websockets-11.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ed058398f55163a79bb9f06a90ef9ccc063b204bb346c4de78efc5d15abfe602"}, + {file = "websockets-11.0.3-py3-none-any.whl", hash = "sha256:6681ba9e7f8f3b19440921e99efbb40fc89f26cd71bf539e45d8c8a25c976dc6"}, + {file = "websockets-11.0.3.tar.gz", hash = "sha256:88fc51d9a26b10fc331be344f1781224a375b78488fc343620184e95a4b27016"}, +] [metadata] lock-version = "2.0" -python-versions = "^3.8" -content-hash = "ca2f8fcd8eae8b8c7c027d852f4c90c593d892f955660dd939809ea655623a79" +python-versions = "^3.12" +content-hash = "2002318232c4db3df4795a3cafd9a0ccee6e56418ccef31f69aeaece0bc6bca3" diff --git a/pyproject.toml b/pyproject.toml index 39f6630..cd665ed 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "MeowerBot" -version = "2.6.3" +version = "3.0" description = "A meower bot lib for py" authors = ["showierdata9978 <68120127+showierdata9978@users.noreply.github.com>"] license = "MIT" @@ -12,10 +12,14 @@ repository = "https://github.com/MeowerBots/MeowerBot.py" [tool.poetry.dependencies] -python = "^3.8" -requests = "^2.28.0" -websocket-client = "*" -backports-strenum = { version = "^1.2.4", python = "<3.11" } +python = "^3.12" +websockets = "^11.0.3" +orjson = "^3.9.4" +httpx = "^0.25.0" +dataclasses-json = "^0.6.1" +typing-extensions = "^4.8.0" +ujson = "^5.8.0" + [tool.poetry.group.extras.dependencies] @@ -23,6 +27,7 @@ backports-strenum = { version = "^1.2.4", python = "<3.11" } [tool.poetry.group.dev.dependencies] bandit = "^1.7.5" +jedi = "^0.19.1" [build-system] requires = ["poetry-core>=1.0.0"] diff --git a/tests/integration_login.py b/tests/integration_login.py new file mode 100644 index 0000000..33ab489 --- /dev/null +++ b/tests/integration_login.py @@ -0,0 +1,26 @@ +from MeowerBot import Bot +from MeowerBot.context import Context, Post +from MeowerBot.API import MeowerAPI +import asyncio +import logging +from os import environ as env + +logging.basicConfig(level=logging.DEBUG) +logging.getLogger("websockets.client").setLevel(level=logging.INFO) + +bot = Bot() + +@bot.event +async def login(t): + print("Logged in!") + +@bot.command(name="ping") +async def ping(ctx: Context): + await ctx.send_msg("Pong!\n My latency is: " + str(bot.latency)) + + + +MeowerAPI.base_uri = "https://beta.meower.org/api/" + +bot.run(env["uname"], env["pswd"], server="wss://beta.meower.org/api/v0/cloudlink") + diff --git a/tests/intergration/API.py b/tests/intergration/API.py deleted file mode 100644 index 127dbcf..0000000 --- a/tests/intergration/API.py +++ /dev/null @@ -1,20 +0,0 @@ -# type: ignore # disable linter - -from MeowerBot import Bot, __version__ -from MeowerBot.API import MeowerAPI - -from os import environ as env - -from logging import basicConfig, DEBUG - -basicConfig(level=DEBUG) - -bot = Bot() -bot.api = None -def direct(val, listener, bot=bot): - if listener == "__meowerbot__login": - bot.send_msg("Meower Stats: " + str(bot.api.statistics())) - -bot.callback(direct, cbid="direct") - -bot.run(env['uname'], env['password']) diff --git a/tests/intergration/cogs.py b/tests/intergration/cogs.py deleted file mode 100644 index 13df6a1..0000000 --- a/tests/intergration/cogs.py +++ /dev/null @@ -1,31 +0,0 @@ - -from MeowerBot import Bot, __version__ -from MeowerBot.cog import Cog -from MeowerBot.command import command -from os import environ as env - -from logging import basicConfig, DEBUG - -basicConfig(level=DEBUG) -class MyBotCog(Cog): - def __init__(self, bot): - super().__init__() - self.bot = bot - - @command() - def test2(self, ctx, *args): - if not hasattr(self, "bot"): - ctx.reply("No bot in cog") - - ctx.send_msg(" ".join(args)) - -bot = Bot(prefix="/") -cog = MyBotCog(bot) -bot.register_cog(cog) - -@bot.command() -def test(ctx, *args): - ctx.send_msg(" ".join(args) + "\n mb.py " + __version__) - -bot.run(env['username'], env['password']) - diff --git a/tests/intergration/command.py b/tests/intergration/command.py deleted file mode 100644 index e67de42..0000000 --- a/tests/intergration/command.py +++ /dev/null @@ -1,30 +0,0 @@ - -from MeowerBot import Bot, __version__ -from MeowerBot.command import AppCommand -from os import environ as env -from logging import basicConfig, DEBUG - -basicConfig(level=DEBUG) - -bot: Bot = Bot(prefix="/", autoreload=1) - -test: AppCommand - -@bot.command() -def test(ctx, *args): - ctx.send_msg(" ".join(args) + "\n mb.py " + __version__) - -@test.subcommand() -def sub(ctx, *args): - ctx.send_msg(" ".join(args)) - - -@bot.command(args=0) -def reloadtime(ctx): - "__doc__ test" - ctx.send_msg(f"My reload time is {round(bot.autoreload_time)}" ) - - - -bot.run(env['uname'], env['password']) - diff --git a/tests/intergration/join_chat.py b/tests/intergration/join_chat.py deleted file mode 100644 index b635d76..0000000 --- a/tests/intergration/join_chat.py +++ /dev/null @@ -1,19 +0,0 @@ -from MeowerBot import Bot, __version__ -from os import environ as env -bot = Bot(prefix="/") -import time -from logging import basicConfig, DEBUG - -basicConfig(level=DEBUG) - -exited = False - -def login_callback(bot=bot): - print("Logged in") - - bot.enter_chat("livechat") - - -bot.callback(login_callback, cbid="login") - -bot.run(env['username'], env['password']) \ No newline at end of file diff --git a/tests/intergration/login.py b/tests/intergration/login.py deleted file mode 100644 index 82b2c6f..0000000 --- a/tests/intergration/login.py +++ /dev/null @@ -1,28 +0,0 @@ - - -from MeowerBot import Bot, __version__ -from os import environ as env -from logging import basicConfig, DEBUG - - -basicConfig(level=DEBUG) - -bot = Bot() - -def login(*_, **__): - print("login CB") - bot.send_msg("TESTING!!!!!!!! O_O", to='home') - bot.send_msg("MeowerBot.py " + __version__, to='home') - - -def msg(msg, *args, **_): - print("msg CB") - if msg.user.username == "Discord": - bot.send_msg("TEEEEEST", to="livechat") - -bot.callback(login, cbid="login") -bot.callback(msg, cbid="message") - -bot.run(env['username'], env['password']) - - diff --git a/tests/intergration/test_help.py b/tests/intergration/test_help.py deleted file mode 100644 index 6bead93..0000000 --- a/tests/intergration/test_help.py +++ /dev/null @@ -1,34 +0,0 @@ - -from MeowerBot import Bot, __version__ -from MeowerBot.command import AppCommand -from MeowerBot.ext.help import Help - -from os import environ as env -from logging import basicConfig, DEBUG - -basicConfig(level=DEBUG) - -bot: Bot = Bot(autoreload=1) - -test: AppCommand - -@bot.command() -def test(ctx, *args): - ctx.send_msg(" ".join(args) + "\n mb.py " + __version__) - -@test.subcommand() -def sub(ctx, *args): - ctx.send_msg(" ".join(args)) - - -@bot.command(args=0) -def reloadtime(ctx): - "__doc__ test" - ctx.send_msg(f"My reload time is {round(bot.autoreload_time)}" ) - -help = Help(bot) - - -bot.register_cog(help) -bot.run(env['uname'], env['password']) - diff --git a/tests/intergration/type_forever.py b/tests/intergration/type_forever.py deleted file mode 100644 index 8231a9b..0000000 --- a/tests/intergration/type_forever.py +++ /dev/null @@ -1,31 +0,0 @@ -from MeowerBot import Bot, __version__ -from os import environ as env -bot = Bot(prefix="/") -import time -from logging import basicConfig, DEBUG - -basicConfig(level=DEBUG) - -exited = False - -def login_callback(bot=bot): - print("Logged in") - - while True: - - bot.send_typing() - - time.sleep(1) - - if exited: - break - -def exit_callback(bot=bot): - global exited - exited = True - - -bot.callback(login_callback, cbid="login") -bot.callback(exit_callback, cbid="close") - -bot.run(env['username'], env['password']) \ No newline at end of file diff --git a/tests/test_api.py b/tests/test_api.py deleted file mode 100644 index ea4c4ff..0000000 --- a/tests/test_api.py +++ /dev/null @@ -1,89 +0,0 @@ -#lint:disable - -import unittest -from unittest.mock import MagicMock, patch -from MeowerBot.API import MeowerAPI - -class TestMeowerAPI(unittest.TestCase): - def setUp(self): - self.api = MeowerAPI("testuser") - self.mock_session = MagicMock() - self.api.session = self.mock_session - self.api.session.headers = {} - - def test_login(self): - # Test that the login method sets the token header - self.api.login("testtoken") - - self.assertIn("token", self.mock_session.headers) - self.assertEqual(self.mock_session.headers["token"], "testtoken") - - def test_get_page_home(self): - # Test that the get_page method returns the correct response for home page - self.mock_session.get.return_value.json.return_value = {"page": 1} - - response = self.api.get_page() - - self.mock_session.get.assert_called_with( - "https://api.meower.org/home?autoget&page=1" - ) - self.assertEqual(response, {"page": 1}) - - def test_get_page_chat(self): - # Test that the get_page method returns the correct response for chat page - self.mock_session.get.return_value.json.return_value = {"page": 1} - - response = self.api.get_page(chatid="testchat") - - self.mock_session.get.assert_called_with( - "https://api.meower.org/posts/testchat?autoget&page=1" - ) - self.assertEqual(response, {"page": 1}) - - def test_get_user(self): - # Test that the get_user method returns the correct response - self.mock_session.get.return_value.json.return_value = {"username": "testuser"} - - response = self.api.get_user("testuser") - - self.mock_session.get.assert_called_with( - "https://api.meower.org/users/testuser" - ) - self.assertEqual(response, {"username": "testuser"}) - - def test_get_user_posts(self): - # Test that the get_user_posts method returns the correct response - self.mock_session.get.return_value.json.return_value = {"page": 1} - - response = self.api.get_user_posts("testuser") - - self.mock_session.get.assert_called_with( - "https://api.meower.org/users/testuser/posts?autoget&page=1" - ) - self.assertEqual(response, {"page": 1}) - - def test_statistics(self): - # Test that the statistics method returns the correct response - self.mock_session.get.return_value.json.return_value = {"users": 10} - - response = self.api.statistics() - - self.mock_session.get.assert_called_with( - "https://api.meower.org/statistics" - ) - self.assertEqual(response, {"users": 10}) - - def test_status(self): - # Test that the status method returns the correct response - self.mock_session.get.return_value.json.return_value = {"status": "ok"} - - response = self.api.status() - - self.mock_session.get.assert_called_with( - "https://api.meower.org/status" - ) - self.assertEqual(response, {"status": "ok"}) - - -if __name__ == "__main__": - unittest.main() \ No newline at end of file diff --git a/tests/test_bot.py b/tests/test_bot.py deleted file mode 100644 index b4c40f1..0000000 --- a/tests/test_bot.py +++ /dev/null @@ -1,287 +0,0 @@ -# nosec -import unittest -from unittest.mock import MagicMock - -from MeowerBot import Bot, botm - -from io import StringIO -from unittest.mock import patch - -#Import the bot module here - - -class TestBot(unittest.TestCase): - def setUp(self): - self.bot = Bot() - self.bot.username = "testuser" - self.bot._password = "testpassword" # nosec - self.bot.wss = MagicMock() - - def test_handle_packet_statuscode(self): - packet = {"cmd": "statuscode", "val": 200, "listener": None} - - run_cb = self.bot.run_cb - self.bot.run_cb = MagicMock() - - try: - result = self.bot.__handle_packet__(packet) - - self.bot.run_cb.assert_called_with("statuscode", args=(200, None)) - except: - raise - finally: - self.bot.run_cb = run_cb - - - def test_handle_packet_ulist(self): - packet = {"cmd": "ulist", "val":"a;b;c;d"} - runcb = self.bot.run_cb - self.bot.run_cb = MagicMock() - - try: - result = self.bot.__handle_packet__(packet) - self.bot.run_cb.assert_called_with("ulist", self.bot.wss.statedata["ulist"]["usernames"]) - except: - raise - finally: - self.bot.run_cb = runcb - - - - - - def test_handle_packet_direct_with_message_callback(self): - packet = {"cmd": "direct", "val": {"u":"aa", "p":"aa", "origin":"a","post_origin":"a"}} - - self.bot.run_command = MagicMock() - - - - #edit bots imports - - botm.CTX = MagicMock() - botm.CTX.return_value = botm.CTX - botm.CTX.message = MagicMock() - - run_cb = self.bot.run_cb - self.bot.run_cb = MagicMock() - self.bot.prefix = "!" - - try: - result = self.bot.__handle_packet__(packet) - - self.bot.run_cb.assert_called_with("raw_message", args=(packet["val"], )) - - except: - raise - finally: - self.bot.run_cb = run_cb - - def test_handle_packet_direct_without_message_callback(self): - packet = {"cmd": "direct", "val": {"p": "!help", "u": "A", "origin": "123", "post_origin": "123"}} - self.bot.callbacks = {} - self.bot.run_command = MagicMock() - self.bot.prefix = "!" - - #edit bots imports - - botm.CTX = MagicMock() - botm.CTX.return_value = botm.CTX - - result = self.bot.__handle_packet__(packet) - - - botm.CTX.assert_called_with(packet["val"], self.bot) - - assert self.bot.run_command.called # nosec - assert self.bot.run_command.call_args[0][0] == botm.CTX.message # nosec - - - - def test_handle_packet_direct_with_prefix(self): - packet = {"cmd": "direct", "val": {"p": ".help","u":"A", "origin": "123", "post_origin": "123"}} - self.bot.callbacks = {} - - - self.bot.run_command = MagicMock() - self.bot.prefix = "!" - - result = self.bot.__handle_packet__(packet) - - self.assertTrue(self.bot.run_command.called) - - def test_handle_packet_other_command(self): - packet = {"cmd": "other", "val": "value", "listener": None} - self.bot.run_cb = MagicMock() - - result = self.bot.__handle_packet__(packet) - - self.bot.run_cb.assert_called_with("other", args=("value", None)) - - def test_handle_packet_pmsg(self): - packet = {"cmd": "pmsg", "val": "Hello, world!", "origin": "123" } - self.bot.BOT_NO_PMSG_RESPONSE = [""] - self.bot.wss.sendPacket = MagicMock() - self.bot.prefix = "!" - result = self.bot.__handle_packet__(packet) - - self.bot.wss.sendPacket.assert_called_with({"cmd": "pmsg", "val": "I:500 | Bot", "id": "123"}) - botm.requests = MagicMock() - - - - def test_handle_bridges_with_bridge(self): - packet = {"val": {"u": "user", "p": "user: message", "origin": "123", "post_origin": "123"}} - self.bot.__bridges__ = ["user"] - - self.bot.prefix = "!" - result = self.bot.handle_bridges(packet) - - self.assertEqual(result["val"]["u"], "user") - self.assertEqual(result["val"]["p"], "message") - - def test_handle_bridges_without_bridge(self): - packet = {"val": {"u": "user", "p": "message"}} - self.bot.__bridges__ = ["False"] - - self.bot.prefix = "!" - result = self.bot.handle_bridges(packet) - - self.assertEqual(result["val"]["u"], "user") - self.assertEqual(result["val"]["p"], "message") - - def test_handle_bridges_with_prefix(self): - packet = {"val": {"u": "user", "p": "!#0000command"}} - self.bot.__bridges__ = ["False"] - - self.bot.prefix = "!" - - result = self.bot.handle_bridges(packet) - - self.assertEqual(result["val"]["u"], "user") - self.assertEqual(result["val"]["p"], "!command") - - - def test_handle_status_trusted_access_enabled(self): - status = "I:112 | Trusted Access enabled" - listener = None - - result = self.bot._handle_status(status, listener) - - self.assertIsNone(result) - - def test_handle_status_logger_in(self): - status = "I:100 | OK" - listener = None - self.bot.logger_in = True - self.bot.wss.sendPacket = MagicMock() - - result = self.bot._handle_status(status, listener) - - self.bot.wss.sendPacket.assert_called_with( - { - "cmd": "direct", - "val": { - "cmd": "authpswd", - "val": {"username": self.bot.username, "pswd": self.bot._password}, - }, - "listener": "__meowerbot__login", - } - ) - self.assertFalse(self.bot.logger_in) - - def test_handle_status_login_success(self): - status = "I:100 | OK" - listener = "__meowerbot__login" - self.bot.run_cb = MagicMock() - - result = self.bot._handle_status(status, listener) - - self.bot.run_cb.assert_called_with("login", args=(), kwargs={}) - - def test_handle_status_login_failure(self): - status = "E:104 | Internal" - listener = "__meowerbot__login" - - - - - with patch("builtins.print", MagicMock()): - self.bot._handle_status(status, listener) - - assert self.bot.bad_exit # nosec - - def test_handle_status_send_message_success(self): - status = "I:100 | OK" - listener = "__meowerbot__send_message" - self.bot.autoreload_time = 10 - - result = self.bot._handle_status(status, listener) - - self.assertEqual(self.bot.autoreload_time, self.bot.autoreload_original) - - def test_handle_status_send_message_failure(self): - status = "E:100 | Internal" - listener = "__meowerbot__send_message" - - with self.assertRaises(RuntimeError): - self.bot._handle_status(status, listener) - -import unittest -from unittest.mock import MagicMock -from MeowerBot import Bot - -class TestBotRun(unittest.TestCase): - def setUp(self): - self.bot = Bot() - self.bot._t_ping_thread = MagicMock() - self.bot.logger = MagicMock() - self.bot.api = MagicMock() - self.bot.wss = MagicMock() - - def test_run_sets_username_and_password(self): - self.bot.run("testuser", "testpassword") - - self.assertEqual(self.bot.username, "testuser") - self.assertEqual(self.bot._password, "testpassword") - - def test_run_starts_ping_thread(self): - self.bot.run("testuser", "testpassword") - - self.bot._t_ping_thread.start.assert_called_once() - - def test_run_sets_prefix_if_none(self): - self.bot.run("testuser", "testpassword") - - self.assertEqual(self.bot.prefix, "@testuser") - - def test_run_sets_logger_in_to_true(self): - self.bot.run("testuser", "testpassword") - - self.assertTrue(self.bot.logger_in) - - def test_run_sets_logger_name(self): - self.bot.run("testuser", "testpassword") - - self.assertEqual(self.bot.logger.name, "MeowerBot testuser") - - def test_run_sets_server(self): - self.bot.run("testuser", "testpassword", server="wss://testserver.com") - - self.assertEqual(self.bot.server, "wss://testserver.com") - - def test_run_calls_wss_client_with_server(self): - self.bot.run("testuser", "testpassword", server="wss://testserver.com") - - self.bot.wss.client.assert_called_once_with("wss://testserver.com") - - def test_run_raises_exception_if_bad_exit(self): - self.bot.bad_exit = True - - with self.assertRaises(BaseException): - with patch("print", MagicMock()): - self.bot.run("testuser", "testpassword") - - -if __name__ == '__main__': - unittest.main() \ No newline at end of file diff --git a/tests/test_cog.py b/tests/test_cog.py deleted file mode 100644 index 7e784fa..0000000 --- a/tests/test_cog.py +++ /dev/null @@ -1,39 +0,0 @@ -import unittest -from unittest.mock import MagicMock -from MeowerBot.cog import Cog -from MeowerBot.command import command, AppCommand - -class CogTestingCog(Cog): - @command("command1") - def command1(self): - pass - - @command("command2") - def command2(self): - pass - -class TestCog(unittest.TestCase): - def setUp(self): - self.cog = CogTestingCog() - - def test_commands(self): - # Test that all commands are registered - self.assertEqual(len(self.cog.__commands__), 2) - - - - - # Test that the commands are registered correctly - self.assertIn("command1", self.cog.__commands__) - self.assertIn("command2", self.cog.__commands__) - - def test_get_info(self): - # Test that the get_info method returns the correct commands - info = self.cog.get_info() - - self.assertIn("command1", info) - self.assertIn("command2", info) - - -if __name__ == "__main__": - unittest.main() \ No newline at end of file diff --git a/tests/test_command.py b/tests/test_command.py deleted file mode 100644 index 00466a0..0000000 --- a/tests/test_command.py +++ /dev/null @@ -1,43 +0,0 @@ -import unittest -from unittest.mock import MagicMock -from MeowerBot.command import AppCommand - -class TestAppCommand(unittest.TestCase): - def setUp(self): - self.mock_connected = MagicMock() - self.command = AppCommand(lambda ctx,a,b: None, name="testcmd", args=2) - - def test_call(self): - # Test that calling an AppCommand raises a RuntimeError - cmd = AppCommand(lambda: None) - with self.assertRaises(RuntimeError): - cmd() - - def test_register_class(self): - # Test that registering a class sets the connected attribute - cmd = AppCommand(lambda: None) - cmd.register_class(self.mock_connected) - self.assertEqual(cmd.connected, self.mock_connected) - - def test_subcommand(self): - # Test that adding a subcommand updates the subcommands dictionary - - self.command.subcommand(name="subcmd")(lambda: None) - - self.assertIn("subcmd", self.command.subcommands) - self.assertEqual(len(self.command.subcommands), 1) - - def test_run_cmd(self): - # Test that running a command calls the correct function with the correct arguments - mock_func = MagicMock() - mock_func.__annotations__ = {} - mock_func.__name__ = "mock_func" - cmd = AppCommand(mock_func, args=2) - - cmd.run_cmd(None, "arg1", "arg2") - mock_func.assert_called_with(None, "arg1", "arg2") - - - -if __name__ == "__main__": - unittest.main() \ No newline at end of file