diff --git a/.dockerignore b/.dockerignore index 6f0d030..9b388cb 100644 --- a/.dockerignore +++ b/.dockerignore @@ -8,6 +8,8 @@ !/jarvis_small.png !/run.py !/config.yaml +# Needed for jarvis-compose +!/.git # Block other files **/__pycache__ diff --git a/README.md b/README.md index 991e41d..4781a7c 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ JARVIS # Just Another Rather Very Intelligent System -
+
[![python 3.10+](https://img.shields.io/badge/python-3.10+-blue)]() [![tokei lines of code](http://135.148.148.80:8000/b1/gitlab/zevaryx/jarvis-bot?category=code)](https://git.zevaryx.com/stark-industries/jarvis/jarvis-bot) @@ -12,28 +12,22 @@ [![ko-fi](https://www.ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/zevaryx) - -Welcome to the JARVIS Initiative! While the main goal is to create the best discord bot there can be, a great achievement would be to present him to the Robots and have him integrated into the dbrand server. Feel free to suggest anything you may think to be useful… or cool. - -**Note:** Some commands have been custom made to be used in the dbrand server. +Welcome to the JARVIS Initiative, an open-source multi-purpose bot ## Features + JARVIS currently offers: -- 👩‍💼 **Administration**: `verify`, `ban/unban`, `kick`, `purge`, `mute/unmute` and more! -- 🚓 **Moderation**: `lock/unlock`, `lockdown`, `warn`, `autoreact`, and also more! -- 🔗 **Social Media**: `reddit` and `twitter` syncing! -- 🔧 **Utilities**: `remindme`, `rolegiver`, `temprole`, `image`, and so many more! -- 🏷️ **Tags**: Custom `tag`s! Useful for custom messages without the hassle! -- 👑 **dbrand**: `ctc2` and other dbrand-specific commands. [Join their server](https://discord.gg/dbrand) to see them in action! - +- 👩‍💼 **Administration**: `verify`, `ban/unban`, `kick`, `purge`, `mute/unmute` and more! +- 🚓 **Moderation**: `lock/unlock`, `lockdown`, `warn`, `autoreact`, and also more! +- 🔧 **Utilities**: `remindme`, `rolegiver`, `temprole`, `image`, and so many more! +- 🏷️ **Tags**: Custom `tag`s! Useful for custom messages without the hassle! ## Contributing Before **creating an issue**, please ensure that it hasn't already been reported/suggested. If you have a question, please join the community Discord before opening an issue. - If you wish to contribute to the JARVIS codebase or documentation, join the Discord! The recognized developers there will help you get started. ## Community @@ -41,12 +35,12 @@ If you wish to contribute to the JARVIS codebase or documentation, join the Disc Join the [Stark R&D Department Discord server](https://discord.gg/VtgZntXcnZ) to be kept up-to-date on code updates and issues. ## Requirements -- MongoDB 5.0 or higher + +- MongoDB 6.0 or higher - Python 3.10 or higher - [tokei](https://github.com/XAMPPRocky/tokei) 12.1 or higher - Everything in `requirements.txt` - ## JARVIS Cogs Current cogs that are implemented: @@ -57,10 +51,6 @@ Current cogs that are implemented: - Handles autoreaction configuration - `BotutilCog` - Handles internal bot utilities (private use only) -- `CTC2Cog` - - dbrand Complete the Code utilities -- `DbrandCog` - - dbrand-specific functions and utilities - `DevCog` - Developer utilities, such as hashing, encoding, and UUID generation - `GitlabCog` @@ -88,7 +78,6 @@ Current cogs that are implemented: - `VerifyCog` - Guild verification - ## Directories ### `jarvis` @@ -102,6 +91,7 @@ All of the cogs listed above are stored in this directory ##### `jarvis.cogs.admin` Contains all AdminCogs, including: + - `BanCog` - `KickCog` - `LockCog` diff --git a/jarvis/__init__.py b/jarvis/__init__.py index af2c56c..ab02bd9 100644 --- a/jarvis/__init__.py +++ b/jarvis/__init__.py @@ -61,18 +61,31 @@ async def run() -> None: config = load_config() logger = get_logger("jarvis", show_locals=False) # jconfig.log_level == "DEBUG") logger.setLevel(config.log_level) - file_handler = logging.FileHandler(filename="jarvis.log", encoding="UTF-8", mode="w") - file_handler.setFormatter(logging.Formatter("[%(asctime)s] [%(name)s] [%(levelname)8s] %(message)s")) + file_handler = logging.FileHandler( + filename="jarvis.log", encoding="UTF-8", mode="w" + ) + file_handler.setFormatter( + logging.Formatter("[%(asctime)s] [%(name)s] [%(levelname)8s] %(message)s") + ) logger.addHandler(file_handler) # Configure client - intents = Intents.DEFAULT | Intents.MESSAGES | Intents.GUILD_MEMBERS | Intents.GUILD_MESSAGES + intents = ( + Intents.DEFAULT + | Intents.MESSAGES + | Intents.GUILD_MEMBERS + | Intents.GUILD_MESSAGES + ) redis_config = config.redis.dict() redis_host = redis_config.pop("host") redis = await aioredis.from_url(redis_host, decode_responses=True, **redis_config) - await connect(**config.mongo.dict(), testing=config.environment.value == "develop", extra_models=[StaticStat, Stat]) + await connect( + **config.mongo.dict(), + testing=config.environment.value == "develop", + extra_models=[StaticStat, Stat], + ) jarvis = Jarvis( intents=intents, @@ -81,6 +94,7 @@ async def run() -> None: send_command_tracebacks=False, redis=redis, logger=logger, + erapi=config.erapi, ) # External modules diff --git a/jarvis/client/__init__.py b/jarvis/client/__init__.py index 56853a1..777c371 100644 --- a/jarvis/client/__init__.py +++ b/jarvis/client/__init__.py @@ -2,6 +2,7 @@ import logging from typing import TYPE_CHECKING +from erapi import ERAPI from interactions.ext.prefixed_commands.context import PrefixedContext from interactions.models.internal.context import BaseContext, InteractionContext from jarvis_core.util.ansi import Fore, Format, fmt @@ -20,13 +21,16 @@ CMD_FMT = fmt(Fore.GREEN, Format.BOLD) class Jarvis(StatipyClient, ErrorMixin, EventMixin, TaskMixin): - def __init__(self, redis: "aioredis.Redis", *args, **kwargs): # noqa: ANN002 ANN003 + def __init__( + self, redis: "aioredis.Redis", erapi: str, *args, **kwargs + ): # noqa: ANN002 ANN003 super().__init__(*args, **kwargs) self.redis = redis self.logger = logging.getLogger(__name__) self.phishing_domains = [] self.pre_run_callback = self._prerun self.synced = False + self.erapi = ERAPI(erapi) async def _prerun(self, ctx: BaseContext, *args, **kwargs) -> None: name = ctx.invoke_target diff --git a/jarvis/client/errors.py b/jarvis/client/errors.py index fba1ba8..cf0f9f1 100644 --- a/jarvis/client/errors.py +++ b/jarvis/client/errors.py @@ -2,6 +2,8 @@ import traceback from datetime import datetime, timezone +from interactions import listen +from interactions.api.events import Error from interactions.client.errors import ( CommandCheckFailure, CommandOnCooldown, @@ -31,16 +33,24 @@ Callback: class ErrorMixin: - async def on_error(self, source: str, error: Exception, *args, **kwargs) -> None: + @listen() + async def on_error(self, event: Error, *args, **kwargs) -> None: """NAFF on_error override.""" + source = event.source + error = event.error if isinstance(error, HTTPException): errors = error.search_for_message(error.errors) - out = f"HTTPException: {error.status}|{error.response.reason}: " + "\n".join(errors) + out = ( + f"HTTPException: {error.status}|{error.response.reason}: " + + "\n".join(errors) + ) self.logger.error(out, exc_info=error) else: self.logger.error(f"Ignoring exception in {source}", exc_info=error) - async def on_command_error(self, ctx: BaseContext, error: Exception, *args: list, **kwargs: dict) -> None: + async def on_command_error( + self, ctx: BaseContext, error: Exception, *args: list, **kwargs: dict + ) -> None: """NAFF on_command_error override.""" name = ctx.invoke_target self.logger.debug(f"Handling error in {name}: {error}") @@ -70,7 +80,11 @@ class ErrorMixin: v = v[97] + "..." arg_str += f" - {v}" callback_args = "\n".join(f" - {i}" for i in args) if args else " None" - callback_kwargs = "\n".join(f" {k}: {v}" for k, v in kwargs.items()) if kwargs else " None" + callback_kwargs = ( + "\n".join(f" {k}: {v}" for k, v in kwargs.items()) + if kwargs + else " None" + ) full_message = ERROR_MSG.format( guild_name=ctx.guild.name, error_time=error_time, @@ -82,7 +96,11 @@ class ErrorMixin: tb = traceback.format_exception(error) if isinstance(error, HTTPException): errors = error.search_for_message(error.errors) - tb[-1] = f"HTTPException: {error.status}|{error.response.reason}: " + "\n".join(errors) + tb[ + -1 + ] = f"HTTPException: {error.status}|{error.response.reason}: " + "\n".join( + errors + ) error_message = "".join(traceback.format_exception(error)) if len(full_message + error_message) >= 1800: error_message = "\n ".join(error_message.split("\n")) @@ -101,7 +119,9 @@ class ErrorMixin: f"\n```yaml\n{full_message}\n```" f"\nException:\n```py\n{error_message}\n```" ) - await ctx.send("Whoops! Encountered an error. The error has been logged.", ephemeral=True) + await ctx.send( + "Whoops! Encountered an error. The error has been logged.", ephemeral=True + ) try: await ctx.defer(ephemeral=True) return await super().on_command_error(ctx, error, *args, **kwargs) diff --git a/jarvis/client/events/__init__.py b/jarvis/client/events/__init__.py index 752d0f3..ee7f9c3 100644 --- a/jarvis/client/events/__init__.py +++ b/jarvis/client/events/__init__.py @@ -35,16 +35,22 @@ class EventMixin(MemberEventMixin, MessageEventMixin, ComponentEventMixin): async def _sync_domains(self) -> None: self.logger.debug("Loading phishing domains") - async with ClientSession(headers={"X-Identity": "Discord: zevaryx#5779"}) as session: + async with ClientSession( + headers={"X-Identity": "Discord: zevaryx#5779"} + ) as session: response = await session.get("https://phish.sinking.yachts/v2/all") response.raise_for_status() self.phishing_domains = await response.json() - self.logger.info(f"Protected from {len(self.phishing_domains)} phishing domains") + self.logger.info( + f"Protected from {len(self.phishing_domains)} phishing domains" + ) @listen() async def on_startup(self) -> None: """NAFF on_startup override. Prometheus info generated here.""" - await StaticStat.find_one(StaticStat.name == "jarvis_version", StaticStat.client_id == self.user.id).upsert( + await StaticStat.find_one( + StaticStat.name == "jarvis_version", StaticStat.client_id == self.user.id + ).upsert( Set( { StaticStat.client_name: self.client_name, @@ -67,7 +73,9 @@ class EventMixin(MemberEventMixin, MessageEventMixin, ComponentEventMixin): except Exception as e: self.logger.error("Failed to load anti-phishing", exc_info=e) self.logger.info("Logged in as {}".format(self.user)) # noqa: T001 - self.logger.info("Connected to {} guild(s)".format(len(self.guilds))) # noqa: T001 + self.logger.info( + "Connected to {} guild(s)".format(len(self.guilds)) + ) # noqa: T001 self.logger.info("Current version: {}".format(const.__version__)) self.logger.info( # noqa: T001 "https://discord.com/api/oauth2/authorize?client_id=" @@ -87,7 +95,9 @@ class EventMixin(MemberEventMixin, MessageEventMixin, ComponentEventMixin): if not isinstance(self.interaction_tree[cid][_], ContextMenu) ) global_context_menus = sum( - 1 for _ in self.interaction_tree[cid] if isinstance(self.interaction_tree[cid][_], ContextMenu) + 1 + for _ in self.interaction_tree[cid] + if isinstance(self.interaction_tree[cid][_], ContextMenu) ) else: guild_base_commands += sum( @@ -96,25 +106,42 @@ class EventMixin(MemberEventMixin, MessageEventMixin, ComponentEventMixin): if not isinstance(self.interaction_tree[cid][_], ContextMenu) ) guild_context_menus += sum( - 1 for _ in self.interaction_tree[cid] if isinstance(self.interaction_tree[cid][_], ContextMenu) + 1 + for _ in self.interaction_tree[cid] + if isinstance(self.interaction_tree[cid][_], ContextMenu) ) - self.logger.info("Loaded {:>3} global base slash commands".format(global_base_commands)) - self.logger.info("Loaded {:>3} global context menus".format(global_context_menus)) - self.logger.info("Loaded {:>3} guild base slash commands".format(guild_base_commands)) - self.logger.info("Loaded {:>3} guild context menus".format(guild_context_menus)) + self.logger.info( + "Loaded {:>3} global base slash commands".format(global_base_commands) + ) + self.logger.info( + "Loaded {:>3} global context menus".format(global_context_menus) + ) + self.logger.info( + "Loaded {:>3} guild base slash commands".format(guild_base_commands) + ) + self.logger.info( + "Loaded {:>3} guild context menus".format(guild_context_menus) + ) except Exception: self.logger.error("interaction_tree not found, try updating NAFF") + self.logger.debug(self.interaction_tree) self.logger.debug("Hitting Reminders for faster loads") _ = await Reminder.find().to_list(None) + self.logger.debug("Updating ERAPI") + await self.erapi.update_async() # Modlog async def on_command(self, ctx: BaseContext) -> None: """NAFF on_command override.""" name = ctx.invoke_target if not isinstance(ctx.channel, DMChannel) and name not in ["pw"]: - modlog = await Setting.find_one(Setting.guild == ctx.guild.id, Setting.setting == "activitylog") - ignore = await Setting.find_one(Setting.guild == ctx.guild.id, Setting.setting == "log_ignore") + modlog = await Setting.find_one( + Setting.guild == ctx.guild.id, Setting.setting == "activitylog" + ) + ignore = await Setting.find_one( + Setting.guild == ctx.guild.id, Setting.setting == "log_ignore" + ) if modlog and (ignore and ctx.channel.id not in ignore.value): channel = await ctx.guild.fetch_channel(modlog.value) args = [] @@ -146,10 +173,14 @@ class EventMixin(MemberEventMixin, MessageEventMixin, ComponentEventMixin): fields=fields, color="#fc9e3f", ) - embed.set_author(name=ctx.author.username, icon_url=ctx.author.display_avatar.url) - embed.set_footer(text=f"{ctx.author.user.username}#{ctx.author.discriminator} | {ctx.author.id}") + embed.set_author( + name=ctx.author.username, icon_url=ctx.author.display_avatar.url + ) + embed.set_footer(text=f"{ctx.author.user.username} | {ctx.author.id}") if channel: await channel.send(embeds=embed) else: - self.logger.warning(f"Activitylog channel no longer exists in {ctx.guild.name}, removing") + self.logger.warning( + f"Activitylog channel no longer exists in {ctx.guild.name}, removing" + ) await modlog.delete() diff --git a/jarvis/client/events/components.py b/jarvis/client/events/components.py index 2390e9c..3678c28 100644 --- a/jarvis/client/events/components.py +++ b/jarvis/client/events/components.py @@ -1,4 +1,5 @@ """JARVIS component event mixin.""" +from beanie import PydanticObjectId from interactions import listen from interactions.api.events.internal import ButtonPressed from interactions.models.discord.embed import EmbedField @@ -32,13 +33,21 @@ class ComponentEventMixin: ): name, parent = action_data.split("|")[:2] action = Action(action_type=name, parent=parent) - note = Note(admin=context.author.id, content="Moderation case opened via message") + note = Note( + admin=context.author.id, + content="Moderation case opened via message", + ) modlog = await Modlog.find_one( - Modlog.user == user.id, Modlog.guild == context.guild.id, Modlog.open == True + Modlog.user == user.id, + Modlog.guild == context.guild.id, + Modlog.open == True, ) if modlog: self.logger.debug("User already has active case in guild") - await context.send(f"User already has open case: {modlog.nanoid}", ephemeral=True) + await context.send( + f"User already has open case: {modlog.nanoid}", + ephemeral=True, + ) else: modlog = Modlog( user=user.id, @@ -59,7 +68,7 @@ class ComponentEventMixin: fields=fields, ) embed.set_author( - name=user.username + "#" + user.discriminator, + name=user.username, icon_url=user.display_avatar.url, ) @@ -75,7 +84,11 @@ class ComponentEventMixin: for component in row.components: component.disabled = True await context.message.edit(components=context.message.components) - msg = "Cancelled" if context.custom_id == "modcase|no" else "Moderation case opened" + msg = ( + "Cancelled" + if context.custom_id == "modcase|no" + else "Moderation case opened" + ) await context.send(msg) await self.redis.delete(user_key) await self.redis.delete(action_key) @@ -101,7 +114,9 @@ class ComponentEventMixin: await context.send("I'm afraid I can't let you do that", ephemeral=True) return True # User does not have perms to delete - if pin := await Pin.find_one(Pin.pin == context.message.id, Pin.guild == context.guild.id): + if pin := await Pin.find_one( + Pin.pin == context.message.id, Pin.guild == context.guild.id + ): await pin.delete() await context.message.delete() @@ -119,20 +134,35 @@ class ComponentEventMixin: what, rid = context.custom_id.split("|")[1:] if what == "rme": - reminder = await Reminder.find_one(Reminder.id == rid) + reminder = await Reminder.find_one(Reminder.id == PydanticObjectId(rid)) if reminder: - new_reminder = Reminder( - user=context.author.id, - channel=context.channel.id, - guild=context.guild.id, - message=reminder.message, - remind_at=reminder.remind_at, - private=reminder.private, - active=reminder.active, - ) - await new_reminder.save() + if await Reminder.find_one( + Reminder.parent == str(reminder.id), + Reminder.user == context.author.id, + ) or await Reminder.find_one( + Reminder.id == reminder.id, Reminder.user == context.author.id + ): + await context.send( + "You've already copied this reminder!", ephemeral=True + ) + else: + new_reminder = Reminder( + user=context.author.id, + channel=context.channel.id, + guild=context.guild.id, + message=reminder.message, + remind_at=reminder.remind_at, + private=reminder.private, + active=reminder.active, + parent=str(reminder.id), + ) + await new_reminder.save() - await context.send("Reminder copied!", ephemeral=True) + await context.send("Reminder copied!", ephemeral=True) + else: + await context.send( + "That reminder doesn't exist anymore", ephemeral=True + ) return True diff --git a/jarvis/client/events/member.py b/jarvis/client/events/member.py index 9e996ac..1ff964e 100644 --- a/jarvis/client/events/member.py +++ b/jarvis/client/events/member.py @@ -38,11 +38,11 @@ class MemberEventMixin: channel = await guild.fetch_channel(log.value) embed = build_embed( title="Member Left", - description=f"{user.username}#{user.discriminator} left {guild.name}", + description=f"{user.username} left {guild.name}", fields=[], ) embed.set_author(name=user.username, icon_url=user.avatar.url) - embed.set_footer(text=f"{user.username}#{user.discriminator} | {user.id}") + embed.set_footer(text=f"{user.username} | {user.id}") await channel.send(embeds=embed) async def process_verify(self, before: Member, after: Member) -> Embed: @@ -56,7 +56,7 @@ class MemberEventMixin: admin_text = "[N/A]" if admin := await after.guild.fet_member(audit_event.user_id): admin_mention = admin.mention - admin_text = f"{admin.username}#{admin.discriminator}" + admin_text = f"{admin.username}" fields = ( EmbedField(name="Moderator", value=f"{admin_mention} ({admin_text})"), EmbedField(name="Reason", value=audit_event.reason), @@ -67,7 +67,7 @@ class MemberEventMixin: fields=fields, ) embed.set_author(name=after.display_name, icon_url=after.display_avatar.url) - embed.set_footer(text=f"{after.username}#{after.discriminator} | {after.id}") + embed.set_footer(text=f"{after.username} | {after.id}") return embed async def process_rolechange(self, before: Member, after: Member) -> Embed: @@ -98,14 +98,13 @@ class MemberEventMixin: fields=fields, ) embed.set_author(name=after.display_name, icon_url=after.display_avatar.url) - embed.set_footer(text=f"{after.username}#{after.discriminator} | {after.id}") + embed.set_footer(text=f"{after.username} | {after.id}") return embed async def process_rename(self, before: Member, after: Member) -> None: """Process name change.""" if ( before.nickname == after.nickname - and before.discriminator == after.discriminator and before.username == after.username ): return @@ -113,9 +112,9 @@ class MemberEventMixin: fields = ( EmbedField( name="Before", - value=f"{before.display_name} ({before.username}#{before.discriminator})", + value=f"{before.display_name} ({before.username})", ), - EmbedField(name="After", value=f"{after.display_name} ({after.username}#{after.discriminator})"), + EmbedField(name="After", value=f"{after.display_name} ({after.username})"), ) embed = build_embed( title="User Renamed", @@ -124,7 +123,7 @@ class MemberEventMixin: color="#fc9e3f", ) embed.set_author(name=after.display_name, icon_url=after.display_avatar.url) - embed.set_footer(text=f"{after.username}#{after.discriminator} | {after.id}") + embed.set_footer(text=f"{after.username} | {after.id}") return embed @listen() diff --git a/jarvis/client/events/message.py b/jarvis/client/events/message.py index e12e3bc..17a3bb7 100644 --- a/jarvis/client/events/message.py +++ b/jarvis/client/events/message.py @@ -40,7 +40,9 @@ class MessageEventMixin: ) if autopurge: if not message.author.has_permission(Permissions.ADMINISTRATOR): - self.logger.debug(f"Autopurging message {message.guild.id}/{message.channel.id}/{message.id}") + self.logger.debug( + f"Autopurging message {message.guild.id}/{message.channel.id}/{message.id}" + ) await message.delete(delay=autopurge.delay) async def autoreact(self, message: Message) -> None: @@ -50,13 +52,15 @@ class MessageEventMixin: Autoreact.channel == message.channel.id, ) if autoreact: - self.logger.debug(f"Autoreacting to message {message.guild.id}/{message.channel.id}/{message.id}") + self.logger.debug( + f"Autoreacting to message {message.guild.id}/{message.channel.id}/{message.id}" + ) for reaction in autoreact.reactions: await message.add_reaction(reaction) if autoreact.thread: name = message.content.replace("\n", " ") name = re.sub(r"<:\w+:(\d+)>", "", name) - if len(name) > 100: + if len(name) >= 100: name = name[:97] + "..." await message.create_thread(name=message.content, reason="Autoreact") @@ -70,7 +74,9 @@ class MessageEventMixin: # ) content = re.sub(r"\s+", "", message.content) match = invites.search(content) - setting = await Setting.find_one(Setting.guild == message.guild.id, Setting.setting == "noinvite") + setting = await Setting.find_one( + Setting.guild == message.guild.id, Setting.setting == "noinvite" + ) if not setting: setting = Setting(guild=message.guild.id, setting="noinvite", value=True) await setting.save() @@ -78,12 +84,20 @@ class MessageEventMixin: guild_invites = [x.code for x in await message.guild.fetch_invites()] if message.guild.vanity_url_code: guild_invites.append(message.guild.vanity_url_code) - allowed = guild_invites + ["dbrand", "VtgZntXcnZ", "gPfYGbvTCE", "interactions", "NTSHu97tHg"] - is_mod = message.author.has_permission(Permissions.MANAGE_GUILD) or message.author.has_permission( - Permissions.ADMINISTRATOR - ) + allowed = guild_invites + [ + "dbrand", + "VtgZntXcnZ", + "gPfYGbvTCE", + "interactions", + "NTSHu97tHg", + ] + is_mod = message.author.has_permission( + Permissions.MANAGE_GUILD + ) or message.author.has_permission(Permissions.ADMINISTRATOR) if (m := match.group(1)) not in allowed and setting.value and not is_mod: - self.logger.debug(f"Removing non-allowed invite `{m}` from {message.guild.id}") + self.logger.debug( + f"Removing non-allowed invite `{m}` from {message.guild.id}" + ) try: await message.delete() except Exception: @@ -116,8 +130,7 @@ class MessageEventMixin: async def filters(self, message: Message) -> None: """Handle filter evennts.""" - filters = Filter.find(Filter.guild == message.guild.id) - async for item in filters: + async for item in Filter.find(Filter.guild == message.guild.id): for f in item.filters: if re.search(f, message.content, re.IGNORECASE): expires_at = datetime.now(tz=timezone.utc) + timedelta(hours=24) @@ -139,7 +152,9 @@ class MessageEventMixin: value=1, ) await Stat(meta=md, name="warning").insert() - embed = warning_embed(message.author, "Sent a message with a filtered word", self.user) + embed = warning_embed( + message.author, "Sent a message with a filtered word", self.user + ) try: await message.reply(embeds=embed) except Exception: @@ -153,24 +168,26 @@ class MessageEventMixin: async def massmention(self, message: Message) -> None: """Handle massmention events.""" - massmention = await Setting.find_one( + massmention: Setting = await Setting.find_one( Setting.guild == message.guild.id, Setting.setting == "massmention", ) - is_mod = message.author.has_permission(Permissions.MANAGE_GUILD) or message.author.has_permission( - Permissions.ADMINISTRATOR - ) + is_mod = message.author.has_permission( + Permissions.MANAGE_GUILD + ) or message.author.has_permission(Permissions.ADMINISTRATOR) if ( massmention - and massmention.value > 0 # noqa: W503 + and int(massmention.value) > 0 # noqa: W503 and len(message._mention_ids + message._mention_roles) # noqa: W503 - (1 if message.author.id in message._mention_ids else 0) # noqa: W503 > massmention.value # noqa: W503 and not is_mod # noqa: W503 ): - self.logger.debug(f"Massmention threshold on {message.guild.id}/{message.channel.id}/{message.id}") + self.logger.debug( + f"Massmention threshold on {message.guild.id}/{message.channel.id}/{message.id}" + ) expires_at = datetime.now(tz=timezone.utc) + timedelta(hours=24) await Warning( active=True, @@ -202,11 +219,20 @@ class MessageEventMixin: if message.author.has_permission(Permissions.MANAGE_GUILD): return except Exception as e: - self.logger.error("Failed to get permissions, pretending check failed", exc_info=e) + self.logger.error( + "Failed to get permissions, pretending check failed", exc_info=e + ) - if await Roleping.find(Roleping.guild == message.guild.id, Roleping.active == True).count() == 0: + if ( + await Roleping.find( + Roleping.guild == message.guild.id, Roleping.active == True + ).count() + == 0 + ): return - rolepings = await Roleping.find(Roleping.guild == message.guild.id, Roleping.active == True).to_list() + rolepings = await Roleping.find( + Roleping.guild == message.guild.id, Roleping.active == True + ).to_list() # Get all role IDs involved with message roles = [x.id async for x in message.mention_roles] @@ -230,7 +256,9 @@ class MessageEventMixin: # Check if user in a bypass list def check_has_role(roleping: Roleping) -> bool: - return any(role.id in roleping.bypass.roles for role in message.author.roles) + return any( + role.id in roleping.bypass.roles for role in message.author.roles + ) user_has_bypass = False for roleping in rolepings: @@ -241,8 +269,15 @@ class MessageEventMixin: user_has_bypass = True break - if role_in_rolepings and user_missing_role and not user_is_admin and not user_has_bypass: - self.logger.debug(f"Rolepinged role in {message.guild.id}/{message.channel.id}/{message.id}") + if ( + role_in_rolepings + and user_missing_role + and not user_is_admin + and not user_has_bypass + ): + self.logger.debug( + f"Rolepinged role in {message.guild.id}/{message.channel.id}/{message.id}" + ) expires_at = datetime.now(tz=timezone.utc) + timedelta(hours=24) await Warning( active=True, @@ -262,7 +297,11 @@ class MessageEventMixin: value=1, ) await Stat(meta=md, name="warning").insert() - embed = warning_embed(message.author, "Pinged a blocked role/user with a blocked role", self.user) + embed = warning_embed( + message.author, + "Pinged a blocked role/user with a blocked role", + self.user, + ) try: await message.channel.send(embeds=embed) except Exception: @@ -318,8 +357,16 @@ class MessageEventMixin: fields=[EmbedField(name="URL", value=m)], ) - valid_button = Button(style=ButtonStyle.GREEN, emoji="✔️", custom_id=f"pl|valid|{pl.id}") - invalid_button = Button(style=ButtonStyle.RED, emoji="✖️", custom_id=f"pl|invalid|{pl.id}") + valid_button = Button( + style=ButtonStyle.GREEN, + emoji="✔️", + custom_id=f"pl|valid|{pl.id}", + ) + invalid_button = Button( + style=ButtonStyle.RED, + emoji="✖️", + custom_id=f"pl|invalid|{pl.id}", + ) channel = await self.fetch_channel(1026918337554423868) @@ -372,7 +419,9 @@ class MessageEventMixin: value=1, ) await Stat(meta=md, name="warning").insert() - reasons = ", ".join(f"{m['source']}: {m['type']}" for m in data["matches"]) + reasons = ", ".join( + f"{m['source']}: {m['type']}" for m in data["matches"] + ) embed = warning_embed(message.author, reasons, self.user) try: await message.channel.send(embeds=embed) @@ -394,8 +443,16 @@ class MessageEventMixin: fields=[EmbedField(name="URL", value=m)], ) - valid_button = Button(style=ButtonStyle.GREEN, emoji="✔️", custom_id=f"pl|valid|{pl.id}") - invalid_button = Button(style=ButtonStyle.RED, emoji="✖️", custom_id=f"pl|invalid|{pl.id}") + valid_button = Button( + style=ButtonStyle.GREEN, + emoji="✔️", + custom_id=f"pl|valid|{pl.id}", + ) + invalid_button = Button( + style=ButtonStyle.RED, + emoji="✖️", + custom_id=f"pl|invalid|{pl.id}", + ) channel = await self.fetch_channel(1026918337554423868) @@ -410,7 +467,9 @@ class MessageEventMixin: """Timeout a user.""" expires_at = datetime.now(tz=timezone.utc) + timedelta(minutes=30) try: - await user.timeout(communication_disabled_until=expires_at, reason="Phishing link") + await user.timeout( + communication_disabled_until=expires_at, reason="Phishing link" + ) await Mute( user=user.id, reason="Auto mute for harmful link", @@ -431,7 +490,7 @@ class MessageEventMixin: ) embed.set_author(name=user.display_name, icon_url=user.display_avatar.url) embed.set_thumbnail(url=user.display_avatar.url) - embed.set_footer(text=f"{user.username}#{user.discriminator} | {user.id}") + embed.set_footer(text=f"{user.username} | {user.id}") await channel.send(embeds=embed) except Exception: @@ -459,10 +518,20 @@ class MessageEventMixin: before = event.before after = event.after if not after.author.bot: - modlog = await Setting.find_one(Setting.guild == after.guild.id, Setting.setting == "activitylog") - ignore = await Setting.find_one(Setting.guild == after.guild.id, Setting.setting == "log_ignore") - if modlog and (not ignore or (ignore and after.channel.id not in ignore.value)): - if not before or before.content == after.content or before.content is None: + modlog = await Setting.find_one( + Setting.guild == after.guild.id, Setting.setting == "activitylog" + ) + ignore = await Setting.find_one( + Setting.guild == after.guild.id, Setting.setting == "log_ignore" + ) + if modlog and ( + not ignore or (ignore and after.channel.id not in ignore.value) + ): + if ( + not before + or before.content == after.content + or before.content is None + ): return try: channel = before.guild.get_channel(modlog.value) @@ -491,7 +560,9 @@ class MessageEventMixin: icon_url=after.author.display_avatar.url, url=after.jump_url, ) - embed.set_footer(text=f"{after.author.username}#{after.author.discriminator} | {after.author.id}") + embed.set_footer( + text=f"{after.author.username} | {after.author.id}" + ) await channel.send(embeds=embed) except Exception as e: self.logger.warning( @@ -512,9 +583,15 @@ class MessageEventMixin: async def on_message_delete(self, event: MessageDelete) -> None: """Process on_message_delete events.""" message = event.message - modlog = await Setting.find_one(Setting.guild == message.guild.id, Setting.setting == "activitylog") - ignore = await Setting.find_one(Setting.guild == message.guild.id, Setting.setting == "log_ignore") - if modlog and (not ignore or (ignore and message.channel.id not in ignore.value)): + modlog = await Setting.find_one( + Setting.guild == message.guild.id, Setting.setting == "activitylog" + ) + ignore = await Setting.find_one( + Setting.guild == message.guild.id, Setting.setting == "log_ignore" + ) + if modlog and ( + not ignore or (ignore and message.channel.id not in ignore.value) + ): try: content = message.content or "N/A" except AttributeError: @@ -523,7 +600,9 @@ class MessageEventMixin: try: if message.attachments: - value = "\n".join([f"[{x.filename}]({x.url})" for x in message.attachments]) + value = "\n".join( + [f"[{x.filename}]({x.url})" for x in message.attachments] + ) fields.append( EmbedField( name="Attachments", @@ -533,7 +612,9 @@ class MessageEventMixin: ) if message.sticker_items: - value = "\n".join([f"Sticker: {x.name}" for x in message.sticker_items]) + value = "\n".join( + [f"Sticker: {x.name}" for x in message.sticker_items] + ) fields.append( EmbedField( name="Stickers", @@ -566,8 +647,10 @@ class MessageEventMixin: url=message.jump_url, ) embed.set_footer( - text=(f"{message.author.username}#{message.author.discriminator} | " f"{message.author.id}") + text=(f"{message.author.username} | " f"{message.author.id}") ) await channel.send(embeds=embed) except Exception as e: - self.logger.warning(f"Failed to process edit {message.guild.id}/{message.channel.id}/{message.id}: {e}") + self.logger.warning( + f"Failed to process edit {message.guild.id}/{message.channel.id}/{message.id}: {e}" + ) diff --git a/jarvis/client/tasks.py b/jarvis/client/tasks.py index bc1f5cd..8629f8b 100644 --- a/jarvis/client/tasks.py +++ b/jarvis/client/tasks.py @@ -7,7 +7,9 @@ from interactions.models.internal.tasks.triggers import IntervalTrigger class TaskMixin: @Task.create(IntervalTrigger(minutes=1)) async def _update_domains(self) -> None: - async with ClientSession(headers={"X-Identity": "Discord: zevaryx#5779"}) as session: + async with ClientSession( + headers={"X-Identity": "Discord: zevaryx#5779"} + ) as session: response = await session.get("https://phish.sinking.yachts/v2/recent/60") response.raise_for_status() data = await response.json() @@ -31,3 +33,7 @@ class TaskMixin: sub -= 1 self.phishing_domains.remove(domain) self.logger.info(f"[antiphish] {add} additions, {sub} removals") + + @Task.create(IntervalTrigger(minutes=30)) + async def _update_currencies(self) -> None: + await self.erapi.update_async() diff --git a/jarvis/cogs/core/admin/ban.py b/jarvis/cogs/core/admin/ban.py index e6e06ad..d17b8af 100644 --- a/jarvis/cogs/core/admin/ban.py +++ b/jarvis/cogs/core/admin/ban.py @@ -41,10 +41,13 @@ class BanCog(ModcaseCog): ) -> None: """Apply a Discord ban.""" await ctx.guild.ban(user, reason=reason, delete_message_seconds=delete_history) + discrim = user.discriminator + if discrim == 0: + discrim = None b = Ban( user=user.id, username=user.username, - discrim=user.discriminator, + discrim=discrim, reason=reason, admin=ctx.author.id, guild=ctx.guild.id, @@ -65,13 +68,18 @@ class BanCog(ModcaseCog): await ctx.send(embeds=embed) - async def discord_apply_unban(self, ctx: InteractionContext, user: User, reason: str) -> None: + async def discord_apply_unban( + self, ctx: InteractionContext, user: User, reason: str + ) -> None: """Apply a Discord unban.""" await ctx.guild.unban(user, reason=reason) + discrim = user.discriminator + if discrim == 0: + discrim = None u = Unban( user=user.id, username=user.username, - discrim=user.discriminator, + discrim=discrim, guild=ctx.guild.id, admin=ctx.author.id, reason=reason, @@ -83,8 +91,15 @@ class BanCog(ModcaseCog): await ctx.send(embeds=embed) @slash_command(name="ban", description="Ban a user") - @slash_option(name="user", description="User to ban", opt_type=OptionType.USER, required=True) - @slash_option(name="reason", description="Ban reason", opt_type=OptionType.STRING, required=True) + @slash_option( + name="user", description="User to ban", opt_type=OptionType.USER, required=True + ) + @slash_option( + name="reason", + description="Ban reason", + opt_type=OptionType.STRING, + required=True, + ) @slash_option( name="btype", description="Ban type", @@ -131,14 +146,23 @@ class BanCog(ModcaseCog): await ctx.send("You cannot set a temp ban to > 1 month", ephemeral=True) return if delete_history and not time_pattern.match(delete_history): - await ctx.send("Invalid time string, please follow example: 1w 3d 7h 5m 20s", ephemeral=True) + await ctx.send( + "Invalid time string, please follow example: 1w 3d 7h 5m 20s", + ephemeral=True, + ) return if len(reason) > 100: await ctx.send("Reason must be < 100 characters", ephemeral=True) return if delete_history: - units = {"w": "weeks", "d": "days", "h": "hours", "m": "minutes", "s": "seconds"} + units = { + "w": "weeks", + "d": "days", + "h": "hours", + "m": "minutes", + "s": "seconds", + } delta = {"weeks": 0, "days": 0, "hours": 0, "minutes": 0, "seconds": 0} delete_history = delete_history.strip().lower() if delete_history: @@ -148,7 +172,10 @@ class BanCog(ModcaseCog): delete_history = int(timedelta(**delta).total_seconds()) if delete_history > 604800: - await ctx.send("Delete history cannot be greater than 7 days (604800 seconds)", ephemeral=True) + await ctx.send( + "Delete history cannot be greater than 7 days (604800 seconds)", + ephemeral=True, + ) return await ctx.defer() @@ -158,7 +185,9 @@ class BanCog(ModcaseCog): mtype = "perma" guild_name = ctx.guild.name - user_message = f"You have been {mtype}banned from {guild_name}." + f" Reason:\n{reason}" + user_message = ( + f"You have been {mtype}banned from {guild_name}." + f" Reason:\n{reason}" + ) if mtype == "temp": user_message += f"\nDuration: {duration} hours" @@ -187,7 +216,9 @@ class BanCog(ModcaseCog): except Exception: self.logger.warn(f"Failed to send ban embed to {user.id}") try: - await self.discord_apply_ban(ctx, reason, user, duration, active, mtype, delete_history or 0) + await self.discord_apply_ban( + ctx, reason, user, duration, active, mtype, delete_history or 0 + ) except Exception as e: await ctx.send(f"Failed to ban user:\n```\n{e}\n```", ephemeral=True) return @@ -196,8 +227,18 @@ class BanCog(ModcaseCog): await ctx.guild.unban(user, reason="Ban was softban") @slash_command(name="unban", description="Unban a user") - @slash_option(name="user", description="User to unban", opt_type=OptionType.STRING, required=True) - @slash_option(name="reason", description="Unban reason", opt_type=OptionType.STRING, required=True) + @slash_option( + name="user", + description="User to unban", + opt_type=OptionType.STRING, + required=True, + ) + @slash_option( + name="reason", + description="Unban reason", + opt_type=OptionType.STRING, + required=True, + ) @check(admin_or_permissions(Permissions.BAN_MEMBERS)) async def _unban( self, @@ -226,7 +267,8 @@ class BanCog(ModcaseCog): user, discrim = user.split("#") if discrim: discord_ban_info = find( - lambda x: x.user.username == user and x.user.discriminator == discrim, + lambda x: x.user.username == user + and x.user.discriminator == discrim, bans, ) else: @@ -235,9 +277,16 @@ class BanCog(ModcaseCog): if len(results) > 1: active_bans = [] for ban in bans: - active_bans.append("{0} ({1}): {2}".format(ban.user.username, ban.user.id, ban.reason)) + active_bans.append( + "{0} ({1}): {2}".format( + ban.user.username, ban.user.id, ban.reason + ) + ) ab_message = "\n".join(active_bans) - message = "More than one result. " f"Please use one of the following IDs:\n```{ab_message}\n```" + message = ( + "More than one result. " + f"Please use one of the following IDs:\n```{ab_message}\n```" + ) await ctx.send(message) return discord_ban_info = results[0] @@ -259,7 +308,7 @@ class BanCog(ModcaseCog): if discrim: search["discrim"] = discrim - database_ban_info = await Ban.find_one(*[getattr(Ban, k) == v for k, v in search.items]) + database_ban_info = await Ban.find_one(search) if not discord_ban_info and not database_ban_info: await ctx.send(f"Unable to find user {orig_user}", ephemeral=True) @@ -282,7 +331,9 @@ class BanCog(ModcaseCog): admin=ctx.author.id, reason=reason, ).save() - await ctx.send("Unable to find user in Discord, but removed entry from database.") + await ctx.send( + "Unable to find user in Discord, but removed entry from database." + ) bans = SlashCommand(name="bans", description="User bans") @@ -306,14 +357,16 @@ class BanCog(ModcaseCog): required=False, ) @check(admin_or_permissions(Permissions.BAN_MEMBERS)) - async def _bans_list(self, ctx: InteractionContext, btype: int = 0, active: bool = True) -> None: + async def _bans_list( + self, ctx: InteractionContext, btype: int = 0, active: bool = True + ) -> None: types = [0, "perm", "temp", "soft"] search = {"guild": ctx.guild.id} if active: search["active"] = True if btype > 0: search["type"] = types[btype] - bans = await Ban.find(*[getattr(Ban, k) == v for k, v in search.items]).sort(-Ban.created_at).to_list() + bans = await Ban.find(search).sort(-Ban.created_at).to_list() db_bans = [] fields = [] for ban in bans: @@ -322,7 +375,7 @@ class BanCog(ModcaseCog): ban.username = user.username if user else "[deleted user]" fields.append( EmbedField( - name=f"Username: {ban.username}#{ban.discrim}", + name=f"Username: {ban.username}", value=( f"Date: {ban.created_at.strftime('%d-%m-%Y')}\n" f"User ID: {ban.user}\n" @@ -339,7 +392,7 @@ class BanCog(ModcaseCog): if ban.user.id not in db_bans: fields.append( EmbedField( - name=f"Username: {ban.user.username}#" + f"{ban.user.discriminator}", + name=f"Username: {ban.user.username}", value=( f"Date: [unknown]\n" f"User ID: {ban.user.id}\n" @@ -368,7 +421,9 @@ class BanCog(ModcaseCog): pages.append(embed) else: for i in range(0, len(bans), 5): - embed = build_embed(title=title, description="", fields=fields[i : i + 5]) + embed = build_embed( + title=title, description="", fields=fields[i : i + 5] + ) embed.set_thumbnail(url=ctx.guild.icon.url) pages.append(embed) diff --git a/jarvis/cogs/core/admin/filters.py b/jarvis/cogs/core/admin/filters.py index 894f069..1c239fb 100644 --- a/jarvis/cogs/core/admin/filters.py +++ b/jarvis/cogs/core/admin/filters.py @@ -31,63 +31,81 @@ class FilterCog(Extension): self.bot = bot self.cache: Dict[int, List[str]] = {} - async def _edit_filter(self, ctx: InteractionContext, name: str, search: bool = False) -> None: - content = "" - f: Filter = None - if search: - if f := await Filter.find_one(Filter.name == name, Filter.guild == ctx.guild.id): - content = "\n".join(f.filters) + async def _edit_filter( + self, ctx: InteractionContext, name: str, search: bool = False + ) -> None: + try: + content = "" + f: Filter = None + if search: + if f := await Filter.find_one( + Filter.name == name, Filter.guild == ctx.guild.id + ): + content = "\n".join(f.filters) - kw = "Updating" if search else "Creating" + kw = "Updating" if search else "Creating" - modal = Modal( - title=f'{kw} filter "{name}"', - components=[ - InputText( - label="Filter (one statement per line)", - placeholder="" if content else "i.e. $bad_word^", - custom_id="filters", - max_length=3000, - value=content, - style=TextStyles.PARAGRAPH, + modal = Modal( + *[ + InputText( + label="Filter (one statement per line)", + placeholder="" if content else "i.e. $bad_word^", + custom_id="filters", + max_length=3000, + value=content, + style=TextStyles.PARAGRAPH, + ) + ], + title=f'{kw} filter "{name}"', + ) + await ctx.send_modal(modal) + try: + data = await self.bot.wait_for_modal( + modal, author=ctx.author.id, timeout=60 * 5 ) - ], - ) - await ctx.send_modal(modal) - try: - data = await self.bot.wait_for_modal(modal, author=ctx.author.id, timeout=60 * 5) - filters = data.responses.get("filters").split("\n") - except asyncio.TimeoutError: - return - # Thanks, Glitter - new_name = re.sub(r"[^\w-]", "", name) - try: - if not f: - f = Filter(name=new_name, guild=ctx.guild.id, filters=filters) - else: - f.name = new_name - f.filters = filters - await f.save() + filters = data.responses.get("filters").split("\n") + except asyncio.TimeoutError: + return + # Thanks, Glitter + new_name = re.sub(r"[^\w-]", "", name) + try: + if not f: + f = Filter(name=new_name, guild=ctx.guild.id, filters=filters) + else: + f.name = new_name + f.filters = filters + await f.save() + except Exception as e: + await data.send(f"{e}", ephemeral=True) + return + + content = content.splitlines() + diff = "\n".join(difflib.ndiff(content, filters)).replace("`", "\u200b`") + + await data.send( + f"Filter `{new_name}` has been updated:\n\n```diff\n{diff}\n```" + ) + + if ctx.guild.id not in self.cache: + self.cache[ctx.guild.id] = [] + if new_name not in self.cache[ctx.guild.id]: + self.cache[ctx.guild.id].append(new_name) + if name != new_name: + self.cache[ctx.guild.id].remove(name) except Exception as e: - await data.send(f"{e}", ephemeral=True) - return - - content = content.splitlines() - diff = "\n".join(difflib.ndiff(content, filters)).replace("`", "\u200b`") - - await data.send(f"Filter `{new_name}` has been updated:\n\n```diff\n{diff}\n```") - - if ctx.guild.id not in self.cache: - self.cache[ctx.guild.id] = [] - if new_name not in self.cache[ctx.guild.id]: - self.cache[ctx.guild.id].append(new_name) - if name != new_name: - self.cache[ctx.guild.id].remove(name) + self.logger.error(e, exc_info=True) filter_ = SlashCommand(name="filter", description="Manage keyword filters") - @filter_.subcommand(sub_cmd_name="create", sub_cmd_description="Create a new filter") - @slash_option(name="name", description="Name of new filter", required=True, opt_type=OptionType.STRING) + @filter_.subcommand( + sub_cmd_name="create", sub_cmd_description="Create a new filter" + ) + @slash_option( + name="name", + description="Name of new filter", + required=True, + opt_type=OptionType.STRING, + ) @check(admin_or_permissions(Permissions.MANAGE_MESSAGES)) async def _filter_create(self, ctx: InteractionContext, name: str) -> None: return await self._edit_filter(ctx, name) @@ -148,11 +166,13 @@ class FilterCog(Extension): @_filter_edit.autocomplete("name") @_filter_view.autocomplete("name") @_filter_delete.autocomplete("name") - async def _autocomplete(self, ctx: AutocompleteContext, name: str) -> None: + async def _autocomplete(self, ctx: AutocompleteContext) -> None: if not self.cache.get(ctx.guild.id): filters = await Filter.find(Filter.guild == ctx.guild.id).to_list() self.cache[ctx.guild.id] = [f.name for f in filters] - results = process.extract(name, self.cache.get(ctx.guild.id), limit=25) + results = process.extract( + ctx.input_text, self.cache.get(ctx.guild.id), limit=25 + ) choices = [{"name": r[0], "value": r[0]} for r in results] await ctx.send(choices=choices) diff --git a/jarvis/cogs/core/admin/modcase.py b/jarvis/cogs/core/admin/modcase.py index d9cebcd..6bbde0e 100644 --- a/jarvis/cogs/core/admin/modcase.py +++ b/jarvis/cogs/core/admin/modcase.py @@ -42,12 +42,18 @@ class CaseCog(Extension): guild: Originating guild """ action_table = Table() - action_table.add_column(header="Type", justify="left", style="orange4", no_wrap=True) - action_table.add_column(header="Admin", justify="left", style="cyan", no_wrap=True) + action_table.add_column( + header="Type", justify="left", style="orange4", no_wrap=True + ) + action_table.add_column( + header="Admin", justify="left", style="cyan", no_wrap=True + ) action_table.add_column(header="Reason", justify="left", style="white") note_table = Table() - note_table.add_column(header="Admin", justify="left", style="cyan", no_wrap=True) + note_table.add_column( + header="Admin", justify="left", style="cyan", no_wrap=True + ) note_table.add_column(header="Content", justify="left", style="white") console = Console() @@ -64,14 +70,18 @@ class CaseCog(Extension): admin = await self.bot.fetch_user(parent_action.admin) admin_text = "[N/A]" if admin: - admin_text = f"{admin.username}#{admin.discriminator}" - action_table.add_row(action.action_type.title(), admin_text, parent_action.reason) + admin_text = f"{admin.username}" + action_table.add_row( + action.action_type.title(), admin_text, parent_action.reason + ) with console.capture() as cap: console.print(action_table) tmp_output = cap.get() if len(tmp_output) >= 800: - action_output_extra = f"... and {len(mod_case.actions[idx:])} more actions" + action_output_extra = ( + f"... and {len(mod_case.actions[idx:])} more actions" + ) break action_output = tmp_output @@ -83,7 +93,7 @@ class CaseCog(Extension): admin = await self.bot.fetch_user(note.admin) admin_text = "[N/A]" if admin: - admin_text = f"{admin.username}#{admin.discriminator}" + admin_text = f"{admin.username}" note_table.add_row(admin_text, note.content) with console.capture() as cap: @@ -102,7 +112,7 @@ class CaseCog(Extension): username = "[N/A]" user_text = "[N/A]" if user: - username = f"{user.username}#{user.discriminator}" + username = f"{user.username}" user_text = user.mention admin = await self.bot.fetch_user(mod_case.admin) @@ -114,8 +124,13 @@ class CaseCog(Extension): note_output = f"```ansi\n{note_output}\n{note_output_extra}\n```" fields = ( - EmbedField(name="Actions", value=action_output if mod_case.actions else "No Actions Found"), - EmbedField(name="Notes", value=note_output if mod_case.notes else "No Notes Found"), + EmbedField( + name="Actions", + value=action_output if mod_case.actions else "No Actions Found", + ), + EmbedField( + name="Notes", value=note_output if mod_case.notes else "No Notes Found" + ), ) embed = build_embed( @@ -148,7 +163,7 @@ class CaseCog(Extension): user_mention = "[N/A]" avatar_url = None if user: - username = f"{user.username}#{user.discriminator}" + username = f"{user.username}" avatar_url = user.avatar.url user_mention = user.mention @@ -166,7 +181,9 @@ class CaseCog(Extension): if admin: admin_text = admin.mention - fields = (EmbedField(name=action.action_type.title(), value=parent_action.reason),) + fields = ( + EmbedField(name=action.action_type.title(), value=parent_action.reason), + ) embed = build_embed( title="Moderation Case Action", description=f"{admin_text} initiated an action against {user_mention}", @@ -195,7 +212,12 @@ class CaseCog(Extension): required=False, ) @check(admin_or_permissions(Permissions.BAN_MEMBERS)) - async def _cases_list(self, ctx: InteractionContext, user: Optional[Member] = None, closed: bool = False) -> None: + async def _cases_list( + self, + ctx: InteractionContext, + user: Optional[Member] = None, + closed: bool = False, + ) -> None: query = [Modlog.guild == ctx.guild.id] if not closed: query.append(Modlog.open == True) @@ -214,8 +236,12 @@ class CaseCog(Extension): case = SlashCommand(name="case", description="Manage a moderation case") show = case.group(name="show", description="Show information about a specific case") - @show.subcommand(sub_cmd_name="summary", sub_cmd_description="Summarize a specific case") - @slash_option(name="cid", description="Case ID", opt_type=OptionType.STRING, required=True) + @show.subcommand( + sub_cmd_name="summary", sub_cmd_description="Summarize a specific case" + ) + @slash_option( + name="cid", description="Case ID", opt_type=OptionType.STRING, required=True + ) @check(admin_or_permissions(Permissions.BAN_MEMBERS)) async def _case_show_summary(self, ctx: InteractionContext, cid: str) -> None: case = await Modlog.find_one(Modlog.guild == ctx.guild.id, Modlog.nanoid == cid) @@ -227,7 +253,9 @@ class CaseCog(Extension): await ctx.send(embeds=embed) @show.subcommand(sub_cmd_name="actions", sub_cmd_description="Get case actions") - @slash_option(name="cid", description="Case ID", opt_type=OptionType.STRING, required=True) + @slash_option( + name="cid", description="Case ID", opt_type=OptionType.STRING, required=True + ) @check(admin_or_permissions(Permissions.BAN_MEMBERS)) async def _case_show_actions(self, ctx: InteractionContext, cid: str) -> None: case = await Modlog.find_one(Modlog.guild == ctx.guild.id, Modlog.nanoid == cid) @@ -240,7 +268,9 @@ class CaseCog(Extension): await paginator.send(ctx) @case.subcommand(sub_cmd_name="close", sub_cmd_description="Show a specific case") - @slash_option(name="cid", description="Case ID", opt_type=OptionType.STRING, required=True) + @slash_option( + name="cid", description="Case ID", opt_type=OptionType.STRING, required=True + ) @check(admin_or_permissions(Permissions.BAN_MEMBERS)) async def _case_close(self, ctx: InteractionContext, cid: str) -> None: case = await Modlog.find_one(Modlog.guild == ctx.guild.id, Modlog.nanoid == cid) @@ -254,8 +284,12 @@ class CaseCog(Extension): embed = await self.get_summary_embed(case, ctx.guild) await ctx.send(embeds=embed) - @case.subcommand(sub_cmd_name="repoen", sub_cmd_description="Reopen a specific case") - @slash_option(name="cid", description="Case ID", opt_type=OptionType.STRING, required=True) + @case.subcommand( + sub_cmd_name="repoen", sub_cmd_description="Reopen a specific case" + ) + @slash_option( + name="cid", description="Case ID", opt_type=OptionType.STRING, required=True + ) @check(admin_or_permissions(Permissions.BAN_MEMBERS)) async def _case_reopen(self, ctx: InteractionContext, cid: str) -> None: case = await Modlog.find_one(Modlog.guild == ctx.guild.id, Modlog.nanoid == cid) @@ -269,9 +303,18 @@ class CaseCog(Extension): embed = await self.get_summary_embed(case, ctx.guild) await ctx.send(embeds=embed) - @case.subcommand(sub_cmd_name="note", sub_cmd_description="Add a note to a specific case") - @slash_option(name="cid", description="Case ID", opt_type=OptionType.STRING, required=True) - @slash_option(name="note", description="Note to add", opt_type=OptionType.STRING, required=True) + @case.subcommand( + sub_cmd_name="note", sub_cmd_description="Add a note to a specific case" + ) + @slash_option( + name="cid", description="Case ID", opt_type=OptionType.STRING, required=True + ) + @slash_option( + name="note", + description="Note to add", + opt_type=OptionType.STRING, + required=True, + ) @check(admin_or_permissions(Permissions.BAN_MEMBERS)) async def _case_note(self, ctx: InteractionContext, cid: str, note: str) -> None: case = await Modlog.find_one(Modlog.guild == ctx.guild.id, Modlog.nanoid == cid) @@ -280,7 +323,9 @@ class CaseCog(Extension): return if not case.open: - await ctx.send("Case is closed, please re-open to add a new comment", ephemeral=True) + await ctx.send( + "Case is closed, please re-open to add a new comment", ephemeral=True + ) return if len(note) > 50: @@ -296,11 +341,20 @@ class CaseCog(Extension): await ctx.send(embeds=embed) @case.subcommand(sub_cmd_name="new", sub_cmd_description="Open a new case") - @slash_option(name="user", description="Target user", opt_type=OptionType.USER, required=True) - @slash_option(name="note", description="Note to add", opt_type=OptionType.STRING, required=True) + @slash_option( + name="user", description="Target user", opt_type=OptionType.USER, required=True + ) + @slash_option( + name="note", + description="Note to add", + opt_type=OptionType.STRING, + required=True, + ) @check(admin_or_permissions(Permissions.BAN_MEMBERS)) async def _case_new(self, ctx: InteractionContext, user: Member, note: str) -> None: - case = await Modlog.find_one(Modlog.guild == ctx.guild.id, Modlog.user == user.id, Modlog.open == True) + case = await Modlog.find_one( + Modlog.guild == ctx.guild.id, Modlog.user == user.id, Modlog.open == True + ) if case: await ctx.send(f"Case already open with ID `{case.nanoid}`", ephemeral=True) return @@ -315,7 +369,13 @@ class CaseCog(Extension): note = Note(admin=ctx.author.id, content=note) - case = Modlog(user=user.id, guild=ctx.guild.id, admin=ctx.author.id, notes=[note], actions=[]) + case = Modlog( + user=user.id, + guild=ctx.guild.id, + admin=ctx.author.id, + notes=[note], + actions=[], + ) await case.save() embed = await self.get_summary_embed(case, ctx.guild) diff --git a/jarvis/cogs/core/admin/mute.py b/jarvis/cogs/core/admin/mute.py index 0e3850f..413dcac 100644 --- a/jarvis/cogs/core/admin/mute.py +++ b/jarvis/cogs/core/admin/mute.py @@ -27,7 +27,9 @@ from jarvis.utils.permissions import admin_or_permissions class MuteCog(ModcaseCog): """JARVIS MuteCog.""" - async def _apply_timeout(self, ctx: InteractionContext, user: Member, reason: str, until: datetime) -> None: + async def _apply_timeout( + self, ctx: InteractionContext, user: Member, reason: str, until: datetime + ) -> None: await user.timeout(communication_disabled_until=until, reason=reason) duration = int((until - datetime.now(tz=timezone.utc)).seconds / 60) await Mute( @@ -42,11 +44,14 @@ class MuteCog(ModcaseCog): return mute_embed(user=user, admin=ctx.author, reason=reason, guild=ctx.guild) @context_menu(name="Mute User", context_type=CommandType.USER) - @check(admin_or_permissions(Permissions.MUTE_MEMBERS, Permissions.BAN_MEMBERS, Permissions.KICK_MEMBERS)) + @check( + admin_or_permissions( + Permissions.MUTE_MEMBERS, Permissions.BAN_MEMBERS, Permissions.KICK_MEMBERS + ) + ) async def _timeout_cm(self, ctx: InteractionContext) -> None: modal = Modal( - title=f"Muting {ctx.target.mention}", - components=[ + *[ InputText( label="Reason?", placeholder="Spamming, harrassment, etc", @@ -62,10 +67,13 @@ class MuteCog(ModcaseCog): max_length=100, ), ], + title=f"Muting {ctx.target.mention}", ) await ctx.send_modal(modal) try: - response = await self.bot.wait_for_modal(modal, author=ctx.author.id, timeout=60 * 5) + response = await self.bot.wait_for_modal( + modal, author=ctx.author.id, timeout=60 * 5 + ) reason = response.responses.get("reason") until = response.responses.get("until") except asyncio.TimeoutError: @@ -76,7 +84,9 @@ class MuteCog(ModcaseCog): "RETURN_AS_TIMEZONE_AWARE": True, } rt_settings = base_settings.copy() - rt_settings["PARSERS"] = [x for x in default_parsers if x not in ["absolute-time", "timestamp"]] + rt_settings["PARSERS"] = [ + x for x in default_parsers if x not in ["absolute-time", "timestamp"] + ] rt_until = parse(until, settings=rt_settings) @@ -91,10 +101,14 @@ class MuteCog(ModcaseCog): until = at_until else: self.logger.debug(f"Failed to parse delay: {until}") - await response.send(f"`{until}` is not a parsable date, please try again", ephemeral=True) + await response.send( + f"`{until}` is not a parsable date, please try again", ephemeral=True + ) return if until < datetime.now(tz=timezone.utc): - await response.send(f"`{old_until}` is in the past, which isn't allowed", ephemeral=True) + await response.send( + f"`{old_until}` is in the past, which isn't allowed", ephemeral=True + ) return try: embed = await self._apply_timeout(ctx, ctx.target, reason, until) @@ -103,7 +117,9 @@ class MuteCog(ModcaseCog): await response.send("Unable to mute this user", ephemeral=True) @slash_command(name="mute", description="Mute a user") - @slash_option(name="user", description="User to mute", opt_type=OptionType.USER, required=True) + @slash_option( + name="user", description="User to mute", opt_type=OptionType.USER, required=True + ) @slash_option( name="reason", description="Reason for mute", @@ -128,9 +144,18 @@ class MuteCog(ModcaseCog): SlashCommandChoice(name="Week(s)", value=10080), ], ) - @check(admin_or_permissions(Permissions.MUTE_MEMBERS, Permissions.BAN_MEMBERS, Permissions.KICK_MEMBERS)) + @check( + admin_or_permissions( + Permissions.MUTE_MEMBERS, Permissions.BAN_MEMBERS, Permissions.KICK_MEMBERS + ) + ) async def _timeout( - self, ctx: InteractionContext, user: Member, reason: str, time: int = 1, scale: int = 60 + self, + ctx: InteractionContext, + user: Member, + reason: str, + time: int = 1, + scale: int = 60, ) -> None: if user == ctx.author: await ctx.send("You cannot mute yourself.", ephemeral=True) @@ -148,7 +173,9 @@ class MuteCog(ModcaseCog): # Max 4 weeks (2419200 seconds) per API duration = time * scale if duration > 40320: - await ctx.send("Mute must be less than 4 weeks (40,320 minutes)", ephemeral=True) + await ctx.send( + "Mute must be less than 4 weeks (40,320 minutes)", ephemeral=True + ) return until = datetime.now(tz=timezone.utc) + timedelta(minutes=duration) @@ -159,13 +186,28 @@ class MuteCog(ModcaseCog): await ctx.send("Unable to mute this user", ephemeral=True) @slash_command(name="unmute", description="Unmute a user") - @slash_option(name="user", description="User to unmute", opt_type=OptionType.USER, required=True) - @slash_option(name="reason", description="Reason for unmute", opt_type=OptionType.STRING, required=True) - @check(admin_or_permissions(Permissions.MUTE_MEMBERS, Permissions.BAN_MEMBERS, Permissions.KICK_MEMBERS)) + @slash_option( + name="user", + description="User to unmute", + opt_type=OptionType.USER, + required=True, + ) + @slash_option( + name="reason", + description="Reason for unmute", + opt_type=OptionType.STRING, + required=True, + ) + @check( + admin_or_permissions( + Permissions.MUTE_MEMBERS, Permissions.BAN_MEMBERS, Permissions.KICK_MEMBERS + ) + ) async def _unmute(self, ctx: InteractionContext, user: Member, reason: str) -> None: if ( not user.communication_disabled_until - or user.communication_disabled_until.timestamp() < datetime.now(tz=timezone.utc).timestamp() # noqa: W503 + or user.communication_disabled_until.timestamp() + < datetime.now(tz=timezone.utc).timestamp() # noqa: W503 ): await ctx.send("User is not muted", ephemeral=True) return @@ -176,6 +218,8 @@ class MuteCog(ModcaseCog): await user.timeout(communication_disabled_until=datetime.now(tz=timezone.utc)) - embed = unmute_embed(user=user, admin=ctx.author, reason=reason, guild=ctx.guild) + embed = unmute_embed( + user=user, admin=ctx.author, reason=reason, guild=ctx.guild + ) await ctx.send(embeds=embed) diff --git a/jarvis/cogs/core/admin/warning.py b/jarvis/cogs/core/admin/warning.py index 50d8912..16d613e 100644 --- a/jarvis/cogs/core/admin/warning.py +++ b/jarvis/cogs/core/admin/warning.py @@ -24,7 +24,9 @@ class WarningCog(ModcaseCog): """JARVIS WarningCog.""" @slash_command(name="warn", description="Warn a user") - @slash_option(name="user", description="User to warn", opt_type=OptionType.USER, required=True) + @slash_option( + name="user", description="User to warn", opt_type=OptionType.USER, required=True + ) @slash_option( name="reason", description="Reason for warning", @@ -38,7 +40,9 @@ class WarningCog(ModcaseCog): required=False, ) @check(admin_or_permissions(Permissions.MANAGE_GUILD)) - async def _warn(self, ctx: InteractionContext, user: Member, reason: str, duration: int = 24) -> None: + async def _warn( + self, ctx: InteractionContext, user: Member, reason: str, duration: int = 24 + ) -> None: if len(reason) > 100: await ctx.send("Reason must be < 100 characters", ephemeral=True) return @@ -66,15 +70,19 @@ class WarningCog(ModcaseCog): await ctx.send(embeds=embed) @slash_command(name="warnings", description="Get count of user warnings") - @slash_option(name="user", description="User to view", opt_type=OptionType.USER, required=True) + @slash_option( + name="user", description="User to view", opt_type=OptionType.USER, required=True + ) @slash_option( name="active", description="View active only", opt_type=OptionType.BOOLEAN, required=False, ) - @check(admin_or_permissions(Permissions.MANAGE_GUILD)) - async def _warnings(self, ctx: InteractionContext, user: Member, active: bool = True) -> None: + # @check(admin_or_permissions(Permissions.MANAGE_GUILD)) + async def _warnings( + self, ctx: InteractionContext, user: Member, active: bool = True + ) -> None: warnings = ( await Warning.find( Warning.user == user.id, @@ -84,6 +92,7 @@ class WarningCog(ModcaseCog): .to_list() ) if len(warnings) == 0: + await ctx.defer(ephemeral=True) await ctx.send("That user has no warnings.", ephemeral=True) return active_warns = get_all(warnings, active=True) @@ -117,7 +126,9 @@ class WarningCog(ModcaseCog): for i in range(0, len(fields), 5): embed = build_embed( title="Warnings", - description=(f"{len(warnings)} total | {len(active_warns)} currently active"), + description=( + f"{len(warnings)} total | {len(active_warns)} currently active" + ), fields=fields[i : i + 5], ) embed.set_author( @@ -125,7 +136,9 @@ class WarningCog(ModcaseCog): icon_url=user.display_avatar.url, ) embed.set_thumbnail(url=ctx.guild.icon.url) - embed.set_footer(text=f"{user.username}#{user.discriminator} | {user.id}") + embed.set_footer( + text=f"{user.username}#{user.discriminator} | {user.id}" + ) pages.append(embed) else: fields = [] @@ -143,10 +156,15 @@ class WarningCog(ModcaseCog): for i in range(0, len(fields), 5): embed = build_embed( title="Warnings", - description=(f"{len(warnings)} total | {len(active_warns)} currently active"), + description=( + f"{len(warnings)} total | {len(active_warns)} currently active" + ), fields=fields[i : i + 5], ) - embed.set_author(name=user.username + "#" + user.discriminator, icon_url=user.display_avatar.url) + embed.set_author( + name=user.username + "#" + user.discriminator, + icon_url=user.display_avatar.url, + ) embed.set_thumbnail(url=ctx.guild.icon.url) pages.append(embed) diff --git a/jarvis/cogs/core/remindme.py b/jarvis/cogs/core/remindme.py index 2d43eba..d40129a 100644 --- a/jarvis/cogs/core/remindme.py +++ b/jarvis/cogs/core/remindme.py @@ -5,6 +5,8 @@ import re from datetime import datetime, timezone from typing import List +import pytz +from croniter import croniter from dateparser import parse from dateparser_data.settings import default_parsers from interactions import AutocompleteContext, Client, Extension, InteractionContext @@ -23,7 +25,7 @@ from thefuzz import process from jarvis.utils import build_embed -valid = re.compile(r"[\w\s\-\\/.!@#$%^*()+=<>:'\",\u0080-\U000E0FFF]*") +valid = re.compile(r"[\w\s\-\\/.!@?#$%^*()+=<>:'\",\u0080-\U000E0FFF]*") time_pattern = re.compile(r"(\d+\.?\d?[s|m|h|d|w]{1})\s?", flags=re.IGNORECASE) invites = re.compile( r"(?:https?://)?(?:www.)?(?:discord.(?:gg|io|me|li)|discord(?:app)?.com/invite)/([^\s/]+?)(?=\b)", # noqa: E501 @@ -41,6 +43,13 @@ class RemindmeCog(Extension): reminders = SlashCommand(name="reminders", description="Manage reminders") @reminders.subcommand(sub_cmd_name="set", sub_cmd_description="Set a reminder") + @slash_option( + name="timezone", + description="Timezone to use", + opt_type=OptionType.STRING, + required=False, + autocomplete=True, + ) @slash_option( name="private", description="Send as DM?", @@ -50,15 +59,16 @@ class RemindmeCog(Extension): async def _remindme( self, ctx: InteractionContext, + timezone: str = "UTC", private: bool = None, ) -> None: if private is None and ctx.guild: private = ctx.guild.member_count >= 5000 elif private is None and not ctx.guild: private = False + timezone = pytz.timezone(timezone) modal = Modal( - title="Set your reminder!", - components=[ + *[ InputText( label="What to remind you?", placeholder="Reminder", @@ -72,14 +82,26 @@ class RemindmeCog(Extension): style=TextStyles.SHORT, custom_id="delay", ), + InputText( + label="Cron pattern for repeating", + placeholder="0 12 * * *", + style=TextStyles.SHORT, + max_length=40, + custom_id="cron", + required=False, + ), ], + title="Set your reminder!", ) await ctx.send_modal(modal) try: - response = await self.bot.wait_for_modal(modal, author=ctx.author.id, timeout=60 * 5) + response = await self.bot.wait_for_modal( + modal, author=ctx.author.id, timeout=60 * 5 + ) message = response.responses.get("message").strip() delay = response.responses.get("delay").strip() + cron = response.responses.get("cron").strip() except asyncio.TimeoutError: return if len(message) > 500: @@ -91,20 +113,32 @@ class RemindmeCog(Extension): ephemeral=True, ) return - elif not valid.fullmatch(message): - await response.send("Hey, you should probably make this readable", ephemeral=True) - return + # elif not valid.fullmatch(message): + # await response.send( + # "Hey, you should probably make this readable", ephemeral=True + # ) + # return elif len(message) == 0: - await response.send("Hey, you should probably add content to your reminder", ephemeral=True) + await response.send( + "Hey, you should probably add content to your reminder", ephemeral=True + ) + return + elif cron and not croniter.is_valid(cron): + await response.send( + f"Invalid cron: {cron}\n\nUse https://crontab.guru to help", + ephemeral=True, + ) return base_settings = { "PREFER_DATES_FROM": "future", - "TIMEZONE": "UTC", + "TIMEZONE": str(timezone), "RETURN_AS_TIMEZONE_AWARE": True, } rt_settings = base_settings.copy() - rt_settings["PARSERS"] = [x for x in default_parsers if x not in ["absolute-time", "timestamp"]] + rt_settings["PARSERS"] = [ + x for x in default_parsers if x not in ["absolute-time", "timestamp"] + ] rt_remind_at = parse(delay, settings=rt_settings) @@ -118,14 +152,20 @@ class RemindmeCog(Extension): remind_at = at_remind_at else: self.logger.debug(f"Failed to parse delay: {delay}") - await response.send(f"`{delay}` is not a parsable date, please try again", ephemeral=True) + await response.send( + f"`{delay}` is not a parsable date, please try again", + ephemeral=True, + ) return - if remind_at < datetime.now(tz=timezone.utc): - await response.send(f"`{delay}` is in the past. Past reminders aren't allowed", ephemeral=True) + if remind_at < datetime.now(tz=timezone): + await response.send( + f"`{delay}` is in the past. Past reminders aren't allowed", + ephemeral=True, + ) return - elif remind_at < datetime.now(tz=timezone.utc): + elif remind_at < datetime.now(tz=timezone): pass r = Reminder( @@ -135,39 +175,59 @@ class RemindmeCog(Extension): message=message, remind_at=remind_at, private=private, + repeat=cron, + timezone=str(timezone), active=True, ) await r.save() + fields = [ + EmbedField(name="Message", value=message), + EmbedField( + name="When", + value=f" ()", + inline=False, + ), + ] + + if r.repeat: + c = croniter(cron, remind_at) + fields.append(EmbedField(name="Repeat Schedule", value=f"`{cron}`")) + next_5 = [c.get_next() for _ in range(5)] + + next_5_str = "\n".join(f" ()" for x in next_5) + fields.append(EmbedField(name="Next 5 runs", value=next_5_str)) + embed = build_embed( title="Reminder Set", description=f"{ctx.author.mention} set a reminder", - fields=[ - EmbedField(name="Message", value=message), - EmbedField( - name="When", - value=f" ()", - inline=False, - ), - ], + fields=fields, ) embed.set_author( - name=ctx.author.username + "#" + ctx.author.discriminator, + name=ctx.author.username, icon_url=ctx.author.display_avatar.url, ) embed.set_thumbnail(url=ctx.author.display_avatar.url) - delete_button = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") + delete_button = Button( + style=ButtonStyle.DANGER, + emoji="🗑️", + custom_id=f"delete|{ctx.author.id}", + ) components = [delete_button] if not r.guild == ctx.author.id: - copy_button = Button(style=ButtonStyle.GREEN, emoji="📋", custom_id=f"copy|rme|{r.id}") + copy_button = Button( + style=ButtonStyle.GREEN, emoji="📋", custom_id=f"copy|rme|{r.id}" + ) components.append(copy_button) private = private if private is not None else False components = [ActionRow(*components)] await response.send(embeds=embed, components=components, ephemeral=private) - async def get_reminders_embed(self, ctx: InteractionContext, reminders: List[Reminder]) -> Embed: + async def get_reminders_embed( + self, ctx: InteractionContext, reminders: List[Reminder] + ) -> Embed: """Build embed for paginator.""" fields = [] for reminder in reminders: @@ -195,7 +255,7 @@ class RemindmeCog(Extension): ) embed.set_author( - name=ctx.author.username + "#" + ctx.author.discriminator, + name=ctx.author.username, icon_url=ctx.author.display_avatar.url, ) embed.set_thumbnail(url=ctx.author.display_avatar.url) @@ -204,16 +264,22 @@ class RemindmeCog(Extension): @reminders.subcommand(sub_cmd_name="list", sub_cmd_description="List reminders") async def _list(self, ctx: InteractionContext) -> None: - reminders = await Reminder.find(Reminder.user == ctx.author.id, Reminder.active == True).to_list() + reminders = await Reminder.find( + Reminder.user == ctx.author.id, Reminder.active == True + ).to_list() if not reminders: await ctx.send("You have no reminders set.", ephemeral=True) return embed = await self.get_reminders_embed(ctx, reminders) - components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") + components = Button( + style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}" + ) await ctx.send(embeds=embed, components=components) - @reminders.subcommand(sub_cmd_name="delete", sub_cmd_description="Delete a reminder") + @reminders.subcommand( + sub_cmd_name="delete", sub_cmd_description="Delete a reminder" + ) @slash_option( name="content", description="Content of the reminder", @@ -222,7 +288,7 @@ class RemindmeCog(Extension): autocomplete=True, ) async def _delete(self, ctx: InteractionContext, content: str) -> None: - reminder = await Reminder.find_one(Reminder.id == content) + reminder = await Reminder.get(content) if not reminder: await ctx.send(f"Reminder `{content}` does not exist", ephemeral=True) return @@ -238,12 +304,14 @@ class RemindmeCog(Extension): ) embed.set_author( - name=ctx.author.display_name + "#" + ctx.author.discriminator, + name=ctx.author.display_name, icon_url=ctx.author.display_avatar.url, ) embed.set_thumbnail(url=ctx.author.display_avatar.url) - components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") + components = Button( + style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}" + ) try: await reminder.delete() except Exception: @@ -275,14 +343,18 @@ class RemindmeCog(Extension): EmbedField(name="Created At", value=f" ()"), ] - embed = build_embed(title="You have a reminder!", description=reminder.message, fields=fields) + embed = build_embed( + title="You have a reminder!", description=reminder.message, fields=fields + ) embed.set_author( - name=ctx.author.display_name + "#" + ctx.author.discriminator, + name=ctx.author.display_name, icon_url=ctx.author.display_avatar.url, ) embed.set_thumbnail(url=ctx.author.display_avatar.url) - components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") + components = Button( + style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}" + ) await ctx.send(embeds=embed, ephemeral=reminder.private, components=components) if reminder.remind_at <= datetime.now(tz=timezone.utc) and not reminder.active: try: @@ -292,13 +364,22 @@ class RemindmeCog(Extension): @_fetch.autocomplete("content") @_delete.autocomplete("content") - async def _search_reminders(self, ctx: AutocompleteContext, content: str) -> None: + async def _search_reminders(self, ctx: AutocompleteContext) -> None: reminders = await Reminder.find(Reminder.user == ctx.author.id).to_list() - lookup = {r.message: str(r.id) for r in reminders} - results = process.extract(content, list(lookup.keys()), limit=5) + lookup = { + f"[{r.created_at.strftime('%d/%m/%Y %H:%M.%S')}] {r.message}": str(r.id) + for r in reminders + } + results = process.extract(ctx.input_text, list(lookup.keys()), limit=5) choices = [{"name": r[0], "value": lookup[r[0]]} for r in results] await ctx.send(choices=choices) + @_remindme.autocomplete("timezone") + async def _timezone_autocomplete(self, ctx: AutocompleteContext): + results = process.extract(ctx.input_text, pytz.all_timezones_set, limit=5) + choices = [{"name": r[0], "value": r[0]} for r in results if r[1] > 80.0] + await ctx.send(choices) + def setup(bot: Client) -> None: """Add RemindmeCog to JARVIS""" diff --git a/jarvis/cogs/core/socials/__init__.py b/jarvis/cogs/core/socials/__init__.py index 66df519..7611970 100644 --- a/jarvis/cogs/core/socials/__init__.py +++ b/jarvis/cogs/core/socials/__init__.py @@ -2,10 +2,8 @@ from interactions import Client -from jarvis.cogs.core.socials import reddit, twitter - def setup(bot: Client) -> None: """Add social cogs to JARVIS""" - reddit.RedditCog(bot) - twitter.TwitterCog(bot) + # Unfortunately there's no social cogs anymore + # Mastodon will come in the future diff --git a/jarvis/cogs/core/socials/reddit.py b/jarvis/cogs/core/socials/reddit.py deleted file mode 100644 index 475a978..0000000 --- a/jarvis/cogs/core/socials/reddit.py +++ /dev/null @@ -1,568 +0,0 @@ -"""JARVIS Reddit cog.""" -import asyncio -import logging -import re -from typing import List, Optional - -from asyncpraw import Reddit -from asyncpraw.models.reddit.submission import Submission -from asyncpraw.models.reddit.submission import Subreddit as Sub -from asyncprawcore.exceptions import Forbidden, NotFound, Redirect -from interactions import Client, Extension, InteractionContext, Permissions -from interactions.client.utils.misc_utils import get -from interactions.models.discord.channel import ChannelType, GuildText -from interactions.models.discord.components import ( - ActionRow, - StringSelectMenu, - StringSelectOption, -) -from interactions.models.discord.embed import Embed, EmbedField -from interactions.models.internal.application_commands import ( - OptionType, - SlashCommand, - SlashCommandChoice, - slash_option, -) -from interactions.models.internal.command import check -from jarvis_core.db.models import Subreddit, SubredditFollow, UserSetting - -from jarvis import const -from jarvis.config import load_config -from jarvis.utils import build_embed -from jarvis.utils.permissions import admin_or_permissions - -DEFAULT_USER_AGENT = f"python:JARVIS:{const.__version__} (by u/zevaryx)" -sub_name = re.compile(r"\A[A-Za-z0-9][A-Za-z0-9_]{2,20}\Z") -user_name = re.compile(r"[A-Za-z0-9_-]+") -image_link = re.compile(r"https?://(?:www)?\.?preview\.redd\.it\/(.*\..*)\?.*") - - -class RedditCog(Extension): - """JARVIS Reddit Cog.""" - - def __init__(self, bot: Client): - self.bot = bot - self.logger = logging.getLogger(__name__) - config = load_config() - config.reddit.user_agent = config.reddit.user_agent or DEFAULT_USER_AGENT - self.api = Reddit(**config.reddit.dict()) - - async def post_embeds(self, sub: Sub, post: Submission) -> Optional[List[Embed]]: - """ - Build a post embeds. - - Args: - post: Post to build embeds - """ - url = f"https://redd.it/{post.id}" - await post.author.load() - author_url = f"https://reddit.com/u/{post.author.name}" - author_icon = post.author.icon_img - images = [] - title = post.title - if len(title) > 256: - title = title[:253] + "..." - fields = [] - content = "" - og_post = None - if "crosspost_parent_list" in vars(post): - og_post = post # noqa: F841 - post = await self.api.submission(post.crosspost_parent_list[0]["id"]) - await post.load() - fields.append(EmbedField(name="Crossposted From", value=post.subreddit_name_prefixed)) - content = f"> **{post.title}**" - if "url" in vars(post): - if any(post.url.endswith(x) for x in ["jpeg", "jpg", "png", "gif"]): - images = [post.url] - if "media_metadata" in vars(post): - for k, v in post.media_metadata.items(): - if v["status"] != "valid" or v["m"] not in ["image/jpg", "image/png", "image/gif"]: - continue - ext = v["m"].split("/")[-1] - i_url = f"https://i.redd.it/{k}.{ext}" - images.append(i_url) - if len(images) == 4: - break - - if "selftext" in vars(post) and post.selftext: - text = post.selftext - if post.spoiler: - text = "||" + text + "||" - content += "\n\n" + post.selftext - if len(content) > 900: - content = content[:900] + "..." - if post.spoiler: - content += "||" - content += f"\n\n[View this post]({url})" - content = "\n".join(image_link.sub(r"https://i.redd.it/\1", x) for x in content.split("\n")) - - if not images and not content: - self.logger.debug(f"Post {post.id} had neither content nor images?") - return None - - color = "#FF4500" - if "primary_color" in vars(sub): - color = sub.primary_color - base_embed = build_embed( - title=title, - description=content, - fields=fields, - timestamp=post.created_utc, - url=url, - color=color, - ) - base_embed.set_author(name="u/" + post.author.name, url=author_url, icon_url=author_icon) - base_embed.set_footer( - text=f"r/{sub.display_name}", - icon_url="https://www.redditinc.com/assets/images/site/reddit-logo.png", - ) - - embeds = [base_embed] - - if len(images) > 0: - embeds[0].set_image(url=images[0]) - for image in images[1:4]: - embed = Embed(url=url) - embed.set_image(url=image) - embeds.append(embed) - - return embeds - - reddit = SlashCommand(name="reddit", description="Manage Reddit follows") - follow = reddit.group(name="follow", description="Add a follow") - unfollow = reddit.group(name="unfollow", description="Remove a follow") - - # Due to bugs and missing models, this section is commented out for the time being - # TODO: - # 1. Fix bugs - # 2. Migrate to beanie - # - # @follow.subcommand(sub_cmd_name="redditor", sub_cmd_description="Follow a Redditor") - # @slash_option( - # name="name", - # description="Redditor name", - # opt_type=OptionType.STRING, - # required=True, - # ) - # @slash_option( - # name="channel", - # description="Channel to post to", - # opt_type=OptionType.CHANNEL, - # channel_types=[ChannelType.GUILD_TEXT], - # required=True, - # ) - # @check(admin_or_permissions(Permissions.MANAGE_GUILD)) - # async def _redditor_follow(self, ctx: InteractionContext, name: str, channel: GuildText) -> None: - # if not user_name.match(name): - # await ctx.send("Invalid Redditor name", ephemeral=True) - # return - - # if not isinstance(channel, GuildText): - # await ctx.send("Channel must be a text channel", ephemeral=True) - # return - - # try: - # redditor = await self.api.redditor(name) - # await redditor.load() - # except (NotFound, Forbidden, Redirect) as e: - # self.logger.debug(f"Redditor {name} raised {e.__class__.__name__} on add") - # await ctx.send("Redditor may be deleted or nonexistent.", ephemeral=True) - # return - - # exists = await RedditorFollow.find_one(q(name=redditor.name, guild=ctx.guild.id)) - # if exists: - # await ctx.send("Redditor already being followed in this guild", ephemeral=True) - # return - - # count = len([i async for i in SubredditFollow.find(q(guild=ctx.guild.id))]) - # if count >= 12: - # await ctx.send("Cannot follow more than 12 Redditors", ephemeral=True) - # return - - # sr = await Redditor.find_one(q(name=redditor.name)) - # if not sr: - # sr = Redditor(name=redditor.name) - # await sr.commit() - - # srf = RedditorFollow( - # name=redditor.name, - # channel=channel.id, - # guild=ctx.guild.id, - # admin=ctx.author.id, - # ) - # await srf.commit() - - # await ctx.send(f"Now following `u/{name}` in {channel.mention}") - - # @unfollow.subcommand(sub_cmd_name="redditor", sub_cmd_description="Unfollow Redditor") - # @check(admin_or_permissions(Permissions.MANAGE_GUILD)) - # async def _redditor_unfollow(self, ctx: InteractionContext) -> None: - # subs = RedditorFollow.find(q(guild=ctx.guild.id)) - # redditors = [] - # async for sub in subs: - # redditors.append(sub) - # if not redditors: - # await ctx.send("You need to follow a redditor first", ephemeral=True) - # return - - # options = [] - # names = [] - # for idx, redditor in enumerate(redditors): - # sub = await Redditor.find_one(q(name=redditor.name)) - # names.append(sub.name) - # option = StringSelectOption(label=sub.name, value=str(idx)) - # options.append(option) - - # select = StringSelectMenu(options=options, custom_id="to_delete", min_values=1, max_values=len(redditors)) - - # components = [ActionRow(select)] - # block = "\n".join(x for x in names) - # message = await ctx.send( - # content=f"You are following the following redditors:\n```\n{block}\n```\n\n" - # "Please choose redditors to unfollow", - # components=components, - # ) - - # try: - # context = await self.bot.wait_for_component( - # check=lambda x: ctx.author.id == x.ctx.author.id, - # messages=message, - # timeout=60 * 5, - # ) - # for to_delete in context.ctx.values: - # follow = get(redditors, guild=ctx.guild.id, name=names[int(to_delete)]) - # try: - # await follow.delete() - # except Exception: - # self.logger.debug("Ignoring deletion error") - # for row in components: - # for component in row.components: - # component.disabled = True - - # block = "\n".join(names[int(x)] for x in context.ctx.values) - # await context.ctx.edit_origin( - # content=f"Unfollowed the following:\n```\n{block}\n```", components=components - # ) - # except asyncio.TimeoutError: - # for row in components: - # for component in row.components: - # component.disabled = True - # await message.edit(components=components) - - @follow.subcommand(sub_cmd_name="subreddit", sub_cmd_description="Follow a Subreddit") - @slash_option( - name="name", - description="Subreddit display name", - opt_type=OptionType.STRING, - required=True, - ) - @slash_option( - name="channel", - description="Channel to post to", - opt_type=OptionType.CHANNEL, - channel_types=[ChannelType.GUILD_TEXT], - required=True, - ) - @check(admin_or_permissions(Permissions.MANAGE_GUILD)) - async def _subreddit_follow(self, ctx: InteractionContext, name: str, channel: GuildText) -> None: - if not sub_name.match(name): - await ctx.send("Invalid Subreddit name", ephemeral=True) - return - - if not isinstance(channel, GuildText): - await ctx.send("Channel must be a text channel", ephemeral=True) - return - - try: - subreddit = await self.api.subreddit(name) - await subreddit.load() - except (NotFound, Forbidden, Redirect) as e: - self.logger.debug(f"Subreddit {name} raised {e.__class__.__name__} on add") - await ctx.send("Subreddit may be private, quarantined, or nonexistent.", ephemeral=True) - return - - exists = await SubredditFollow.find_one( - SubredditFollow.display_name == subreddit.display_name, SubredditFollow.guild == ctx.guild.id - ) - if exists: - await ctx.send("Subreddit already being followed in this guild", ephemeral=True) - return - - count = await SubredditFollow.find(SubredditFollow.guild == ctx.guild.id).count() - if count >= 12: - await ctx.send("Cannot follow more than 12 Subreddits", ephemeral=True) - return - - if subreddit.over18 and not channel.nsfw: - await ctx.send( - "Subreddit is nsfw, but channel is not. Mark the channel NSFW first.", - ephemeral=True, - ) - return - - sr = await Subreddit.find_one(Subreddit.display_name == subreddit.display_name) - if not sr: - sr = Subreddit(display_name=subreddit.display_name, over18=subreddit.over18) - await sr.save() - - srf = SubredditFollow( - display_name=subreddit.display_name, - channel=channel.id, - guild=ctx.guild.id, - admin=ctx.author.id, - ) - await srf.save() - - await ctx.send(f"Now following `r/{name}` in {channel.mention}") - - @unfollow.subcommand(sub_cmd_name="subreddit", sub_cmd_description="Unfollow Subreddits") - @check(admin_or_permissions(Permissions.MANAGE_GUILD)) - async def _subreddit_unfollow(self, ctx: InteractionContext) -> None: - subreddits = await SubredditFollow.find(SubredditFollow.guild == ctx.guild.id).to_list() - if not subreddits: - await ctx.send("You need to follow a Subreddit first", ephemeral=True) - return - - options = [] - names = [] - for idx, subreddit in enumerate(subreddits): - sub = await Subreddit.find_one(Subreddit.display_name == subreddit.display_name) - names.append(sub.display_name) - option = StringSelectOption(label=sub.display_name, value=str(idx)) - options.append(option) - - select = StringSelectMenu(options=options, custom_id="to_delete", min_values=1, max_values=len(subreddits)) - - components = [ActionRow(select)] - block = "\n".join(x for x in names) - message = await ctx.send( - content=f"You are following the following subreddits:\n```\n{block}\n```\n\n" - "Please choose subreddits to unfollow", - components=components, - ) - - try: - context = await self.bot.wait_for_component( - check=lambda x: ctx.author.id == x.ctx.author.id, - messages=message, - timeout=60 * 5, - ) - for to_delete in context.ctx.values: - follow = get(subreddits, guild=ctx.guild.id, display_name=names[int(to_delete)]) - try: - await follow.delete() - except Exception: - self.logger.debug("Ignoring deletion error") - for row in components: - for component in row.components: - component.disabled = True - - block = "\n".join(names[int(x)] for x in context.ctx.values) - await context.ctx.edit_origin( - content=f"Unfollowed the following:\n```\n{block}\n```", components=components - ) - except asyncio.TimeoutError: - for row in components: - for component in row.components: - component.disabled = True - await message.edit(components=components) - - @reddit.subcommand(sub_cmd_name="hot", sub_cmd_description="Get the hot post of a subreddit") - @slash_option(name="name", description="Subreddit name", opt_type=OptionType.STRING, required=True) - async def _subreddit_hot(self, ctx: InteractionContext, name: str) -> None: - if not sub_name.match(name): - await ctx.send("Invalid Subreddit name", ephemeral=True) - return - try: - await ctx.defer() - subreddit = await self.api.subreddit(name) - await subreddit.load() - except (NotFound, Forbidden, Redirect) as e: - self.logger.debug(f"Subreddit {name} raised {e.__class__.__name__} in hot") - await ctx.send("Subreddit may be private, quarantined, or nonexistent.", ephemeral=True) - return - try: - post = [x async for x in subreddit.hot(limit=1)][0] - except Exception as e: - self.logger.error(f"Failed to get post from {name}", exc_info=e) - await ctx.send("Well, this is awkward. Something went wrong", ephemeral=True) - return - - embeds = await self.post_embeds(subreddit, post) - if post.over_18 and not ctx.channel.nsfw: - setting = await UserSetting.find_one( - UserSetting.user == ctx.author.id, UserSetting.type == "reddit", UserSetting.setting == "dm_nsfw" - ) - if setting and setting.value: - try: - await ctx.author.send(embeds=embeds) - except Exception: - pass - await ctx.send("Hey! Due to content, I cannot share the result") - else: - await ctx.send(embeds=embeds) - - @reddit.subcommand(sub_cmd_name="top", sub_cmd_description="Get the top post of a subreddit") - @slash_option(name="name", description="Subreddit name", opt_type=OptionType.STRING, required=True) - @slash_option( - name="time", - description="Top time", - opt_type=OptionType.STRING, - required=False, - choices=[ - SlashCommandChoice(name="All", value="all"), - SlashCommandChoice(name="Day", value="day"), - SlashCommandChoice(name="Hour", value="hour"), - SlashCommandChoice(name="Month", value="month"), - SlashCommandChoice(name="Week", value="week"), - SlashCommandChoice(name="Year", value="year"), - ], - ) - async def _subreddit_top(self, ctx: InteractionContext, name: str, time: str = "all") -> None: - if not sub_name.match(name): - await ctx.send("Invalid Subreddit name", ephemeral=True) - return - try: - await ctx.defer() - subreddit = await self.api.subreddit(name) - await subreddit.load() - except (NotFound, Forbidden, Redirect) as e: - self.logger.debug(f"Subreddit {name} raised {e.__class__.__name__} in top") - await ctx.send("Subreddit may be private, quarantined, or nonexistent.", ephemeral=True) - return - try: - post = [x async for x in subreddit.top(time_filter=time, limit=1)][0] - except Exception as e: - self.logger.error(f"Failed to get post from {name}", exc_info=e) - await ctx.send("Well, this is awkward. Something went wrong", ephemeral=True) - return - - embeds = await self.post_embeds(subreddit, post) - if post.over_18 and not ctx.channel.nsfw: - setting = await UserSetting.find_one( - UserSetting.user == ctx.author.id, UserSetting.type == "reddit", UserSetting.setting == "dm_nsfw" - ) - if setting and setting.value: - try: - await ctx.author.send(embeds=embeds) - except Exception: - pass - await ctx.send("Hey! Due to content, I cannot share the result") - else: - await ctx.send(embeds=embeds) - - @reddit.subcommand(sub_cmd_name="random", sub_cmd_description="Get a random post of a subreddit") - @slash_option(name="name", description="Subreddit name", opt_type=OptionType.STRING, required=True) - async def _subreddit_random(self, ctx: InteractionContext, name: str) -> None: - if not sub_name.match(name): - await ctx.send("Invalid Subreddit name", ephemeral=True) - return - try: - await ctx.defer() - subreddit = await self.api.subreddit(name) - await subreddit.load() - except (NotFound, Forbidden, Redirect) as e: - self.logger.debug(f"Subreddit {name} raised {e.__class__.__name__} in random") - await ctx.send("Subreddit may be private, quarantined, or nonexistent.", ephemeral=True) - return - try: - post = await subreddit.random() - except Exception as e: - self.logger.error(f"Failed to get post from {name}", exc_info=e) - await ctx.send("Well, this is awkward. Something went wrong", ephemeral=True) - return - - embeds = await self.post_embeds(subreddit, post) - if post.over_18 and not ctx.channel.nsfw: - setting = await UserSetting.find_one( - UserSetting.user == ctx.author.id, UserSetting.type == "reddit", UserSetting.setting == "dm_nsfw" - ) - if setting and setting.value: - try: - await ctx.author.send(embeds=embeds) - except Exception: - pass - await ctx.send("Hey! Due to content, I cannot share the result") - else: - await ctx.send(embeds=embeds) - - @reddit.subcommand(sub_cmd_name="rising", sub_cmd_description="Get a rising post of a subreddit") - @slash_option(name="name", description="Subreddit name", opt_type=OptionType.STRING, required=True) - async def _subreddit_rising(self, ctx: InteractionContext, name: str) -> None: - if not sub_name.match(name): - await ctx.send("Invalid Subreddit name", ephemeral=True) - return - try: - await ctx.defer() - subreddit = await self.api.subreddit(name) - await subreddit.load() - except (NotFound, Forbidden, Redirect) as e: - self.logger.debug(f"Subreddit {name} raised {e.__class__.__name__} in rising") - await ctx.send("Subreddit may be private, quarantined, or nonexistent.", ephemeral=True) - return - try: - post = [x async for x in subreddit.rising(limit=1)][0] - except Exception as e: - self.logger.error(f"Failed to get post from {name}", exc_info=e) - await ctx.send("Well, this is awkward. Something went wrong", ephemeral=True) - return - - embeds = await self.post_embeds(subreddit, post) - if post.over_18 and not ctx.channel.nsfw: - setting = await UserSetting.find_one( - UserSetting.user == ctx.author.id, UserSetting.type == "reddit", UserSetting.setting == "dm_nsfw" - ) - if setting and setting.value: - try: - await ctx.author.send(embeds=embeds) - except Exception: - pass - await ctx.send("Hey! Due to content, I cannot share the result") - else: - await ctx.send(embeds=embeds) - - @reddit.subcommand(sub_cmd_name="post", sub_cmd_description="Get a specific submission") - @slash_option(name="sid", description="Submission ID", opt_type=OptionType.STRING, required=True) - async def _reddit_post(self, ctx: InteractionContext, sid: str) -> None: - await ctx.defer() - try: - post = await self.api.submission(sid) - await post.load() - except (NotFound, Forbidden, Redirect) as e: - self.logger.debug(f"Submission {sid} raised {e.__class__.__name__} in post") - await ctx.send("Post could not be found.", ephemeral=True) - return - - embeds = await self.post_embeds(post.subreddit, post) - if post.over_18 and not ctx.channel.nsfw: - setting = await UserSetting.find_one( - UserSetting.user == ctx.author.id, UserSetting.type == "reddit", UserSetting.setting == "dm_nsfw" - ) - if setting and setting.value: - try: - await ctx.author.send(embeds=embeds) - except Exception: - pass - await ctx.send("Hey! Due to content, I cannot share the result") - else: - await ctx.send(embeds=embeds) - - @reddit.subcommand(sub_cmd_name="dm_nsfw", sub_cmd_description="DM NSFW posts if channel isn't NSFW") - @slash_option(name="dm", description="Send DM?", opt_type=OptionType.BOOLEAN, required=True) - async def _reddit_dm(self, ctx: InteractionContext, dm: bool) -> None: - setting = await UserSetting.find_one( - UserSetting.user == ctx.author.id, UserSetting.type == "reddit", UserSetting.setting == "dm_nsfw" - ) - if not setting: - setting = UserSetting(user=ctx.author.id, type="reddit", setting="dm_nsfw", value=dm) - setting.value = dm - await setting.save() - await ctx.send(f"Reddit DM NSFW setting is now set to {dm}", ephemeral=True) - - -def setup(bot: Client) -> None: - """Add RedditCog to JARVIS""" - if load_config().reddit: - RedditCog(bot) - else: - bot.logger.info("Missing Reddit configuration, not loading") diff --git a/jarvis/cogs/core/socials/twitter.py b/jarvis/cogs/core/socials/twitter.py deleted file mode 100644 index c5d0cf0..0000000 --- a/jarvis/cogs/core/socials/twitter.py +++ /dev/null @@ -1,246 +0,0 @@ -"""JARVIS Twitter Cog.""" -import asyncio -import logging - -import tweepy -from interactions import Client, Extension, InteractionContext, Permissions -from interactions.client.utils.misc_utils import get -from interactions.models.discord.channel import GuildText -from interactions.models.discord.components import ( - ActionRow, - StringSelectMenu, - StringSelectOption, -) -from interactions.models.internal.application_commands import ( - OptionType, - SlashCommand, - slash_option, -) -from interactions.models.internal.command import check -from jarvis_core.db.models import TwitterAccount, TwitterFollow - -from jarvis.config import load_config -from jarvis.utils.permissions import admin_or_permissions - - -class TwitterCog(Extension): - """JARVIS Twitter Cog.""" - - def __init__(self, bot: Client): - self.bot = bot - self.logger = logging.getLogger(__name__) - config = load_config() - auth = tweepy.AppAuthHandler(config.twitter.consumer_key, config.twitter.consumer_secret) - self.api = tweepy.API(auth) - self._guild_cache = {} - self._channel_cache = {} - - twitter = SlashCommand( - name="twitter", - description="Manage Twitter follows", - ) - - @twitter.subcommand( - sub_cmd_name="follow", - sub_cmd_description="Follow a Twitter acount", - ) - @slash_option(name="handle", description="Twitter account", opt_type=OptionType.STRING, required=True) - @slash_option( - name="channel", - description="Channel to post tweets to", - opt_type=OptionType.CHANNEL, - required=True, - ) - @slash_option( - name="retweets", - description="Mirror re-tweets?", - opt_type=OptionType.BOOLEAN, - required=False, - ) - @check(admin_or_permissions(Permissions.MANAGE_GUILD)) - async def _twitter_follow( - self, ctx: InteractionContext, handle: str, channel: GuildText, retweets: bool = True - ) -> None: - handle = handle.lower() - if len(handle) > 15 or len(handle) < 4: - await ctx.send("Invalid Twitter handle", ephemeral=True) - return - - if not isinstance(channel, GuildText): - await ctx.send("Channel must be a text channel", ephemeral=True) - return - - try: - account = await asyncio.to_thread(self.api.get_user, screen_name=handle) - latest_tweet = (await asyncio.to_thread(self.api.user_timeline, screen_name=handle))[0] - except Exception: - await ctx.send("Unable to get user timeline. Are you sure the handle is correct?", ephemeral=True) - return - - exists = await TwitterFollow.find_one( - TwitterFollow.twitter_id == account.id, TwitterFollow.guild == ctx.guild.id - ) - if exists: - await ctx.send("Twitter account already being followed in this guild", ephemeral=True) - return - - count = await TwitterFollow.find(TwitterFollow.guild == ctx.guild.id).count() - if count >= 12: - await ctx.send("Cannot follow more than 12 Twitter accounts", ephemeral=True) - return - - ta = await TwitterAccount.find_one(TwitterAccount.twitter_id == account.id) - if not ta: - ta = TwitterAccount( - handle=account.screen_name, - twitter_id=account.id, - last_tweet=latest_tweet.id, - ) - await ta.save() - - tf = TwitterFollow( - twitter_id=account.id, - guild=ctx.guild.id, - channel=channel.id, - admin=ctx.author.id, - retweets=retweets, - ) - - await tf.save() - - await ctx.send(f"Now following `@{handle}` in {channel.mention}") - - @twitter.subcommand(sub_cmd_name="unfollow", sub_cmd_description="Unfollow Twitter accounts") - @check(admin_or_permissions(Permissions.MANAGE_GUILD)) - async def _twitter_unfollow(self, ctx: InteractionContext) -> None: - t = TwitterFollow.find(TwitterFollow.guild == ctx.guild.id) - twitters = [] - async for twitter in t: - twitters.append(twitter) - if not twitters: - await ctx.send("You need to follow a Twitter account first", ephemeral=True) - return - - options = [] - handlemap = {} - for twitter in twitters: - account = await TwitterAccount.find_one(TwitterAccount.twitter_id == twitter.twitter_id) - handlemap[str(twitter.twitter_id)] = account.handle - option = StringSelectOption(label=account.handle, value=str(twitter.twitter_id)) - options.append(option) - - select = StringSelectMenu(options=options, custom_id="to_delete", min_values=1, max_values=len(twitters)) - - components = [ActionRow(select)] - block = "\n".join(x for x in handlemap.values()) - message = await ctx.send( - content=f"You are following the following accounts:\n```\n{block}\n```\n\n" - "Please choose accounts to unfollow", - components=components, - ) - - try: - context = await self.bot.wait_for_component( - check=lambda x: ctx.author.id == x.ctx.author.id, - messages=message, - timeout=60 * 5, - ) - for to_delete in context.ctx.values: - follow = get(twitters, guild=ctx.guild.id, twitter_id=int(to_delete)) - try: - await follow.delete() - except Exception: - self.logger.debug("Ignoring deletion error") - for row in components: - for component in row.components: - component.disabled = True - - block = "\n".join(handlemap[x] for x in context.ctx.values) - await context.ctx.edit_origin( - content=f"Unfollowed the following:\n```\n{block}\n```", components=components - ) - except asyncio.TimeoutError: - for row in components: - for component in row.components: - component.disabled = True - await message.edit(components=components) - - @twitter.subcommand( - sub_cmd_name="retweets", - sub_cmd_description="Modify followed Twitter accounts", - ) - @slash_option( - name="retweets", - description="Mirror re-tweets?", - opt_type=OptionType.BOOLEAN, - required=False, - ) - @check(admin_or_permissions(Permissions.MANAGE_GUILD)) - async def _twitter_modify(self, ctx: InteractionContext, retweets: bool = True) -> None: - t = TwitterFollow.find(TwitterFollow.guild == ctx.guild.id) - twitters = [] - async for twitter in t: - twitters.append(twitter) - if not twitters: - await ctx.send("You need to follow a Twitter account first", ephemeral=True) - return - - options = [] - handlemap = {} - for twitter in twitters: - account = await TwitterAccount.find_one(TwitterAccount.twitter_id == twitter.id) - handlemap[str(twitter.twitter_id)] = account.handle - option = StringSelectOption(label=account.handle, value=str(twitter.twitter_id)) - options.append(option) - - select = StringSelectMenu(options=options, custom_id="to_update", min_values=1, max_values=len(twitters)) - - components = [ActionRow(select)] - block = "\n".join(x for x in handlemap.values()) - message = await ctx.send( - content=f"You are following the following accounts:\n```\n{block}\n```\n\n" - f"Please choose which accounts to {'un' if not retweets else ''}follow retweets from", - components=components, - ) - - try: - context = await self.bot.wait_for_component( - check=lambda x: ctx.author.id == x.ctx.author.id, - messages=message, - timeout=60 * 5, - ) - - handlemap = {} - for to_update in context.ctx.values: - account = await TwitterAccount.find_one(TwitterAccount.twitter_id == int(to_update)) - handlemap[str(twitter.twitter_id)] = account.handle - t = get(twitters, guild=ctx.guild.id, twitter_id=int(to_update)) - t.retweets = True - await t.save() - - for row in components: - for component in row.components: - component.disabled = True - - block = "\n".join(handlemap[x] for x in context.ctx.values) - await context.ctx.edit_origin( - content=( - f"{'Unfollowed' if not retweets else 'Followed'} " - "retweets from the following:" - f"\n```\n{block}\n```" - ), - components=components, - ) - except asyncio.TimeoutError: - for row in components: - for component in row.components: - component.disabled = True - await message.edit(components=components) - - -def setup(bot: Client) -> None: - """Add TwitterCog to JARVIS""" - if load_config().twitter: - TwitterCog(bot) - else: - bot.logger.info("No Twitter configuration, not loading") diff --git a/jarvis/cogs/core/util.py b/jarvis/cogs/core/util.py index 73a43ae..b0b6770 100644 --- a/jarvis/cogs/core/util.py +++ b/jarvis/cogs/core/util.py @@ -92,16 +92,35 @@ class UtilCog(Extension): ) ) fields.append( - EmbedField(name="interactions", value=f"[{ipyv}](https://interactionspy.readthedocs.io)", inline=True) + EmbedField( + name="interactions", + value=f"[{ipyv}](https://interactionspy.readthedocs.io)", + inline=True, + ) ) self.bot.logger.debug("Getting repo information") repo_url = f"https://git.zevaryx.com/stark-industries/jarvis/jarvis-bot/-/tree/{get_repo_hash()}" - fields.append(EmbedField(name="Git Hash", value=f"[{get_repo_hash()[:7]}]({repo_url})", inline=True)) - fields.append(EmbedField(name="Online Since", value=f"", inline=False)) + fields.append( + EmbedField( + name="Git Hash", + value=f"[{get_repo_hash()[:7]}]({repo_url})", + inline=True, + ) + ) + fields.append( + EmbedField(name="Online Since", value=f"", inline=False) + ) num_domains = len(self.bot.phishing_domains) - fields.append(EmbedField(name="Phishing Protection", value=f"Detecting {num_domains} phishing domains")) + fields.append( + EmbedField( + name="Phishing Protection", + value=f"Detecting {num_domains} phishing domains", + ) + ) embed = build_embed(title=title, description=desc, fields=fields, color=color) - components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") + components = Button( + style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}" + ) await ctx.send(embeds=embed, components=components) @bot.subcommand( @@ -114,7 +133,11 @@ class UtilCog(Extension): JARVIS_LOGO.save(image_bytes, "PNG") image_bytes.seek(0) logo = File(image_bytes, file_name="logo.png") - components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") + components = Button( + style=ButtonStyle.DANGER, + emoji="🗑️", + custom_id=f"delete|{ctx.author.id}", + ) await ctx.send(file=logo, components=components) rc = SlashCommand(name="rc", description="Robot Camo emoji commands") @@ -159,8 +182,10 @@ class UtilCog(Extension): embed = build_embed(title="Avatar", description="", fields=[], color="#00FFEE") embed.set_image(url=avatar) - embed.set_author(name=f"{user.username}#{user.discriminator}", icon_url=avatar) - components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") + embed.set_author(name=f"{user.username}", icon_url=avatar) + components = Button( + style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}" + ) await ctx.send(embeds=embed, components=components) @slash_command( @@ -179,11 +204,19 @@ class UtilCog(Extension): EmbedField(name="Name", value=role.mention, inline=True), EmbedField(name="Color", value=str(role.color.hex), inline=True), EmbedField(name="Mention", value=f"`{role.mention}`", inline=True), - EmbedField(name="Hoisted", value="Yes" if role.hoist else "No", inline=True), + EmbedField( + name="Hoisted", value="Yes" if role.hoist else "No", inline=True + ), EmbedField(name="Position", value=str(role.position), inline=True), - EmbedField(name="Mentionable", value="Yes" if role.mentionable else "No", inline=True), + EmbedField( + name="Mentionable", + value="Yes" if role.mentionable else "No", + inline=True, + ), EmbedField(name="Member Count", value=str(len(role.members)), inline=True), - EmbedField(name="Created At", value=f""), + EmbedField( + name="Created At", value=f"" + ), ] embed = build_embed( title="", @@ -208,7 +241,11 @@ class UtilCog(Extension): im.save(image_bytes, "PNG") image_bytes.seek(0) color_show = File(image_bytes, file_name="color_show.png") - components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") + components = Button( + style=ButtonStyle.DANGER, + emoji="🗑️", + custom_id=f"delete|{ctx.author.id}", + ) await ctx.send(embeds=embed, file=color_show, components=components) @slash_command(name="avatar", description="Get a user avatar") @@ -252,14 +289,18 @@ class UtilCog(Extension): ), EmbedField( name=f"Roles [{len(user_roles)}]", - value=" ".join([x.mention for x in user_roles]) if user_roles else "None", + value=" ".join([x.mention for x in user_roles]) + if user_roles + else "None", inline=False, ), ] if muted: ts = int(user.communication_disabled_until.timestamp()) - fields.append(EmbedField(name="Muted Until", value=f" ()")) + fields.append( + EmbedField(name="Muted Until", value=f" ()") + ) embed = build_embed( title="", @@ -269,16 +310,23 @@ class UtilCog(Extension): ) embed.set_author( - name=f"{'🔇 ' if muted else ''}{user.display_name}#{user.discriminator}", + name=f"{'🔇 ' if muted else ''}{user.display_name}", icon_url=user.display_avatar.url, ) embed.set_thumbnail(url=user.display_avatar.url) embed.set_footer(text=f"ID: {user.id}") - components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") + components = Button( + style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}" + ) await ctx.send(embeds=embed, components=components) @slash_command(name="lmgtfy", description="Let me Google that for you") - @slash_option(name="search", description="What to search", opt_type=OptionType.STRING, required=True) + @slash_option( + name="search", + description="What to search", + opt_type=OptionType.STRING, + required=True, + ) async def _lmgtfy(self, ctx: SlashContext, search: str) -> None: url = "https://letmegooglethat.com/?q=" + urllib.parse.quote_plus(search) await ctx.send(url) @@ -306,7 +354,7 @@ class UtilCog(Extension): owner = await guild.fetch_owner() - owner = f"{owner.username}#{owner.discriminator}" if owner else "||`[redacted]`||" + owner = f"{owner.username}" if owner else "||`[redacted]`||" categories = len([x for x in guild.channels if isinstance(x, GuildCategory)]) text_channels = len([x for x in guild.channels if isinstance(x, GuildText)]) @@ -325,24 +373,29 @@ class UtilCog(Extension): EmbedField(name="Threads", value=str(threads), inline=True), EmbedField(name="Members", value=str(members), inline=True), EmbedField(name="Roles", value=str(roles), inline=True), - EmbedField(name="Created At", value=f""), + EmbedField( + name="Created At", value=f"" + ), ] if len(role_list) < 1024: fields.append(EmbedField(name="Role List", value=role_list, inline=False)) - embed = build_embed(title="", description="", fields=fields, timestamp=guild.created_at) + embed = build_embed( + title="", description="", fields=fields, timestamp=guild.created_at + ) embed.set_author(name=guild.name, icon_url=guild.icon.url) embed.set_thumbnail(url=guild.icon.url) embed.set_footer(text=f"ID: {guild.id} | Server Created") - components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") + components = Button( + style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}" + ) await ctx.send(embeds=embed, components=components) @slash_command( name="pw", sub_cmd_name="gen", description="Generate a secure password", - scopes=[862402786116763668], ) @slash_option( name="length", @@ -363,7 +416,9 @@ class UtilCog(Extension): ], ) @cooldown(bucket=Buckets.USER, rate=1, interval=15) - async def _pw_gen(self, ctx: SlashContext, length: int = 32, chars: int = 3) -> None: + async def _pw_gen( + self, ctx: SlashContext, length: int = 32, chars: int = 3 + ) -> None: if length > 256: await ctx.send("Please limit password to 256 characters", ephemeral=True) return @@ -384,7 +439,12 @@ class UtilCog(Extension): ) @slash_command(name="pigpen", description="Encode a string into pigpen") - @slash_option(name="text", description="Text to encode", opt_type=OptionType.STRING, required=True) + @slash_option( + name="text", + description="Text to encode", + opt_type=OptionType.STRING, + required=True, + ) async def _pigpen(self, ctx: SlashContext, text: str) -> None: outp = "`" for c in text: @@ -399,17 +459,34 @@ class UtilCog(Extension): outp += "`" await ctx.send(outp[:2000]) - @slash_command(name="timestamp", description="Convert a datetime or timestamp into it's counterpart") - @slash_option(name="string", description="String to convert", opt_type=OptionType.STRING, required=True) - @slash_option(name="private", description="Respond quietly?", opt_type=OptionType.BOOLEAN, required=False) - async def _timestamp(self, ctx: SlashContext, string: str, private: bool = False) -> None: + @slash_command( + name="timestamp", + description="Convert a datetime or timestamp into it's counterpart", + ) + @slash_option( + name="string", + description="String to convert", + opt_type=OptionType.STRING, + required=True, + ) + @slash_option( + name="private", + description="Respond quietly?", + opt_type=OptionType.BOOLEAN, + required=False, + ) + async def _timestamp( + self, ctx: SlashContext, string: str, private: bool = False + ) -> None: timestamp = parse(string) if not timestamp: await ctx.send("Valid time not found, try again", ephemeral=True) return if not timestamp.tzinfo: - timestamp = timestamp.replace(tzinfo=get_localzone()).astimezone(tz=timezone.utc) + timestamp = timestamp.replace(tzinfo=get_localzone()).astimezone( + tz=timezone.utc + ) timestamp_utc = timestamp.astimezone(tz=timezone.utc) @@ -422,8 +499,12 @@ class UtilCog(Extension): EmbedField(name="Relative Time", value=f"\n``"), EmbedField(name="ISO8601", value=timestamp.isoformat()), ] - embed = build_embed(title="Converted Time", description=f"`{string}`", fields=fields) - components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") + embed = build_embed( + title="Converted Time", description=f"`{string}`", fields=fields + ) + components = Button( + style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}" + ) await ctx.send(embeds=embed, ephemeral=private, components=components) @bot.subcommand(sub_cmd_name="support", sub_cmd_description="Got issues?") @@ -438,7 +519,10 @@ We'll help as best we can with whatever issues you encounter. """ ) - @bot.subcommand(sub_cmd_name="privacy_terms", sub_cmd_description="View Privacy and Terms of Use") + @bot.subcommand( + sub_cmd_name="privacy_terms", + sub_cmd_description="View Privacy and Terms of Use", + ) async def _privacy_terms(self, ctx: SlashContext) -> None: await ctx.send( """ diff --git a/jarvis/cogs/extra/calc.py b/jarvis/cogs/extra/calc.py index ac1c1d9..18db39f 100644 --- a/jarvis/cogs/extra/calc.py +++ b/jarvis/cogs/extra/calc.py @@ -1,8 +1,6 @@ """JARVIS Calculator Cog.""" -import json - -from aiohttp import ClientSession from calculator import calculate +from erapi import const from interactions import AutocompleteContext, Client, Extension, InteractionContext from interactions.models.discord.components import Button from interactions.models.discord.embed import Embed, EmbedField @@ -24,39 +22,8 @@ TEMP_CHOICES = ( SlashCommandChoice(name="Kelvin", value=2), ) TEMP_LOOKUP = {0: "F", 1: "C", 2: "K"} -CURRENCIES = ( - "AUD", - "BGN", - "BRL", - "CAD", - "CHF", - "CNY", - "CZK", - "DKK", - "EUR", - "GBP", - "HKD", - "HRK", - "HUF", - "IDR", - "INR", - "ISK", - "JPY", - "KRW", - "MXN", - "MYR", - "NOK", - "NZD", - "PHP", - "PLN", - "RON", - "SEK", - "SGD", - "THB", - "TRY", - "USD", - "ZAR", -) +CURRENCY_BY_NAME = {x["name"]: x["code"] for x in const.VALID_CODES} +CURRENCY_BY_CODE = {x["code"]: x["name"] for x in const.VALID_CODES} class CalcCog(Extension): @@ -67,22 +34,32 @@ class CalcCog(Extension): async def _get_currency_conversion(self, from_: str, to: str) -> int: """Get the conversion rate.""" - async with ClientSession() as session: - async with session.get("https://theforexapi.com/api/latest", params={"base": from_, "symbols": to}) as resp: - raw = await resp.content.read() - data = json.loads(raw.decode("UTF8")) - return data["rates"][to] + return self.bot.erapi.get_conversion_rate(from_, to) calc = SlashCommand(name="calc", description="Calculate some things") - @calc.subcommand(sub_cmd_name="math", sub_cmd_description="Do a basic math calculation") - @slash_option(name="expression", description="Expression to calculate", required=True, opt_type=OptionType.STRING) + @calc.subcommand( + sub_cmd_name="math", sub_cmd_description="Do a basic math calculation" + ) + @slash_option( + name="expression", + description="Expression to calculate", + required=True, + opt_type=OptionType.STRING, + ) async def _calc_math(self, ctx: InteractionContext, expression: str) -> None: if expression == "The answer to life, the universe, and everything": - fields = (EmbedField(name="Expression", value=f"`{expression}`"), EmbedField(name="Result", value=str(42))) + fields = ( + EmbedField(name="Expression", value=f"`{expression}`"), + EmbedField(name="Result", value=str(42)), + ) embed = build_embed(title="Calculator", description=None, fields=fields) - components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") + components = Button( + style=ButtonStyle.DANGER, + emoji="🗑️", + custom_id=f"delete|{ctx.author.id}", + ) await ctx.send(embeds=embed, components=components) return try: @@ -94,21 +71,41 @@ class CalcCog(Extension): await ctx.send("No value? Try a valid expression", ephemeral=True) return - fields = (EmbedField(name="Expression", value=f"`{expression}`"), EmbedField(name="Result", value=str(value))) + fields = ( + EmbedField(name="Expression", value=f"`{expression}`"), + EmbedField(name="Result", value=str(value)), + ) embed = build_embed(title="Calculator", description=None, fields=fields) - components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") + components = Button( + style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}" + ) await ctx.send(embeds=embed, components=components) convert = calc.group(name="convert", description="Conversion helpers") - @convert.subcommand(sub_cmd_name="temperature", sub_cmd_description="Convert between temperatures") - @slash_option(name="value", description="Value to convert", required=True, opt_type=OptionType.NUMBER) - @slash_option( - name="from_unit", description="From unit", required=True, opt_type=OptionType.INTEGER, choices=TEMP_CHOICES + @convert.subcommand( + sub_cmd_name="temperature", sub_cmd_description="Convert between temperatures" ) @slash_option( - name="to_unit", description="To unit", required=True, opt_type=OptionType.INTEGER, choices=TEMP_CHOICES + name="value", + description="Value to convert", + required=True, + opt_type=OptionType.NUMBER, + ) + @slash_option( + name="from_unit", + description="From unit", + required=True, + opt_type=OptionType.INTEGER, + choices=TEMP_CHOICES, + ) + @slash_option( + name="to_unit", + description="To unit", + required=True, + opt_type=OptionType.INTEGER, + choices=TEMP_CHOICES, ) async def _calc_convert_temperature( self, ctx: InteractionContext, value: int, from_unit: int, to_unit: int @@ -139,11 +136,21 @@ class CalcCog(Extension): description=f"°{TEMP_LOOKUP.get(from_unit)} -> °{TEMP_LOOKUP.get(to_unit)}", fields=fields, ) - components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") + components = Button( + style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}" + ) await ctx.send(embeds=embed, components=components) - @convert.subcommand(sub_cmd_name="currency", sub_cmd_description="Convert currency based on current rates") - @slash_option(name="value", description="Value of starting currency", required=True, opt_type=OptionType.NUMBER) + @convert.subcommand( + sub_cmd_name="currency", + sub_cmd_description="Convert currency based on current rates", + ) + @slash_option( + name="value", + description="Value of starting currency", + required=True, + opt_type=OptionType.NUMBER, + ) @slash_option( name="from_currency", description="Currency to convert from", @@ -168,27 +175,58 @@ class CalcCog(Extension): conv = value * rate fields = ( - EmbedField(name="Conversion Rate", value=f"1 {from_currency} ~= {rate:0.4f} {to_currency}"), - EmbedField(name=from_currency, value=f"{value:0.2f}"), - EmbedField(name=to_currency, value=f"{conv:0.2f}"), + EmbedField( + name="Conversion Rate", + value=f"1 {from_currency} ~= {rate:0.4f} {to_currency}", + ), + EmbedField( + name=f"{CURRENCY_BY_CODE[from_currency]} ({from_currency})", + value=f"{value:0.2f}", + ), + EmbedField( + name=f"{CURRENCY_BY_CODE[to_currency]} ({to_currency})", + value=f"{conv:0.2f}", + ), ) - embed = build_embed(title="Conversion", description=f"{from_currency} -> {to_currency}", fields=fields) - components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") + embed = build_embed( + title="Conversion", + description=f"{from_currency} -> {to_currency}", + fields=fields, + ) + components = Button( + style=ButtonStyle.DANGER, + emoji="🗑️", + custom_id=f"delete|{ctx.author.id}", + ) await ctx.send(embeds=embed, components=components) - async def _convert(self, ctx: InteractionContext, from_: str, to: str, value: int) -> Embed: + async def _convert( + self, ctx: InteractionContext, from_: str, to: str, value: int + ) -> Embed: *_, which = ctx.invoke_target.split(" ") which = getattr(units, which.capitalize(), None) ratio = which.get_rate(from_, to) converted = value / ratio - fields = (EmbedField(name=from_, value=f"{value:0.2f}"), EmbedField(name=to, value=f"{converted:0.2f}")) - embed = build_embed(title="Conversion", description=f"{from_} -> {to}", fields=fields) - components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") + fields = ( + EmbedField(name=from_, value=f"{value:0.2f}"), + EmbedField(name=to, value=f"{converted:0.2f}"), + ) + embed = build_embed( + title="Conversion", description=f"{from_} -> {to}", fields=fields + ) + components = Button( + style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}" + ) await ctx.send(embeds=embed, components=components) @convert.subcommand(sub_cmd_name="angle", sub_cmd_description="Convert angles") - @slash_option(name="value", description="Angle to convert", opt_type=OptionType.NUMBER, required=True) + @slash_option( + name="value", + description="Angle to convert", + opt_type=OptionType.NUMBER, + required=True, + ) @slash_option( name="from_unit", description="Units to convert from", @@ -197,13 +235,24 @@ class CalcCog(Extension): autocomplete=True, ) @slash_option( - name="to_unit", description="Units to convert to", opt_type=OptionType.STRING, required=True, autocomplete=True + name="to_unit", + description="Units to convert to", + opt_type=OptionType.STRING, + required=True, + autocomplete=True, ) - async def _calc_convert_angle(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None: + async def _calc_convert_angle( + self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str + ) -> None: await self._convert(ctx, from_unit, to_unit, value) @convert.subcommand(sub_cmd_name="area", sub_cmd_description="Convert areas") - @slash_option(name="value", description="Area to convert", opt_type=OptionType.NUMBER, required=True) + @slash_option( + name="value", + description="Area to convert", + opt_type=OptionType.NUMBER, + required=True, + ) @slash_option( name="from_unit", description="Units to convert from", @@ -212,13 +261,24 @@ class CalcCog(Extension): autocomplete=True, ) @slash_option( - name="to_unit", description="Units to convert to", opt_type=OptionType.STRING, required=True, autocomplete=True + name="to_unit", + description="Units to convert to", + opt_type=OptionType.STRING, + required=True, + autocomplete=True, ) - async def _calc_convert_area(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None: + async def _calc_convert_area( + self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str + ) -> None: await self._convert(ctx, from_unit, to_unit, value) @convert.subcommand(sub_cmd_name="data", sub_cmd_description="Convert data sizes") - @slash_option(name="value", description="Data size to convert", opt_type=OptionType.NUMBER, required=True) + @slash_option( + name="value", + description="Data size to convert", + opt_type=OptionType.NUMBER, + required=True, + ) @slash_option( name="from_unit", description="Units to convert from", @@ -227,13 +287,24 @@ class CalcCog(Extension): autocomplete=True, ) @slash_option( - name="to_unit", description="Units to convert to", opt_type=OptionType.STRING, required=True, autocomplete=True + name="to_unit", + description="Units to convert to", + opt_type=OptionType.STRING, + required=True, + autocomplete=True, ) - async def _calc_convert_data(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None: + async def _calc_convert_data( + self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str + ) -> None: await self._convert(ctx, from_unit, to_unit, value) @convert.subcommand(sub_cmd_name="energy", sub_cmd_description="Convert energy") - @slash_option(name="value", description="Energy to convert", opt_type=OptionType.NUMBER, required=True) + @slash_option( + name="value", + description="Energy to convert", + opt_type=OptionType.NUMBER, + required=True, + ) @slash_option( name="from_unit", description="Units to convert from", @@ -242,13 +313,24 @@ class CalcCog(Extension): autocomplete=True, ) @slash_option( - name="to_unit", description="Units to convert to", opt_type=OptionType.STRING, required=True, autocomplete=True + name="to_unit", + description="Units to convert to", + opt_type=OptionType.STRING, + required=True, + autocomplete=True, ) - async def _calc_convert_energy(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None: + async def _calc_convert_energy( + self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str + ) -> None: await self._convert(ctx, from_unit, to_unit, value) @convert.subcommand(sub_cmd_name="length", sub_cmd_description="Convert lengths") - @slash_option(name="value", description="Length to convert", opt_type=OptionType.NUMBER, required=True) + @slash_option( + name="value", + description="Length to convert", + opt_type=OptionType.NUMBER, + required=True, + ) @slash_option( name="from_unit", description="Units to convert from", @@ -257,13 +339,24 @@ class CalcCog(Extension): autocomplete=True, ) @slash_option( - name="to_unit", description="Units to convert to", opt_type=OptionType.STRING, required=True, autocomplete=True + name="to_unit", + description="Units to convert to", + opt_type=OptionType.STRING, + required=True, + autocomplete=True, ) - async def _calc_convert_length(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None: + async def _calc_convert_length( + self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str + ) -> None: await self._convert(ctx, from_unit, to_unit, value) @convert.subcommand(sub_cmd_name="power", sub_cmd_description="Convert powers") - @slash_option(name="value", description="Power to convert", opt_type=OptionType.NUMBER, required=True) + @slash_option( + name="value", + description="Power to convert", + opt_type=OptionType.NUMBER, + required=True, + ) @slash_option( name="from_unit", description="Units to convert from", @@ -272,13 +365,26 @@ class CalcCog(Extension): autocomplete=True, ) @slash_option( - name="to_unit", description="Units to convert to", opt_type=OptionType.STRING, required=True, autocomplete=True + name="to_unit", + description="Units to convert to", + opt_type=OptionType.STRING, + required=True, + autocomplete=True, ) - async def _calc_convert_power(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None: + async def _calc_convert_power( + self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str + ) -> None: await self._convert(ctx, from_unit, to_unit, value) - @convert.subcommand(sub_cmd_name="pressure", sub_cmd_description="Convert pressures") - @slash_option(name="value", description="Pressure to convert", opt_type=OptionType.NUMBER, required=True) + @convert.subcommand( + sub_cmd_name="pressure", sub_cmd_description="Convert pressures" + ) + @slash_option( + name="value", + description="Pressure to convert", + opt_type=OptionType.NUMBER, + required=True, + ) @slash_option( name="from_unit", description="Units to convert from", @@ -287,13 +393,24 @@ class CalcCog(Extension): autocomplete=True, ) @slash_option( - name="to_unit", description="Units to convert to", opt_type=OptionType.STRING, required=True, autocomplete=True + name="to_unit", + description="Units to convert to", + opt_type=OptionType.STRING, + required=True, + autocomplete=True, ) - async def _calc_convert_pressure(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None: + async def _calc_convert_pressure( + self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str + ) -> None: await self._convert(ctx, from_unit, to_unit, value) @convert.subcommand(sub_cmd_name="speed", sub_cmd_description="Convert speeds") - @slash_option(name="value", description="Speed to convert", opt_type=OptionType.NUMBER, required=True) + @slash_option( + name="value", + description="Speed to convert", + opt_type=OptionType.NUMBER, + required=True, + ) @slash_option( name="from_unit", description="Units to convert from", @@ -302,13 +419,24 @@ class CalcCog(Extension): autocomplete=True, ) @slash_option( - name="to_unit", description="Units to convert to", opt_type=OptionType.STRING, required=True, autocomplete=True + name="to_unit", + description="Units to convert to", + opt_type=OptionType.STRING, + required=True, + autocomplete=True, ) - async def _calc_convert_speed(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None: + async def _calc_convert_speed( + self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str + ) -> None: await self._convert(ctx, from_unit, to_unit, value) @convert.subcommand(sub_cmd_name="time", sub_cmd_description="Convert times") - @slash_option(name="value", description="Time to convert", opt_type=OptionType.NUMBER, required=True) + @slash_option( + name="value", + description="Time to convert", + opt_type=OptionType.NUMBER, + required=True, + ) @slash_option( name="from_unit", description="Units to convert from", @@ -317,13 +445,24 @@ class CalcCog(Extension): autocomplete=True, ) @slash_option( - name="to_unit", description="Units to convert to", opt_type=OptionType.STRING, required=True, autocomplete=True + name="to_unit", + description="Units to convert to", + opt_type=OptionType.STRING, + required=True, + autocomplete=True, ) - async def _calc_convert_time(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None: + async def _calc_convert_time( + self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str + ) -> None: await self._convert(ctx, from_unit, to_unit, value) @convert.subcommand(sub_cmd_name="volume", sub_cmd_description="Convert volumes") - @slash_option(name="value", description="Volume to convert", opt_type=OptionType.NUMBER, required=True) + @slash_option( + name="value", + description="Volume to convert", + opt_type=OptionType.NUMBER, + required=True, + ) @slash_option( name="from_unit", description="Units to convert from", @@ -332,13 +471,24 @@ class CalcCog(Extension): autocomplete=True, ) @slash_option( - name="to_unit", description="Units to convert to", opt_type=OptionType.STRING, required=True, autocomplete=True + name="to_unit", + description="Units to convert to", + opt_type=OptionType.STRING, + required=True, + autocomplete=True, ) - async def _calc_convert_volume(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None: + async def _calc_convert_volume( + self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str + ) -> None: await self._convert(ctx, from_unit, to_unit, value) @convert.subcommand(sub_cmd_name="weight", sub_cmd_description="Convert weights") - @slash_option(name="value", description="Weight to convert", opt_type=OptionType.NUMBER, required=True) + @slash_option( + name="value", + description="Weight to convert", + opt_type=OptionType.NUMBER, + required=True, + ) @slash_option( name="from_unit", description="Units to convert from", @@ -347,12 +497,20 @@ class CalcCog(Extension): autocomplete=True, ) @slash_option( - name="to_unit", description="Units to convert to", opt_type=OptionType.STRING, required=True, autocomplete=True + name="to_unit", + description="Units to convert to", + opt_type=OptionType.STRING, + required=True, + autocomplete=True, ) - async def _calc_convert_weight(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None: + async def _calc_convert_weight( + self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str + ) -> None: await self._convert(ctx, from_unit, to_unit, value) - def _unit_autocomplete(self, which: units.Converter, unit: str) -> list[dict[str, str]]: + def _unit_autocomplete( + self, which: units.Converter, unit: str + ) -> list[dict[str, str]]: options = list(which.CONVERSIONS.keys()) results = process.extract(unit, options, limit=25) if any([r[1] > 0 for r in results]): @@ -392,10 +550,24 @@ class CalcCog(Extension): await ctx.send(choices=self._unit_autocomplete(which, ctx.input_text)) def _currency_autocomplete(self, currency: str) -> list[dict[str, str]]: - results = process.extract(currency, CURRENCIES, limit=25) + lookup_name = {f"{k} ({v})": v for k, v in CURRENCY_BY_NAME.items()} + lookup_value = {v: k for k, v in lookup_name.items()} + results_name = process.extract(currency, list(lookup_name.keys()), limit=25) + results_value = process.extract(currency, list(lookup_value.keys()), limit=25) + results = {} + for r in results_value + results_name: + name = r[0] + if len(name) == 3: + name = lookup_value[name] + if name not in results: + results[name] = r[1] + if r[1] > results[name]: + results[name] = r[1] + + results = sorted(list(results.items()), key=lambda x: -x[1])[:10] if any([r[1] > 0 for r in results]): - return [{"name": r[0], "value": r[0]} for r in results if r[1] > 50] - return [{"name": r[0], "value": r[0]} for r in results] + return [{"name": r[0], "value": lookup_name[r[0]]} for r in results if r[1]] + return [{"name": r[0], "value": lookup_name[r[0]]} for r in results] @_calc_convert_currency.autocomplete("from_currency") async def _autocomplete_from_currency(self, ctx: AutocompleteContext) -> None: diff --git a/jarvis/cogs/extra/dev.py b/jarvis/cogs/extra/dev.py index 55180c1..e82eba9 100644 --- a/jarvis/cogs/extra/dev.py +++ b/jarvis/cogs/extra/dev.py @@ -5,14 +5,17 @@ import logging import re import subprocess # noqa: S404 import uuid as uuidpy +from datetime import datetime from io import BytesIO import nanoid +import pytz import ulid as ulidpy from aiofile import AIOFile from ansitoimg.render import ansiToRender from bson import ObjectId -from interactions import Client, Extension, InteractionContext +from croniter import croniter +from interactions import Client, Extension, InteractionContext, AutocompleteContext from interactions.models.discord.components import Button from interactions.models.discord.embed import EmbedField from interactions.models.discord.enums import ButtonStyle @@ -30,13 +33,16 @@ from jarvis_core.filters import invites, url from jarvis_core.util import convert_bytesize, hash from jarvis_core.util.http import get_size from rich.console import Console +from thefuzz import process from jarvis.utils import build_embed supported_hashes = {x for x in hashlib.algorithms_guaranteed if "shake" not in x} OID_VERIFY = re.compile(r"^([1-9][0-9]{0,3}|0)(\.([1-9][0-9]{0,3}|0)){5,13}$") -URL_VERIFY = re.compile(r"http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+") +URL_VERIFY = re.compile( + r"http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+" +) DN_VERIFY = re.compile( r"^(?:(?PCN=(?P[^,]*)),)?(?:(?P(?:(?:CN|OU)=[^,]+,?)+),)?(?P(?:DC=[^,]+,?)+)$" # noqa: E501 ) @@ -60,6 +66,42 @@ class DevCog(Extension): dev = SlashCommand(name="dev", description="Developer utilities") + @dev.subcommand(sub_cmd_name="cron", sub_cmd_description="Test cron strings") + @slash_option( + name="cron", + description="Cron pattern", + opt_type=OptionType.STRING, + required=True, + ) + @slash_option( + name="timezone", + description="Timezone", + opt_type=OptionType.STRING, + required=False, + autocomplete=True, + ) + async def _dev_cron(self, ctx: InteractionContext, cron: str, timezone="utc"): + try: + if not croniter.is_valid(cron): + await ctx.defer(ephemeral=True) + await ctx.send(f"Invalid cron pattern: `{cron}`", ephemeral=True) + return + base = datetime.now(tz=pytz.timezone(timezone)) + parsed = croniter(cron, base) + next_5 = [parsed.get_next() for _ in range(5)] + + next_5_str = "\n".join(f" ()" for x in next_5) + + embed = build_embed( + title="Cron", + description=f"Pattern: `{cron}`\n\nNext 5 runs:\n{next_5_str}\n\nTimezone: `{timezone}`", + fields=[], + ) + + await ctx.send(embeds=[embed]) + except Exception: + self.logger.error("Encountered error", exc_info=True) + @dev.subcommand(sub_cmd_name="hash", sub_cmd_description="Hash some data") @slash_option( name="method", @@ -74,9 +116,20 @@ class DevCog(Extension): opt_type=OptionType.STRING, required=False, ) - @slash_option(name="attach", description="File to hash", opt_type=OptionType.ATTACHMENT, required=False) + @slash_option( + name="attach", + description="File to hash", + opt_type=OptionType.ATTACHMENT, + required=False, + ) @cooldown(bucket=Buckets.USER, rate=1, interval=2) - async def _hash(self, ctx: InteractionContext, method: str, data: str = None, attach: Attachment = None) -> None: + async def _hash( + self, + ctx: InteractionContext, + method: str, + data: str = None, + attach: Attachment = None, + ) -> None: if not data and not attach: await ctx.send( "No data to hash", @@ -93,8 +146,12 @@ class DevCog(Extension): elif url.match(data): try: if (size := await get_size(data)) > MAX_FILESIZE: - await ctx.send("Please hash files that are <= 5GB in size", ephemeral=True) - self.logger.debug(f"Refused to hash file of size {convert_bytesize(size)}") + await ctx.send( + "Please hash files that are <= 5GB in size", ephemeral=True + ) + self.logger.debug( + f"Refused to hash file of size {convert_bytesize(size)}" + ) return except Exception as e: await ctx.send(f"Failed to retrieve URL: ```\n{e}\n```", ephemeral=True) @@ -117,7 +174,9 @@ class DevCog(Extension): ] embed = build_embed(title=title, description=description, fields=fields) - components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") + components = Button( + style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}" + ) await ctx.send(embeds=embed, components=components) @dev.subcommand(sub_cmd_name="uuid", sub_cmd_description="Generate a UUID") @@ -134,7 +193,9 @@ class DevCog(Extension): opt_type=OptionType.STRING, required=False, ) - async def _uuid(self, ctx: InteractionContext, version: str, data: str = None) -> None: + async def _uuid( + self, ctx: InteractionContext, version: str, data: str = None + ) -> None: version = int(version) if version in [3, 5] and not data: await ctx.send(f"UUID{version} requires data.", ephemeral=True) @@ -173,7 +234,12 @@ class DevCog(Extension): sub_cmd_name="uuid2ulid", sub_cmd_description="Convert a UUID to a ULID", ) - @slash_option(name="uuid", description="UUID to convert", opt_type=OptionType.STRING, required=True) + @slash_option( + name="uuid", + description="UUID to convert", + opt_type=OptionType.STRING, + required=True, + ) @cooldown(bucket=Buckets.USER, rate=1, interval=2) async def _uuid2ulid(self, ctx: InteractionContext, uuid: str) -> None: if UUID_VERIFY.match(uuid): @@ -186,7 +252,12 @@ class DevCog(Extension): sub_cmd_name="ulid2uuid", sub_cmd_description="Convert a ULID to a UUID", ) - @slash_option(name="ulid", description="ULID to convert", opt_type=OptionType.STRING, required=True) + @slash_option( + name="ulid", + description="ULID to convert", + opt_type=OptionType.STRING, + required=True, + ) @cooldown(bucket=Buckets.USER, rate=1, interval=2) async def _ulid2uuid(self, ctx: InteractionContext, ulid: str) -> None: if ULID_VERIFY.match(ulid): @@ -230,7 +301,9 @@ class DevCog(Extension): EmbedField(name=mstr, value=f"`{encoded}`", inline=False), ] embed = build_embed(title="Encoded Data", description="", fields=fields) - components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") + components = Button( + style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}" + ) await ctx.send(embeds=embed, components=components) @dev.subcommand(sub_cmd_name="decode", sub_cmd_description="Decode some data") @@ -266,14 +339,18 @@ class DevCog(Extension): EmbedField(name=mstr, value=f"`{decoded}`", inline=False), ] embed = build_embed(title="Decoded Data", description="", fields=fields) - components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") + components = Button( + style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}" + ) await ctx.send(embeds=embed, components=components) @dev.subcommand(sub_cmd_name="cloc", sub_cmd_description="Get JARVIS lines of code") @cooldown(bucket=Buckets.CHANNEL, rate=1, interval=30) async def _cloc(self, ctx: InteractionContext) -> None: await ctx.defer() - output = subprocess.check_output(["tokei", "-C", "--sort", "code"]).decode("UTF-8") # noqa: S603, S607 + output = subprocess.check_output(["tokei", "-C", "--sort", "code"]).decode( + "UTF-8" + ) # noqa: S603, S607 console = Console() with console.capture() as capture: console.print(output) @@ -290,6 +367,12 @@ class DevCog(Extension): tokei = File(file_bytes, file_name="tokei.png") await ctx.send(file=tokei) + @_dev_cron.autocomplete("timezone") + async def _timezone_autocomplete(self, ctx: AutocompleteContext): + results = process.extract(ctx.input_text, pytz.all_timezones_set, limit=5) + choices = [{"name": r[0], "value": r[0]} for r in results if r[1] > 80.0] + await ctx.send(choices) + def setup(bot: Client) -> None: """Add DevCog to JARVIS""" diff --git a/jarvis/cogs/extra/pinboard.py b/jarvis/cogs/extra/pinboard.py index 7f679e9..bb8cbd9 100644 --- a/jarvis/cogs/extra/pinboard.py +++ b/jarvis/cogs/extra/pinboard.py @@ -44,7 +44,9 @@ class PinboardCog(Extension): async def _purge_starboard(self, ctx: InteractionContext, board: Pinboard) -> None: channel = await ctx.guild.fetch_channel(board.channel) - async for pin in Pin.find(Pin.pinboard == channel.id, Pin.guild == ctx.guild.id): + async for pin in Pin.find( + Pin.pinboard == channel.id, Pin.guild == ctx.guild.id + ): if message := await channel.fetch_message(pin.message): try: await message.delete() @@ -89,9 +91,13 @@ class PinboardCog(Extension): await ctx.send("Channel must be a GuildText", ephemeral=True) return - exists = await Pinboard.find_one(Pinboard.channel == channel.id, Pinboard.guild == ctx.guild.id) + exists = await Pinboard.find_one( + Pinboard.channel == channel.id, Pinboard.guild == ctx.guild.id + ) if exists: - await ctx.send(f"Pinboard already exists at {channel.mention}.", ephemeral=True) + await ctx.send( + f"Pinboard already exists at {channel.mention}.", ephemeral=True + ) return count = await Pinboard.find(Pinboard.guild == ctx.guild.id).count() @@ -115,7 +121,9 @@ class PinboardCog(Extension): ) @check(admin_or_permissions(Permissions.MANAGE_GUILD, Permissions.MANAGE_MESSAGES)) async def _delete(self, ctx: InteractionContext, channel: GuildText) -> None: - found = await Pinboard.find_one(Pinboard.channel == channel.id, Pinboard.guild == ctx.guild.id) + found = await Pinboard.find_one( + Pinboard.channel == channel.id, Pinboard.guild == ctx.guild.id + ) if found: await found.delete() asyncio.create_task(self._purge_starboard(ctx, found)) @@ -129,128 +137,147 @@ class PinboardCog(Extension): message: str, channel: GuildText = None, ) -> None: - if not channel: - channel = ctx.channel - pinboards = await Pinboard.find(Pinboard.guild == ctx.guild.id).to_list() - if not pinboards: - await ctx.send("No pinboards exist.", ephemeral=True) - return - - await ctx.defer() - - if not isinstance(message, Message): - if message.startswith("https://"): - message = message.split("/")[-1] - message = await channel.fetch_message(int(message)) - - if not message: - await ctx.send("Message not found", ephemeral=True) + try: + if not channel: + channel = ctx.channel + pinboards = await Pinboard.find(Pinboard.guild == ctx.guild.id).to_list() + if not pinboards: + await ctx.send("No pinboards exist.", ephemeral=True) return - channel_list = [] - to_delete: list[Pinboard] = [] + await ctx.defer() - for pinboard in pinboards: - c = await ctx.guild.fetch_channel(pinboard.channel) - if c and isinstance(c, GuildText): - channel_list.append(c) - else: - self.logger.warning(f"Pinboard {pinboard.channel} no longer valid in {ctx.guild.name}") - to_delete.append(pinboard) + if not isinstance(message, Message): + if message.startswith("https://"): + message = message.split("/")[-1] + message = await channel.fetch_message(int(message)) - for pinboard in to_delete: - try: - await pinboard.delete() - except Exception: - self.logger.debug("Ignoring deletion error") + if not message: + await ctx.send("Message not found", ephemeral=True) + return - select_channels = [] - for idx, x in enumerate(channel_list): - if x: - select_channels.append(StringSelectOption(label=x.name, value=str(idx))) + channel_list = [] + to_delete: list[Pinboard] = [] - select_channels = [StringSelectOption(label=x.name, value=str(idx)) for idx, x in enumerate(channel_list)] + channel_to_pinboard = {} - select = StringSelectMenu( - options=select_channels, - min_values=1, - max_values=1, - ) + for pinboard in pinboards: + c = await ctx.guild.fetch_channel(pinboard.channel) + if c and isinstance(c, GuildText): + channel_list.append(c) + channel_to_pinboard[c.id] = pinboard + else: + self.logger.warning( + f"Pinboard {pinboard.channel} no longer valid in {ctx.guild.name}" + ) + to_delete.append(pinboard) - components = [ActionRow(select)] + for pinboard in to_delete: + try: + await pinboard.delete() + except Exception: + self.logger.debug("Ignoring deletion error") - msg = await ctx.send(content="Choose a pinboard", components=components) + select_channels = [] + for idx, x in enumerate(channel_list): + if x: + select_channels.append( + StringSelectOption(label=x.name, value=str(idx)) + ) - com_ctx = await self.bot.wait_for_component( - messages=msg, - components=components, - check=lambda x: ctx.author.id == x.context.author.id, - ) + select_channels = [ + StringSelectOption(label=x.name, value=str(idx)) + for idx, x in enumerate(channel_list) + ] - pinboard = channel_list[int(com_ctx.context.values[0])] - - exists = await Pin.find_one( - Pin.message == message.id, - Pin.channel == channel.id, - Pin.guild == ctx.guild.id, - Pin.pinboard == pinboard.id, - ) - - if exists: - await ctx.send( - f"Message already sent to Pinboard {pinboard.mention}", - ephemeral=True, + select = StringSelectMenu( + *select_channels, + min_values=1, + max_values=1, ) - return - count = await Pin.find(Pin.guild == ctx.guild.id, Pin.pinboard == pinboard.id).count() - content = message.content + components = [ActionRow(select)] - attachments = message.attachments - image_url = None - if attachments: - for attachment in attachments: - if attachment.content_type in supported_images: - image_url = attachment.url - break - if not content and image_url: - content = "\u200b" + msg = await ctx.send(content="Choose a pinboard", components=components) - embed = build_embed( - title=f"[#{count}] Click Here to view context", - description=content, - fields=[], - url=message.jump_url, - timestamp=message.created_at, - ) - embed.set_author( - name=message.author.display_name, - url=message.jump_url, - icon_url=message.author.avatar.url, - ) - embed.set_footer(text=ctx.guild.name + " | " + channel.name) - if image_url: - embed.set_image(url=image_url) - star_components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") - pin = await pinboard.send(embeds=embed, components=star_components) + com_ctx = await self.bot.wait_for_component( + messages=msg, + components=components, + check=lambda x: ctx.author.id == x.ctx.author.id, + ) - await Pin( - index=count, - message=message.id, - channel=channel.id, - guild=ctx.guild.id, - pinboard=pinboard.id, - admin=ctx.author.id, - pin=pin.id, - active=True, - ).save() + pinboard = channel_list[int(com_ctx.ctx.values[0])] - components[0].components[0].disabled = True + exists = await Pin.find_one( + Pin.message == int(message.id), + Pin.channel == int(channel.id), + Pin.guild == int(ctx.guild.id), + Pin.pinboard == int(pinboard.id), + ) - await com_ctx.context.edit_origin( - content=f"Message saved to Pinboard.\nSee it in {pinboard.mention}", - components=components, - ) + if exists: + await ctx.send( + f"Message already sent to Pinboard {pinboard.mention}", + ephemeral=True, + ) + return + + count = await Pin.find( + Pin.guild == ctx.guild.id, Pin.pinboard == pinboard.id + ).count() + content = message.content + + attachments = message.attachments + image_url = None + if attachments: + for attachment in attachments: + if attachment.content_type in supported_images: + image_url = attachment.url + break + if not content and image_url: + content = "\u200b" + + embed = build_embed( + title=f"[#{count}] Click Here to view context", + description=content, + fields=[], + url=message.jump_url, + timestamp=message.created_at, + ) + embed.set_author( + name=message.author.display_name, + url=message.jump_url, + icon_url=message.author.avatar.url, + ) + embed.set_footer(text=ctx.guild.name + " | " + channel.name) + if image_url: + embed.set_image(url=image_url) + star_components = Button( + style=ButtonStyle.DANGER, + emoji="🗑️", + custom_id=f"delete|{ctx.author.id}", + ) + pin = await pinboard.send(embeds=embed, components=star_components) + + await Pin( + index=count, + message=int(message.id), + channel=int(channel.id), + guild=int(ctx.guild.id), + pinboard=channel_to_pinboard[pinboard.id], + admin=int(ctx.author.id), + pin=int(pin.id), + active=True, + ).save() + + components[0].components[0].disabled = True + + await com_ctx.ctx.edit_origin( + content=f"Message saved to Pinboard.\nSee it in {pinboard.mention}", + components=components, + ) + except: + self.bot.logger.error("E", exc_info=True) @context_menu(name="Pin Message", context_type=CommandType.MESSAGE) @check(admin_or_permissions(Permissions.MANAGE_GUILD, Permissions.MANAGE_MESSAGES)) diff --git a/jarvis/cogs/extra/rolegiver.py b/jarvis/cogs/extra/rolegiver.py index db10b2d..a4cfaf1 100644 --- a/jarvis/cogs/extra/rolegiver.py +++ b/jarvis/cogs/extra/rolegiver.py @@ -64,13 +64,17 @@ class RolegiverCog(Extension): rolegiver.roles = roles await rolegiver.save() - rolegiver = SlashCommand(name="rolegiver", description="Allow users to choose their own roles") + rolegiver = SlashCommand( + name="rolegiver", description="Allow users to choose their own roles" + ) @rolegiver.subcommand( sub_cmd_name="add", sub_cmd_description="Add a role to rolegiver", ) - @slash_option(name="role", description="Role to add", opt_type=OptionType.ROLE, required=True) + @slash_option( + name="role", description="Role to add", opt_type=OptionType.ROLE, required=True + ) @check(admin_or_permissions(Permissions.MANAGE_GUILD)) async def _rolegiver_add(self, ctx: InteractionContext, role: Role) -> None: if role.id == ctx.guild.id: @@ -122,15 +126,19 @@ class RolegiverCog(Extension): embed.set_thumbnail(url=ctx.guild.icon.url) - embed.set_footer(text=f"{ctx.author.username}#{ctx.author.discriminator} | {ctx.author.id}") - components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") + embed.set_footer(text=f"{ctx.author.username} | {ctx.author.id}") + components = Button( + style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}" + ) await ctx.send(embeds=embed, components=components) if ctx.guild.id not in self.cache: self.cache[ctx.guild.id] = {} self.cache[ctx.guild.id][role.name] = role.id - @rolegiver.subcommand(sub_cmd_name="remove", sub_cmd_description="Remove a role from rolegiver") + @rolegiver.subcommand( + sub_cmd_name="remove", sub_cmd_description="Remove a role from rolegiver" + ) @slash_option( name="role", description="Name of role to add", @@ -149,7 +157,9 @@ class RolegiverCog(Extension): if cache: role_id = cache.get(role) else: - await ctx.send("Something went wrong, please try a different role", ephemeral=True) + await ctx.send( + "Something went wrong, please try a different role", ephemeral=True + ) return setting.value.remove(role_id) @@ -171,14 +181,21 @@ class RolegiverCog(Extension): fields = [ EmbedField(name="Removed Role", value=role.mention), - EmbedField(name="Remaining Role(s)", value="\n".join([x.mention for x in remaining])), + EmbedField( + name="Remaining Role(s)", + value="\n".join([x.mention for x in remaining]), + ), ] - embed = build_embed(title="Rolegiver Updated", description="Role removed from rolegiver", fields=fields) + embed = build_embed( + title="Rolegiver Updated", + description="Role removed from rolegiver", + fields=fields, + ) embed.set_thumbnail(url=ctx.guild.icon.url) - embed.set_footer(text=f"{ctx.author.username}#{ctx.author.discriminator} | {ctx.author.id}") + embed.set_footer(text=f"{ctx.author.username} | {ctx.author.id}") await ctx.send( embeds=embed, @@ -187,7 +204,9 @@ class RolegiverCog(Extension): if ctx.guild.id in self.cache: self.cache[ctx.guild.id].pop(role.name) - @rolegiver.subcommand(sub_cmd_name="list", sub_cmd_description="List rolegiver roles") + @rolegiver.subcommand( + sub_cmd_name="list", sub_cmd_description="List rolegiver roles" + ) async def _rolegiver_list(self, ctx: InteractionContext) -> None: setting = await Rolegiver.find_one(Rolegiver.guild == ctx.guild.id) if not setting or (setting and not setting.roles): @@ -214,34 +233,40 @@ class RolegiverCog(Extension): embed.set_thumbnail(url=ctx.guild.icon.url) - embed.set_footer(text=f"{ctx.author.username}#{ctx.author.discriminator} | {ctx.author.id}") - components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") + embed.set_footer(text=f"{ctx.author.username} | {ctx.author.id}") + components = Button( + style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}" + ) await ctx.send(embeds=embed, components=components) @rolegiver.subcommand(sub_cmd_name="get", sub_cmd_description="Get a role") @cooldown(bucket=Buckets.USER, rate=1, interval=10) async def _role_get(self, ctx: InteractionContext) -> None: - setting = await Rolegiver.find_one(Rolegiver.quild == ctx.guild.id) - if not setting or (setting and not setting.roles): - await ctx.send("Rolegiver has no roles", ephemeral=True) + try: + setting = await Rolegiver.find_one(Rolegiver.guild == ctx.guild.id) + if not setting or (setting and not setting.roles): + await ctx.send("Rolegiver has no roles", ephemeral=True) + return + + options = [] + for role in setting.roles: + role: Role = await ctx.guild.fetch_role(role) + option = StringSelectOption(label=role.name, value=str(role.id)) + options.append(option) + + select = StringSelectMenu( + *options, + placeholder="Select roles to add", + min_values=1, + max_values=len(options), + ) + components = [ActionRow(select)] + + message = await ctx.send(content="\u200b", components=components) + except Exception as e: + self.logger.error("Encountered error", exc_info=True) return - options = [] - for role in setting.roles: - role: Role = await ctx.guild.fetch_role(role) - option = StringSelectOption(label=role.name, value=str(role.id)) - options.append(option) - - select = StringSelectMenu( - options=options, - placeholder="Select roles to add", - min_values=1, - max_values=len(options), - ) - components = [ActionRow(select)] - - message = await ctx.send(content="\u200b", components=components) - try: context = await self.bot.wait_for_component( check=lambda x: ctx.author.id == x.ctx.author.id, @@ -255,16 +280,11 @@ class RolegiverCog(Extension): added_roles.append(role) await ctx.author.add_role(role, reason="Rolegiver") - roles = ctx.author.roles - if roles: - roles.sort(key=lambda x: -x.position) - _ = roles.pop(-1) - - avalue = "\n".join([r.mention for r in added_roles]) if added_roles else "None" - value = "\n".join([r.mention for r in roles]) if roles else "None" + avalue = ( + "\n".join([r.mention for r in added_roles]) if added_roles else "None" + ) fields = [ EmbedField(name="Added Role(s)", value=avalue), - EmbedField(name="Prior Role(s)", value=value), ] embed = build_embed( @@ -279,13 +299,15 @@ class RolegiverCog(Extension): icon_url=ctx.author.display_avatar.url, ) - embed.set_footer(text=f"{ctx.author.username}#{ctx.author.discriminator} | {ctx.author.id}") + embed.set_footer(text=f"{ctx.author.username} | {ctx.author.id}") for row in components: for component in row.components: component.disabled = True - await context.ctx.edit_origin(embeds=embed, content="\u200b", components=components) + await context.ctx.edit_origin( + embeds=embed, content="\u200b", components=components + ) except asyncio.TimeoutError: for row in components: for component in row.components: @@ -312,7 +334,7 @@ class RolegiverCog(Extension): options.append(option) select = StringSelectMenu( - options=options, + *options, custom_id="to_remove", placeholder="Select roles to remove", min_values=1, @@ -336,14 +358,13 @@ class RolegiverCog(Extension): user_roles.remove(role) removed_roles.append(role) - user_roles.sort(key=lambda x: -x.position) - _ = user_roles.pop(-1) - - value = "\n".join([r.mention for r in user_roles]) if user_roles else "None" - rvalue = "\n".join([r.mention for r in removed_roles]) if removed_roles else "None" + rvalue = ( + "\n".join([r.mention for r in removed_roles]) + if removed_roles + else "None" + ) fields = [ EmbedField(name="Removed Role(s)", value=rvalue), - EmbedField(name="Remaining Role(s)", value=value), ] embed = build_embed( @@ -353,15 +374,19 @@ class RolegiverCog(Extension): ) embed.set_thumbnail(url=ctx.guild.icon.url) - embed.set_author(name=ctx.author.display_name, icon_url=ctx.author.display_avatar.url) + embed.set_author( + name=ctx.author.display_name, icon_url=ctx.author.display_avatar.url + ) - embed.set_footer(text=f"{ctx.author.username}#{ctx.author.discriminator} | {ctx.author.id}") + embed.set_footer(text=f"{ctx.author.username} | {ctx.author.id}") for row in components: for component in row.components: component.disabled = True - await context.ctx.edit_origin(embeds=embed, components=components, content="\u200b") + await context.ctx.edit_origin( + embeds=embed, components=components, content="\u200b" + ) except asyncio.TimeoutError: for row in components: @@ -369,7 +394,10 @@ class RolegiverCog(Extension): component.disabled = True await message.edit(components=components) - @rolegiver.subcommand(sub_cmd_name="cleanup", sub_cmd_description="Removed deleted roles from rolegiver") + @rolegiver.subcommand( + sub_cmd_name="cleanup", + sub_cmd_description="Removed deleted roles from rolegiver", + ) @check(admin_or_permissions(Permissions.MANAGE_GUILD)) async def _rolegiver_cleanup(self, ctx: InteractionContext) -> None: setting = await Rolegiver.find_one(Rolegiver.guild == ctx.guild.id) diff --git a/jarvis/cogs/extra/tags.py b/jarvis/cogs/extra/tags.py index 3d23660..4dc0c8a 100644 --- a/jarvis/cogs/extra/tags.py +++ b/jarvis/cogs/extra/tags.py @@ -50,7 +50,10 @@ class TagCog(Extension): async def _get(self, ctx: InteractionContext, name: str) -> None: tag = await Tag.find_one(Tag.guild == ctx.guild.id, Tag.name == name) if not tag: - await ctx.send("Well this is awkward, looks like the tag was deleted just now", ephemeral=True) + await ctx.send( + "Well this is awkward, looks like the tag was deleted just now", + ephemeral=True, + ) return await ctx.send(tag.content) @@ -58,8 +61,7 @@ class TagCog(Extension): @tag.subcommand(sub_cmd_name="create", sub_cmd_description="Create a tag") async def _create(self, ctx: SlashContext) -> None: modal = Modal( - title="Create a new tag!", - components=[ + *[ InputText( label="Tag name", placeholder="name", @@ -75,17 +77,22 @@ class TagCog(Extension): max_length=512, ), ], + title="Create a new tag!", ) await ctx.send_modal(modal) try: - response = await self.bot.wait_for_modal(modal, author=ctx.author.id, timeout=60 * 5) + response = await self.bot.wait_for_modal( + modal, author=ctx.author.id, timeout=60 * 5 + ) name = response.responses.get("name").replace("`", "") content = response.responses.get("content") except asyncio.TimeoutError: return - noinvite = await Setting.find_one(Setting.guild == ctx.guild.id, Setting.setting == "noinvite") + noinvite = await Setting.find_one( + Setting.guild == ctx.guild.id, Setting.setting == "noinvite" + ) if ( (invites.search(content) or invites.search(name)) @@ -95,13 +102,17 @@ class TagCog(Extension): or ctx.author.has_permission(Permissions.MANAGE_MESSAGES) ) ): - await response.send("Listen, don't use this to try and bypass the rules", ephemeral=True) + await response.send( + "Listen, don't use this to try and bypass the rules", ephemeral=True + ) return elif not content.strip() or not name.strip(): await response.send("Content and name required", ephemeral=True) return elif not tag_name.match(name): - await response.send("Tag name must only contain: [A-Za-z0-9_- ]", ephemeral=True) + await response.send( + "Tag name must only contain: [A-Za-z0-9_- ]", ephemeral=True + ) return tag = await Tag.find_one(Tag.guild == ctx.guild.id, Tag.name == name) @@ -122,7 +133,10 @@ class TagCog(Extension): embed = build_embed( title="Tag Created", description=f"{ctx.author.mention} created a new tag", - fields=[EmbedField(name="Name", value=name), EmbedField(name="Content", value=content)], + fields=[ + EmbedField(name="Name", value=name), + EmbedField(name="Content", value=content), + ], ) embed.set_author( @@ -130,7 +144,9 @@ class TagCog(Extension): icon_url=ctx.author.display_avatar.url, ) - components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") + components = Button( + style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}" + ) await response.send(embeds=embed, components=components) if ctx.guild.id not in self.cache: @@ -155,12 +171,13 @@ class TagCog(Extension): ctx.author.has_permission(Permissions.ADMINISTRATOR) or ctx.author.has_permission(Permissions.MANAGE_MESSAGES) ): - await ctx.send("You didn't create this tag, ask the creator to edit it", ephemeral=True) + await ctx.send( + "You didn't create this tag, ask the creator to edit it", ephemeral=True + ) return modal = Modal( - title="Edit a tag!", - components=[ + *[ InputText( label="Tag name", value=tag.name, @@ -176,11 +193,14 @@ class TagCog(Extension): max_length=512, ), ], + title="Edit a tag!", ) await ctx.send_modal(modal) try: - response = await self.bot.wait_for_modal(modal, author=ctx.author.id, timeout=60 * 5) + response = await self.bot.wait_for_modal( + modal, author=ctx.author.id, timeout=60 * 5 + ) name = response.responses.get("name").replace("`", "") content = response.responses.get("content") except asyncio.TimeoutError: @@ -188,10 +208,15 @@ class TagCog(Extension): new_tag = await Tag.find_one(Tag.guild == ctx.guild.id, Tag.name == name) if new_tag and new_tag.id != tag.id: - await ctx.send("That tag name is used by another tag, choose another name", ephemeral=True) + await ctx.send( + "That tag name is used by another tag, choose another name", + ephemeral=True, + ) return - noinvite = await Setting.find_one(Setting.guild == ctx.guild.id, Setting.setting == "noinvite") + noinvite = await Setting.find_one( + Setting.guild == ctx.guild.id, Setting.setting == "noinvite" + ) if ( (invites.search(content) or invites.search(name)) @@ -201,13 +226,17 @@ class TagCog(Extension): or ctx.author.has_permission(Permissions.MANAGE_MESSAGES) ) ): - await response.send("Listen, don't use this to try and bypass the rules", ephemeral=True) + await response.send( + "Listen, don't use this to try and bypass the rules", ephemeral=True + ) return elif not content.strip() or not name.strip(): await response.send("Content and name required", ephemeral=True) return elif not tag_name.match(name): - await response.send("Tag name must only contain: [A-Za-z0-9_- ]", ephemeral=True) + await response.send( + "Tag name must only contain: [A-Za-z0-9_- ]", ephemeral=True + ) return tag.content = re.sub(r"\\?([@<])", r"\\\g<1>", content) @@ -230,7 +259,9 @@ class TagCog(Extension): name=ctx.author.username + "#" + ctx.author.discriminator, icon_url=ctx.author.display_avatar.url, ) - components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") + components = Button( + style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}" + ) await response.send(embeds=embed, components=components) if tag.name not in self.cache[ctx.guild.id]: self.cache[ctx.guild.id].remove(old_name) @@ -253,7 +284,10 @@ class TagCog(Extension): ctx.author.has_permission(Permissions.ADMINISTRATOR) or ctx.author.has_permission(Permissions.MANAGE_MESSAGES) ): - await ctx.send("You didn't create this tag, ask the creator to delete it", ephemeral=True) + await ctx.send( + "You didn't create this tag, ask the creator to delete it", + ephemeral=True, + ) return await tag.delete() @@ -307,7 +341,9 @@ class TagCog(Extension): name=f"{username}#{discrim}" if username else "Unknown User", icon_url=url, ) - components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") + components = Button( + style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}" + ) await ctx.send(embeds=embed, components=components) @tag.subcommand(sub_cmd_name="list", sub_cmd_description="List tag names") @@ -315,7 +351,9 @@ class TagCog(Extension): tags = await Tag.find(Tag.guild == ctx.guild.id).to_list() names = "\n".join(f"`{t.name}`" for t in tags) embed = build_embed(title="All Tags", description=names, fields=[]) - components = Button(style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}") + components = Button( + style=ButtonStyle.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}" + ) await ctx.send(embeds=embed, components=components) @_get.autocomplete("name") @@ -326,7 +364,9 @@ class TagCog(Extension): if not self.cache.get(ctx.guild.id): tags = await Tag.find(Tag.guild == ctx.guild.id).to_list() self.cache[ctx.guild.id] = [tag.name for tag in tags] - results = process.extract(ctx.input_text, self.cache.get(ctx.guild.id), limit=25) + results = process.extract( + ctx.input_text, self.cache.get(ctx.guild.id), limit=25 + ) choices = [{"name": r[0], "value": r[0]} for r in results] await ctx.send(choices=choices) diff --git a/jarvis/cogs/unique/ctc2.py b/jarvis/cogs/unique/ctc2.py index 6b27034..0f2ef41 100644 --- a/jarvis/cogs/unique/ctc2.py +++ b/jarvis/cogs/unique/ctc2.py @@ -1,4 +1,10 @@ -"""JARVIS Complete the Code 2 Cog.""" +""" +JARVIS Complete the Code 2 Cog. + +This cog is now maintenance-only due to conflict with the dbrand moderators. + +Please do not file feature requests related to this cog; they will be closed. +""" import logging import re @@ -19,7 +25,7 @@ from jarvis_core.db.models import Guess from jarvis.utils import build_embed -guild_ids = [578757004059738142, 520021794380447745, 862402786116763668] +guild_ids = [] # [578757004059738142, 520021794380447745, 862402786116763668] valid = re.compile(r"[\w\s\-\\/.!@#$%^*()+=<>,\u0080-\U000E0FFF]*") invites = re.compile( @@ -40,30 +46,54 @@ class CTCCog(Extension): def __del__(self): self._session.close() - ctc2 = SlashCommand(name="ctc2", description="CTC2 related commands", scopes=guild_ids) + ctc2 = SlashCommand( + name="ctc2", description="CTC2 related commands", scopes=guild_ids + ) @ctc2.subcommand(sub_cmd_name="about") @cooldown(bucket=Buckets.USER, rate=1, interval=30) async def _about(self, ctx: InteractionContext) -> None: - components = [ActionRow(Button(style=ButtonStyle.URL, url="https://completethecode.com", label="More Info"))] - await ctx.send("See https://completethecode.com for more information", components=components) + components = [ + ActionRow( + Button( + style=ButtonStyle.URL, + url="https://completethecode.com", + label="More Info", + ) + ) + ] + await ctx.send( + "See https://completethecode.com for more information", + components=components, + ) @ctc2.subcommand( sub_cmd_name="pw", sub_cmd_description="Guess a password for https://completethecodetwo.cards", ) - @slash_option(name="guess", description="Guess a password", opt_type=OptionType.STRING, required=True) + @slash_option( + name="guess", + description="Guess a password", + opt_type=OptionType.STRING, + required=True, + ) @cooldown(bucket=Buckets.USER, rate=1, interval=2) async def _pw(self, ctx: InteractionContext, guess: str) -> None: if len(guess) > 800: await ctx.send( - ("Listen here, dipshit. Don't be like <@256110768724901889>. " "Make your guesses < 800 characters."), + ( + "Listen here, dipshit. Don't be like <@256110768724901889>. " + "Make your guesses < 800 characters." + ), ephemeral=True, ) return elif not valid.fullmatch(guess): await ctx.send( - ("Listen here, dipshit. Don't be like <@256110768724901889>. " "Make your guesses *readable*."), + ( + "Listen here, dipshit. Don't be like <@256110768724901889>. " + "Make your guesses *readable*." + ), ephemeral=True, ) return @@ -102,7 +132,7 @@ class CTCCog(Extension): if not user: user = "[redacted]" if isinstance(user, (Member, User)): - user = user.username + "#" + user.discriminator + user = user.username cache[guess.user] = user name = "Correctly" if guess["correct"] else "Incorrectly" name += " guessed by: " + user diff --git a/jarvis/cogs/unique/dbrand.py b/jarvis/cogs/unique/dbrand.py index 30562c8..9bbc07f 100644 --- a/jarvis/cogs/unique/dbrand.py +++ b/jarvis/cogs/unique/dbrand.py @@ -1,4 +1,10 @@ -"""JARVIS dbrand cog.""" +""" +JARVIS dbrand cog. + +This cog is now maintenance-only due to conflict with the dbrand moderators. + +Please do not file feature requests related to this cog; they will be closed. +""" import logging import re from datetime import datetime, timedelta, timezone @@ -63,7 +69,9 @@ async def parse_db_status() -> dict: else: cell = cell.get_text().strip() row_data.append(cell) - data[data_key].append({headers[idx]: value for idx, value in enumerate(row_data)}) + data[data_key].append( + {headers[idx]: value for idx, value in enumerate(row_data)} + ) return data @@ -88,7 +96,9 @@ class DbrandCog(Extension): db = SlashCommand(name="db", description="dbrand commands", scopes=guild_ids) - @db.subcommand(sub_cmd_name="status", sub_cmd_description="Get dbrand operational status") + @db.subcommand( + sub_cmd_name="status", sub_cmd_description="Get dbrand operational status" + ) async def _status(self, ctx: InteractionContext) -> None: status = self.cache.get("status") if not status or status["cache_expiry"] <= datetime.now(tz=timezone.utc): @@ -97,7 +107,10 @@ class DbrandCog(Extension): self.cache["status"] = status status = status.get("operations") emojies = [x["Status"] for x in status] - fields = [EmbedField(name=f'{x["Status"]} {x["Service"]}', value=x["Detail"]) for x in status] + fields = [ + EmbedField(name=f'{x["Status"]} {x["Service"]}', value=x["Detail"]) + for x in status + ] color = "#FBBD1E" if all("green" in x for x in emojies): color = "#38F657" @@ -169,7 +182,9 @@ class DbrandCog(Extension): async def _support(self, ctx: InteractionContext) -> None: return await self._db_support_cmd(ctx) - @db.subcommand(sub_cmd_name="gripcheck", sub_cmd_description="Watch a dbrand grip get thrown") + @db.subcommand( + sub_cmd_name="gripcheck", sub_cmd_description="Watch a dbrand grip get thrown" + ) async def _gripcheck(self, ctx: InteractionContext) -> None: video_url = "https://cdn.discordapp.com/attachments/599068193339736096/890679742263623751/video0.mov" image_url = "https://cdn.discordapp.com/attachments/599068193339736096/890680198306095104/image0.jpg" @@ -188,13 +203,22 @@ class DbrandCog(Extension): f"[Be (not) extorted]({self.base_url + 'not-extortion'})", "[Robot Camo Wallpapers](https://db.io/wallpapers)", ] - embed = build_embed(title="Useful Links", description="\n\n".join(urls), fields=[], color="#FFBB00") + embed = build_embed( + title="Useful Links", + description="\n\n".join(urls), + fields=[], + color="#FFBB00", + ) embed.set_footer( text="dbrand.com", icon_url="https://dev.zevaryx.com/db_logo.png", ) embed.set_thumbnail(url="https://dev.zevaryx.com/db_logo.png") - embed.set_author(name="dbrand", url=self.base_url, icon_url="https://dev.zevaryx.com/db_logo.png") + embed.set_author( + name="dbrand", + url=self.base_url, + icon_url="https://dev.zevaryx.com/db_logo.png", + ) await ctx.send(embeds=embed) @db.subcommand( @@ -217,11 +241,15 @@ class DbrandCog(Extension): ): # Magic number, subtract from flag char to get ascii char uni2ascii = 127365 - search = chr(ord(search[0]) - uni2ascii) + chr(ord(search[1]) - uni2ascii) + search = chr(ord(search[0]) - uni2ascii) + chr( + ord(search[1]) - uni2ascii + ) elif search == "🏳️": search = "fr" else: - await ctx.send("Please use text to search for shipping.", ephemeral=True) + await ctx.send( + "Please use text to search for shipping.", ephemeral=True + ) return if len(search) > 3: countries = {x["country"]: x["alpha-2"] for x in shipping_lookup} @@ -246,7 +274,9 @@ class DbrandCog(Extension): data = await self._session.get(api_link) if 200 <= data.status < 400: data = await data.json() - data["cache_expiry"] = datetime.now(tz=timezone.utc) + timedelta(hours=24) + data["cache_expiry"] = datetime.now(tz=timezone.utc) + timedelta( + hours=24 + ) self.cache[dest] = data else: data = None @@ -255,12 +285,18 @@ class DbrandCog(Extension): fields = [] for service in data["shipping_services_available"]: service_data = self.cache.get(f"{dest}-{service}") - if not service_data or service_data["cache_expiry"] < datetime.now(tz=timezone.utc): - service_data = await self._session.get(self.api_url + dest + "/" + service["url"]) + if not service_data or service_data["cache_expiry"] < datetime.now( + tz=timezone.utc + ): + service_data = await self._session.get( + self.api_url + dest + "/" + service["url"] + ) if service_data.status > 400: continue service_data = await service_data.json() - service_data["cache_expiry"] = datetime.now(tz=timezone.utc) + timedelta(hours=24) + service_data["cache_expiry"] = datetime.now( + tz=timezone.utc + ) + timedelta(hours=24) self.cache[f"{dest}-{service}"] = service_data title = f'{service_data["carrier"]} {service_data["tier-title"]} | {service_data["costs-min"]}' message = service_data["time-title"] @@ -271,7 +307,9 @@ class DbrandCog(Extension): status = self.cache.get("status") if not status or status["cache_expiry"] <= datetime.now(tz=timezone.utc): status = await parse_db_status() - status["cache_expiry"] = datetime.now(tz=timezone.utc) + timedelta(hours=2) + status["cache_expiry"] = datetime.now(tz=timezone.utc) + timedelta( + hours=2 + ) self.cache["status"] = status status = status["countries"] @@ -284,10 +322,10 @@ class DbrandCog(Extension): description = "" color = "#FFBB00" if shipping_info: - description = ( - f'{shipping_info["Status"]}\u200b \u200b {shipping_info["Est. Delivery Time"].split(":")[0]}' + description = f'{shipping_info["Status"]}\u200b \u200b {shipping_info["Est. Delivery Time"].split(":")[0]}' + created = self.cache.get("status").get("cache_expiry") - timedelta( + hours=2 ) - created = self.cache.get("status").get("cache_expiry") - timedelta(hours=2) ts = int(created.timestamp()) description += f" \u200b | \u200b Last updated: \n\u200b" if "green" in shipping_info["Status"]: @@ -316,7 +354,8 @@ class DbrandCog(Extension): embed = build_embed( title="Check Shipping Times", description=( - "Country not found.\nYou can [view all shipping " "destinations here](https://dbrand.com/shipping)" + "Country not found.\nYou can [view all shipping " + "destinations here](https://dbrand.com/shipping)" ), fields=[], url="https://dbrand.com/shipping", diff --git a/jarvis/config.py b/jarvis/config.py index c11b6ba..0281199 100644 --- a/jarvis/config.py +++ b/jarvis/config.py @@ -40,24 +40,6 @@ class Mastodon(BaseModel): url: str -class Reddit(BaseModel): - """Reddit config.""" - - user_agent: Optional[str] = None - client_secret: str - client_id: str - - -class Twitter(BaseModel): - """Twitter config.""" - - consumer_key: str - consumer_secret: str - access_token: str - access_secret: str - bearer_token: str - - class Environment(Enum): """JARVIS running environment.""" @@ -69,12 +51,13 @@ class Config(BaseModel): """JARVIS config model.""" token: str + """Bot token""" + erapi: str + """exchangerate-api.org API token""" environment: Environment = Environment.develop mongo: Mongo redis: Redis mastodon: Optional[Mastodon] = None - reddit: Optional[Reddit] = None - twitter: Optional[Twitter] = None urls: Optional[dict[str, str]] = None sync: bool = False log_level: str = "INFO" @@ -112,22 +95,16 @@ def _load_env() -> Config | None: mongo = {} redis = {} mastodon = {} - twitter = {} - reddit = {} urls = {} mongo_keys = find_all(lambda x: x.upper().startswith("MONGO"), environ.keys()) redis_keys = find_all(lambda x: x.upper().startswith("REDIS"), environ.keys()) mastodon_keys = find_all(lambda x: x.upper().startswith("MASTODON"), environ.keys()) - reddit_keys = find_all(lambda x: x.upper().startswith("REDDIT"), environ.keys()) - twitter_keys = find_all(lambda x: x.upper().startswith("TWITTER"), environ.keys()) url_keys = find_all(lambda x: x.upper().startswith("URLS"), environ.keys()) config_keys = ( mongo_keys + redis_keys + mastodon_keys - + reddit_keys - + twitter_keys + url_keys + ["TOKEN", "SYNC", "LOG_LEVEL", "JURIGGED"] ) @@ -145,12 +122,6 @@ def _load_env() -> Config | None: elif item in mastodon_keys: key = "_".join(item.split("_")[1:]).lower() mastodon[key] = value - elif item in twitter_keys: - key = "_".join(item.split("_")[1:]).lower() - twitter[key] = value - elif item in reddit_keys: - key = "_".join(item.split("_")[1:]).lower() - reddit[key] = value elif item in url_keys: key = "_".join(item.split("_")[1:]).lower() urls[key] = value @@ -161,10 +132,6 @@ def _load_env() -> Config | None: data["mongo"] = mongo data["redis"] = redis - if all(x is not None for x in reddit.values()): - data["reddit"] = reddit - if all(x is not None for x in twitter.values()): - data["twitter"] = twitter if all(x is not None for x in mastodon.values()): data["mastodon"] = mastodon data["urls"] = {k: v for k, v in urls if v} diff --git a/jarvis/data/dbrand.py b/jarvis/data/dbrand.py index f45ae70..3b93c0c 100644 --- a/jarvis/data/dbrand.py +++ b/jarvis/data/dbrand.py @@ -1,7 +1,7 @@ """dbrand-specific data.""" shipping_lookup = [ {"country": "Afghanistan", "alpha-2": "AF", "alpha-3": "AFG", "numeric": "0004"}, - {"country": "Ã…land Islands", "alpha-2": "AX", "alpha-3": "ALA", "numeric": "0248"}, + {"country": "Aland Islands", "alpha-2": "AX", "alpha-3": "ALA", "numeric": "0248"}, {"country": "Albania", "alpha-2": "AL", "alpha-3": "ALB", "numeric": "0008"}, {"country": "Algeria", "alpha-2": "DZ", "alpha-3": "DZA", "numeric": "0012"}, {"country": "American Samoa", "alpha-2": "AS", "alpha-3": "ASM", "numeric": "0016"}, @@ -9,7 +9,12 @@ shipping_lookup = [ {"country": "Angola", "alpha-2": "AO", "alpha-3": "AGO", "numeric": "0024"}, {"country": "Anguilla", "alpha-2": "AI", "alpha-3": "AIA", "numeric": "0660"}, {"country": "Antarctica", "alpha-2": "AQ", "alpha-3": "ATA", "numeric": "0010"}, - {"country": "Antigua and Barbuda", "alpha-2": "AG", "alpha-3": "ATG", "numeric": "0028"}, + { + "country": "Antigua and Barbuda", + "alpha-2": "AG", + "alpha-3": "ATG", + "numeric": "0028", + }, {"country": "Argentina", "alpha-2": "AR", "alpha-3": "ARG", "numeric": "0032"}, {"country": "Armenia", "alpha-2": "AM", "alpha-3": "ARM", "numeric": "0051"}, {"country": "Aruba", "alpha-2": "AW", "alpha-3": "ABW", "numeric": "0533"}, @@ -38,7 +43,12 @@ shipping_lookup = [ "alpha-3": "BES", "numeric": "0535", }, - {"country": "Bosnia and Herzegovina", "alpha-2": "BA", "alpha-3": "BIH", "numeric": "0070"}, + { + "country": "Bosnia and Herzegovina", + "alpha-2": "BA", + "alpha-3": "BIH", + "numeric": "0070", + }, {"country": "Botswana", "alpha-2": "BW", "alpha-3": "BWA", "numeric": "0072"}, {"country": "Bouvet Island", "alpha-2": "BV", "alpha-3": "BVT", "numeric": "0074"}, {"country": "Brazil", "alpha-2": "BR", "alpha-3": "BRA", "numeric": "0076"}, @@ -48,7 +58,12 @@ shipping_lookup = [ "alpha-3": "IOT", "numeric": "0086", }, - {"country": "Brunei Darussalam", "alpha-2": "BN", "alpha-3": "BRN", "numeric": "0096"}, + { + "country": "Brunei Darussalam", + "alpha-2": "BN", + "alpha-3": "BRN", + "numeric": "0096", + }, {"country": "Bulgaria", "alpha-2": "BG", "alpha-3": "BGR", "numeric": "0100"}, {"country": "Burkina Faso", "alpha-2": "BF", "alpha-3": "BFA", "numeric": "0854"}, {"country": "Burundi", "alpha-2": "BI", "alpha-3": "BDI", "numeric": "0108"}, @@ -56,7 +71,12 @@ shipping_lookup = [ {"country": "Cambodia", "alpha-2": "KH", "alpha-3": "KHM", "numeric": "0116"}, {"country": "Cameroon", "alpha-2": "CM", "alpha-3": "CMR", "numeric": "0120"}, {"country": "Canada", "alpha-2": "CA", "alpha-3": "CAN", "numeric": "0124"}, - {"country": "Cayman Islands (the)", "alpha-2": "KY", "alpha-3": "CYM", "numeric": "0136"}, + { + "country": "Cayman Islands (the)", + "alpha-2": "KY", + "alpha-3": "CYM", + "numeric": "0136", + }, { "country": "Central African Republic (the)", "alpha-2": "CF", @@ -66,7 +86,12 @@ shipping_lookup = [ {"country": "Chad", "alpha-2": "TD", "alpha-3": "TCD", "numeric": "0148"}, {"country": "Chile", "alpha-2": "CL", "alpha-3": "CHL", "numeric": "0152"}, {"country": "China", "alpha-2": "CN", "alpha-3": "CHN", "numeric": "0156"}, - {"country": "Christmas Island", "alpha-2": "CX", "alpha-3": "CXR", "numeric": "0162"}, + { + "country": "Christmas Island", + "alpha-2": "CX", + "alpha-3": "CXR", + "numeric": "0162", + }, { "country": "Cocos (Keeling) Islands (the)", "alpha-2": "CC", @@ -82,22 +107,37 @@ shipping_lookup = [ "numeric": "0180", }, {"country": "Congo (the)", "alpha-2": "CG", "alpha-3": "COG", "numeric": "0178"}, - {"country": "Cook Islands (the)", "alpha-2": "CK", "alpha-3": "COK", "numeric": "0184"}, + { + "country": "Cook Islands (the)", + "alpha-2": "CK", + "alpha-3": "COK", + "numeric": "0184", + }, {"country": "Costa Rica", "alpha-2": "CR", "alpha-3": "CRI", "numeric": "0188"}, - {"country": "Côte d'Ivoire", "alpha-2": "CI", "alpha-3": "CIV", "numeric": "0384"}, + {"country": "Ivory Coast", "alpha-2": "CI", "alpha-3": "CIV", "numeric": "0384"}, {"country": "Croatia", "alpha-2": "HR", "alpha-3": "HRV", "numeric": "0191"}, {"country": "Cuba", "alpha-2": "CU", "alpha-3": "CUB", "numeric": "0192"}, - {"country": "Curaçao", "alpha-2": "CW", "alpha-3": "CUW", "numeric": "0531"}, + {"country": "Curacao", "alpha-2": "CW", "alpha-3": "CUW", "numeric": "0531"}, {"country": "Cyprus", "alpha-2": "CY", "alpha-3": "CYP", "numeric": "0196"}, {"country": "Czechia", "alpha-2": "CZ", "alpha-3": "CZE", "numeric": "0203"}, {"country": "Denmark", "alpha-2": "DK", "alpha-3": "DNK", "numeric": "0208"}, {"country": "Djibouti", "alpha-2": "DJ", "alpha-3": "DJI", "numeric": "0262"}, {"country": "Dominica", "alpha-2": "DM", "alpha-3": "DMA", "numeric": "0212"}, - {"country": "Dominican Republic (the)", "alpha-2": "DO", "alpha-3": "DOM", "numeric": "0214"}, + { + "country": "Dominican Republic (the)", + "alpha-2": "DO", + "alpha-3": "DOM", + "numeric": "0214", + }, {"country": "Ecuador", "alpha-2": "EC", "alpha-3": "ECU", "numeric": "0218"}, {"country": "Egypt", "alpha-2": "EG", "alpha-3": "EGY", "numeric": "0818"}, {"country": "El Salvador", "alpha-2": "SV", "alpha-3": "SLV", "numeric": "0222"}, - {"country": "Equatorial Guinea", "alpha-2": "GQ", "alpha-3": "GNQ", "numeric": "0226"}, + { + "country": "Equatorial Guinea", + "alpha-2": "GQ", + "alpha-3": "GNQ", + "numeric": "0226", + }, {"country": "Eritrea", "alpha-2": "ER", "alpha-3": "ERI", "numeric": "0232"}, {"country": "Estonia", "alpha-2": "EE", "alpha-3": "EST", "numeric": "0233"}, {"country": "Eswatini", "alpha-2": "SZ", "alpha-3": "SWZ", "numeric": "0748"}, @@ -108,12 +148,22 @@ shipping_lookup = [ "alpha-3": "FLK", "numeric": "0238", }, - {"country": "Faroe Islands (the)", "alpha-2": "FO", "alpha-3": "FRO", "numeric": "0234"}, + { + "country": "Faroe Islands (the)", + "alpha-2": "FO", + "alpha-3": "FRO", + "numeric": "0234", + }, {"country": "Fiji", "alpha-2": "FJ", "alpha-3": "FJI", "numeric": "0242"}, {"country": "Finland", "alpha-2": "FI", "alpha-3": "FIN", "numeric": "0246"}, {"country": "France", "alpha-2": "FR", "alpha-3": "FRA", "numeric": "0250"}, {"country": "French Guiana", "alpha-2": "GF", "alpha-3": "GUF", "numeric": "0254"}, - {"country": "French Polynesia", "alpha-2": "PF", "alpha-3": "PYF", "numeric": "0258"}, + { + "country": "French Polynesia", + "alpha-2": "PF", + "alpha-3": "PYF", + "numeric": "0258", + }, { "country": "French Southern Territories (the)", "alpha-2": "TF", @@ -150,7 +200,12 @@ shipping_lookup = [ {"country": "Iceland", "alpha-2": "IS", "alpha-3": "ISL", "numeric": "0352"}, {"country": "India", "alpha-2": "IN", "alpha-3": "IND", "numeric": "0356"}, {"country": "Indonesia", "alpha-2": "ID", "alpha-3": "IDN", "numeric": "0360"}, - {"country": "Iran (Islamic Republic of)", "alpha-2": "IR", "alpha-3": "IRN", "numeric": "0364"}, + { + "country": "Iran (Islamic Republic of)", + "alpha-2": "IR", + "alpha-3": "IRN", + "numeric": "0364", + }, {"country": "Iraq", "alpha-2": "IQ", "alpha-3": "IRQ", "numeric": "0368"}, {"country": "Ireland", "alpha-2": "IE", "alpha-3": "IRL", "numeric": "0372"}, {"country": "Isle of Man", "alpha-2": "IM", "alpha-3": "IMN", "numeric": "0833"}, @@ -169,7 +224,12 @@ shipping_lookup = [ "alpha-3": "PRK", "numeric": "0408", }, - {"country": "Korea (the Republic of)", "alpha-2": "KR", "alpha-3": "KOR", "numeric": "0410"}, + { + "country": "Korea (the Republic of)", + "alpha-2": "KR", + "alpha-3": "KOR", + "numeric": "0410", + }, {"country": "Kuwait", "alpha-2": "KW", "alpha-3": "KWT", "numeric": "0414"}, {"country": "Kyrgyzstan", "alpha-2": "KG", "alpha-3": "KGZ", "numeric": "0417"}, { @@ -199,7 +259,12 @@ shipping_lookup = [ {"country": "Maldives", "alpha-2": "MV", "alpha-3": "MDV", "numeric": "0462"}, {"country": "Mali", "alpha-2": "ML", "alpha-3": "MLI", "numeric": "0466"}, {"country": "Malta", "alpha-2": "MT", "alpha-3": "MLT", "numeric": "0470"}, - {"country": "Marshall Islands (the)", "alpha-2": "MH", "alpha-3": "MHL", "numeric": "0584"}, + { + "country": "Marshall Islands (the)", + "alpha-2": "MH", + "alpha-3": "MHL", + "numeric": "0584", + }, {"country": "Martinique", "alpha-2": "MQ", "alpha-3": "MTQ", "numeric": "0474"}, {"country": "Mauritania", "alpha-2": "MR", "alpha-3": "MRT", "numeric": "0478"}, {"country": "Mauritius", "alpha-2": "MU", "alpha-3": "MUS", "numeric": "0480"}, @@ -211,7 +276,12 @@ shipping_lookup = [ "alpha-3": "FSM", "numeric": "0583", }, - {"country": "Moldova (the Republic of)", "alpha-2": "MD", "alpha-3": "MDA", "numeric": "0498"}, + { + "country": "Moldova (the Republic of)", + "alpha-2": "MD", + "alpha-3": "MDA", + "numeric": "0498", + }, {"country": "Monaco", "alpha-2": "MC", "alpha-3": "MCO", "numeric": "0492"}, {"country": "Mongolia", "alpha-2": "MN", "alpha-3": "MNG", "numeric": "0496"}, {"country": "Montenegro", "alpha-2": "ME", "alpha-3": "MNE", "numeric": "0499"}, @@ -222,7 +292,12 @@ shipping_lookup = [ {"country": "Namibia", "alpha-2": "NA", "alpha-3": "NAM", "numeric": "0516"}, {"country": "Nauru", "alpha-2": "NR", "alpha-3": "NRU", "numeric": "0520"}, {"country": "Nepal", "alpha-2": "NP", "alpha-3": "NPL", "numeric": "0524"}, - {"country": "Netherlands (the)", "alpha-2": "NL", "alpha-3": "NLD", "numeric": "0528"}, + { + "country": "Netherlands (the)", + "alpha-2": "NL", + "alpha-3": "NLD", + "numeric": "0528", + }, {"country": "New Caledonia", "alpha-2": "NC", "alpha-3": "NCL", "numeric": "0540"}, {"country": "New Zealand", "alpha-2": "NZ", "alpha-3": "NZL", "numeric": "0554"}, {"country": "Nicaragua", "alpha-2": "NI", "alpha-3": "NIC", "numeric": "0558"}, @@ -240,32 +315,72 @@ shipping_lookup = [ {"country": "Oman", "alpha-2": "OM", "alpha-3": "OMN", "numeric": "0512"}, {"country": "Pakistan", "alpha-2": "PK", "alpha-3": "PAK", "numeric": "0586"}, {"country": "Palau", "alpha-2": "PW", "alpha-3": "PLW", "numeric": "0585"}, - {"country": "Palestine, State of", "alpha-2": "PS", "alpha-3": "PSE", "numeric": "0275"}, + { + "country": "Palestine, State of", + "alpha-2": "PS", + "alpha-3": "PSE", + "numeric": "0275", + }, {"country": "Panama", "alpha-2": "PA", "alpha-3": "PAN", "numeric": "0591"}, - {"country": "Papua New Guinea", "alpha-2": "PG", "alpha-3": "PNG", "numeric": "0598"}, + { + "country": "Papua New Guinea", + "alpha-2": "PG", + "alpha-3": "PNG", + "numeric": "0598", + }, {"country": "Paraguay", "alpha-2": "PY", "alpha-3": "PRY", "numeric": "0600"}, {"country": "Peru", "alpha-2": "PE", "alpha-3": "PER", "numeric": "0604"}, - {"country": "Philippines (the)", "alpha-2": "PH", "alpha-3": "PHL", "numeric": "0608"}, + { + "country": "Philippines (the)", + "alpha-2": "PH", + "alpha-3": "PHL", + "numeric": "0608", + }, {"country": "Pitcairn", "alpha-2": "PN", "alpha-3": "PCN", "numeric": "0612"}, {"country": "Poland", "alpha-2": "PL", "alpha-3": "POL", "numeric": "0616"}, {"country": "Portugal", "alpha-2": "PT", "alpha-3": "PRT", "numeric": "0620"}, {"country": "Puerto Rico", "alpha-2": "PR", "alpha-3": "PRI", "numeric": "0630"}, {"country": "Qatar", "alpha-2": "QA", "alpha-3": "QAT", "numeric": "0634"}, - {"country": "Réunion", "alpha-2": "RE", "alpha-3": "REU", "numeric": "0638"}, + {"country": "Reunion", "alpha-2": "RE", "alpha-3": "REU", "numeric": "0638"}, {"country": "Romania", "alpha-2": "RO", "alpha-3": "ROU", "numeric": "0642"}, - {"country": "Russian Federation (the)", "alpha-2": "RU", "alpha-3": "RUS", "numeric": "0643"}, + { + "country": "Russian Federation (the)", + "alpha-2": "RU", + "alpha-3": "RUS", + "numeric": "0643", + }, {"country": "Rwanda", "alpha-2": "RW", "alpha-3": "RWA", "numeric": "0646"}, - {"country": "Saint Barthélemy", "alpha-2": "BL", "alpha-3": "BLM", "numeric": "0652"}, + { + "country": "Saint Barthelemy", + "alpha-2": "BL", + "alpha-3": "BLM", + "numeric": "0652", + }, { "country": "Saint Helena, Ascension and Tristan da Cunha", "alpha-2": "SH", "alpha-3": "SHN", "numeric": "0654", }, - {"country": "Saint Kitts and Nevis", "alpha-2": "KN", "alpha-3": "KNA", "numeric": "0659"}, + { + "country": "Saint Kitts and Nevis", + "alpha-2": "KN", + "alpha-3": "KNA", + "numeric": "0659", + }, {"country": "Saint Lucia", "alpha-2": "LC", "alpha-3": "LCA", "numeric": "0662"}, - {"country": "Saint Martin (French part)", "alpha-2": "MF", "alpha-3": "MAF", "numeric": "0663"}, - {"country": "Saint Pierre and Miquelon", "alpha-2": "PM", "alpha-3": "SPM", "numeric": "0666"}, + { + "country": "Saint Martin (French part)", + "alpha-2": "MF", + "alpha-3": "MAF", + "numeric": "0663", + }, + { + "country": "Saint Pierre and Miquelon", + "alpha-2": "PM", + "alpha-3": "SPM", + "numeric": "0666", + }, { "country": "Saint Vincent and the Grenadines", "alpha-2": "VC", @@ -274,17 +389,32 @@ shipping_lookup = [ }, {"country": "Samoa", "alpha-2": "WS", "alpha-3": "WSM", "numeric": "0882"}, {"country": "San Marino", "alpha-2": "SM", "alpha-3": "SMR", "numeric": "0674"}, - {"country": "Sao Tome and Principe", "alpha-2": "ST", "alpha-3": "STP", "numeric": "0678"}, + { + "country": "Sao Tome and Principe", + "alpha-2": "ST", + "alpha-3": "STP", + "numeric": "0678", + }, {"country": "Saudi Arabia", "alpha-2": "SA", "alpha-3": "SAU", "numeric": "0682"}, {"country": "Senegal", "alpha-2": "SN", "alpha-3": "SEN", "numeric": "0686"}, {"country": "Serbia", "alpha-2": "RS", "alpha-3": "SRB", "numeric": "0688"}, {"country": "Seychelles", "alpha-2": "SC", "alpha-3": "SYC", "numeric": "0690"}, {"country": "Sierra Leone", "alpha-2": "SL", "alpha-3": "SLE", "numeric": "0694"}, {"country": "Singapore", "alpha-2": "SG", "alpha-3": "SGP", "numeric": "0702"}, - {"country": "Sint Maarten (Dutch part)", "alpha-2": "SX", "alpha-3": "SXM", "numeric": "0534"}, + { + "country": "Sint Maarten (Dutch part)", + "alpha-2": "SX", + "alpha-3": "SXM", + "numeric": "0534", + }, {"country": "Slovakia", "alpha-2": "SK", "alpha-3": "SVK", "numeric": "0703"}, {"country": "Slovenia", "alpha-2": "SI", "alpha-3": "SVN", "numeric": "0705"}, - {"country": "Solomon Islands", "alpha-2": "SB", "alpha-3": "SLB", "numeric": "0090"}, + { + "country": "Solomon Islands", + "alpha-2": "SB", + "alpha-3": "SLB", + "numeric": "0090", + }, {"country": "Somalia", "alpha-2": "SO", "alpha-3": "SOM", "numeric": "0706"}, {"country": "South Africa", "alpha-2": "ZA", "alpha-3": "ZAF", "numeric": "0710"}, { @@ -298,11 +428,26 @@ shipping_lookup = [ {"country": "Sri Lanka", "alpha-2": "LK", "alpha-3": "LKA", "numeric": "0144"}, {"country": "Sudan (the)", "alpha-2": "SD", "alpha-3": "SDN", "numeric": "0729"}, {"country": "Suriname", "alpha-2": "SR", "alpha-3": "SUR", "numeric": "0740"}, - {"country": "Svalbard and Jan Mayen", "alpha-2": "SJ", "alpha-3": "SJM", "numeric": "0744"}, + { + "country": "Svalbard and Jan Mayen", + "alpha-2": "SJ", + "alpha-3": "SJM", + "numeric": "0744", + }, {"country": "Sweden", "alpha-2": "SE", "alpha-3": "SWE", "numeric": "0752"}, {"country": "Switzerland", "alpha-2": "CH", "alpha-3": "CHE", "numeric": "0756"}, - {"country": "Syrian Arab Republic", "alpha-2": "SY", "alpha-3": "SYR", "numeric": "0760"}, - {"country": "Taiwan (Province of China)", "alpha-2": "TW", "alpha-3": "TWN", "numeric": "0158"}, + { + "country": "Syrian Arab Republic", + "alpha-2": "SY", + "alpha-3": "SYR", + "numeric": "0760", + }, + { + "country": "Taiwan (Province of China)", + "alpha-2": "TW", + "alpha-3": "TWN", + "numeric": "0158", + }, {"country": "Tajikistan", "alpha-2": "TJ", "alpha-3": "TJK", "numeric": "0762"}, { "country": "Tanzania, United Republic of", @@ -315,7 +460,12 @@ shipping_lookup = [ {"country": "Togo", "alpha-2": "TG", "alpha-3": "TGO", "numeric": "0768"}, {"country": "Tokelau", "alpha-2": "TK", "alpha-3": "TKL", "numeric": "0772"}, {"country": "Tonga", "alpha-2": "TO", "alpha-3": "TON", "numeric": "0776"}, - {"country": "Trinidad and Tobago", "alpha-2": "TT", "alpha-3": "TTO", "numeric": "0780"}, + { + "country": "Trinidad and Tobago", + "alpha-2": "TT", + "alpha-3": "TTO", + "numeric": "0780", + }, {"country": "Tunisia", "alpha-2": "TN", "alpha-3": "TUN", "numeric": "0788"}, {"country": "Turkey", "alpha-2": "TR", "alpha-3": "TUR", "numeric": "0792"}, {"country": "Turkmenistan", "alpha-2": "TM", "alpha-3": "TKM", "numeric": "0795"}, @@ -328,7 +478,12 @@ shipping_lookup = [ {"country": "Tuvalu", "alpha-2": "TV", "alpha-3": "TUV", "numeric": "0798"}, {"country": "Uganda", "alpha-2": "UG", "alpha-3": "UGA", "numeric": "0800"}, {"country": "Ukraine", "alpha-2": "UA", "alpha-3": "UKR", "numeric": "0804"}, - {"country": "United Arab Emirates (the)", "alpha-2": "AE", "alpha-3": "ARE", "numeric": "0784"}, + { + "country": "United Arab Emirates (the)", + "alpha-2": "AE", + "alpha-3": "ARE", + "numeric": "0784", + }, { "country": "United Kingdom of Great Britain and Northern Ireland (the)", "alpha-2": "GB", @@ -357,258 +512,26 @@ shipping_lookup = [ "numeric": "0862", }, {"country": "Viet Nam", "alpha-2": "VN", "alpha-3": "VNM", "numeric": "0704"}, - {"country": "Virgin Islands (British)", "alpha-2": "VG", "alpha-3": "VGB", "numeric": "0092"}, - {"country": "Virgin Islands (U.S.)", "alpha-2": "VI", "alpha-3": "VIR", "numeric": "0850"}, - {"country": "Wallis and Futuna", "alpha-2": "WF", "alpha-3": "WLF", "numeric": "0876"}, + { + "country": "Virgin Islands (British)", + "alpha-2": "VG", + "alpha-3": "VGB", + "numeric": "0092", + }, + { + "country": "Virgin Islands (U.S.)", + "alpha-2": "VI", + "alpha-3": "VIR", + "numeric": "0850", + }, + { + "country": "Wallis and Futuna", + "alpha-2": "WF", + "alpha-3": "WLF", + "numeric": "0876", + }, {"country": "Western Sahara", "alpha-2": "EH", "alpha-3": "ESH", "numeric": "0732"}, {"country": "Yemen", "alpha-2": "YE", "alpha-3": "YEM", "numeric": "0887"}, {"country": "Zambia", "alpha-2": "ZM", "alpha-3": "ZMB", "numeric": "0894"}, {"country": "Zimbabwe", "alpha-2": "ZW", "alpha-3": "ZWE", "numeric": "0716"}, ] - -# TODO: Implement lookup for this. Currently not doable -how_to_array = [ - "https://dbrand.com/how-to-apply/airpower", - "https://dbrand.com/how-to-apply/alienware-13-r3", - "https://dbrand.com/how-to-apply/alienware-15-r3", - "https://dbrand.com/how-to-apply/alienware-17-r4-eye-tracking", - "https://dbrand.com/how-to-apply/alienware-17-r4-no-eye-tracking", - "https://dbrand.com/how-to-apply/alienware-17-r5-eye-tracking", - "https://dbrand.com/how-to-apply/alienware-17-r5-no-eye-tracking", - "https://dbrand.com/how-to-apply/anker-powercore-13000-usb-c", - "https://dbrand.com/how-to-apply/anker-powercore-plus-20100-usb-c", - "https://dbrand.com/how-to-apply/anker-powercore-plus-26800-pd", - "https://dbrand.com/how-to-apply/anker-powercore-slim-10000-pd", - "https://dbrand.com/how-to-apply/apple-18w-usb-c-power-adapter", - "https://dbrand.com/how-to-apply/apple-5w-usb-power-adapter", - "https://dbrand.com/how-to-apply/apple-airpods-gen-1", - "https://dbrand.com/how-to-apply/apple-airpods-gen-2-no-wireless-charging", - "https://dbrand.com/how-to-apply/apple-airpods-gen-2-wireless-charging", - "https://dbrand.com/how-to-apply/apple-airpods-pro", - "https://dbrand.com/how-to-apply/apple-card", - "https://dbrand.com/how-to-apply/apple-pencil", - "https://dbrand.com/how-to-apply/apple-pencil-2", - "https://dbrand.com/how-to-apply/axon-7", - "https://dbrand.com/how-to-apply/blade-14-2014-2016-gtx-970m", - "https://dbrand.com/how-to-apply/blade-14-2016-2017-gtx-1060", - "https://dbrand.com/how-to-apply/blade-stealth-125-early-2016-skylake", - "https://dbrand.com/how-to-apply/blade-stealth-125-late-2016-2017-kaby-lake", - "https://dbrand.com/how-to-apply/blade-stealth-13.3-2017-2018", - "https://dbrand.com/how-to-apply/blade-stealth-13.3-early-2019", - "https://dbrand.com/how-to-apply/blade-stealth-13.3-late-2019", - "https://dbrand.com/how-to-apply/dell-xps-13-2-in-1-7390", - "https://dbrand.com/how-to-apply/dell-xps-13-2-in-1-9365", - "https://dbrand.com/how-to-apply/dell-xps-13-7390", - "https://dbrand.com/how-to-apply/dell-xps-13-9350-9360", - "https://dbrand.com/how-to-apply/dell-xps-15-9550", - "https://dbrand.com/how-to-apply/dell-xps-15-9560", - "https://dbrand.com/how-to-apply/eluktronics-mag-15", - "https://dbrand.com/how-to-apply/essential-phone", - "https://dbrand.com/how-to-apply/eve-v", - "https://dbrand.com/how-to-apply/galaxy-a50", - "https://dbrand.com/how-to-apply/galaxy-a70", - "https://dbrand.com/how-to-apply/galaxy-buds", - "https://dbrand.com/how-to-apply/galaxy-fold", - "https://dbrand.com/how-to-apply/galaxy-note-10", - "https://dbrand.com/how-to-apply/galaxy-note-10-plus", - "https://dbrand.com/how-to-apply/galaxy-note-10-plus-5g", - "https://dbrand.com/how-to-apply/galaxy-note-4", - "https://dbrand.com/how-to-apply/galaxy-note-5", - "https://dbrand.com/how-to-apply/galaxy-note-7", - "https://dbrand.com/how-to-apply/galaxy-note-8", - "https://dbrand.com/how-to-apply/galaxy-note-9", - "https://dbrand.com/how-to-apply/galaxy-note-fe", - "https://dbrand.com/how-to-apply/galaxy-s10", - "https://dbrand.com/how-to-apply/galaxy-s10-5g", - "https://dbrand.com/how-to-apply/galaxy-s10e", - "https://dbrand.com/how-to-apply/galaxy-s10-plus", - "https://dbrand.com/how-to-apply/galaxy-s6", - "https://dbrand.com/how-to-apply/galaxy-s6-active", - "https://dbrand.com/how-to-apply/galaxy-s6-edge", - "https://dbrand.com/how-to-apply/galaxy-s6-edge-plus", - "https://dbrand.com/how-to-apply/galaxy-s7", - "https://dbrand.com/how-to-apply/galaxy-s7-active", - "https://dbrand.com/how-to-apply/galaxy-s7-edge", - "https://dbrand.com/how-to-apply/galaxy-s8", - "https://dbrand.com/how-to-apply/galaxy-s8-active", - "https://dbrand.com/how-to-apply/galaxy-s8-plus", - "https://dbrand.com/how-to-apply/galaxy-s9", - "https://dbrand.com/how-to-apply/galaxy-s9-plus", - "https://dbrand.com/how-to-apply/google-home", - "https://dbrand.com/how-to-apply/honor-8", - "https://dbrand.com/how-to-apply/htc-10", - "https://dbrand.com/how-to-apply/htc-one-m7", - "https://dbrand.com/how-to-apply/htc-one-m8", - "https://dbrand.com/how-to-apply/htc-one-m9", - "https://dbrand.com/how-to-apply/htc-u-ultra", - "https://dbrand.com/how-to-apply/huawei-mate-10", - "https://dbrand.com/how-to-apply/huawei-mate-10-pro", - "https://dbrand.com/how-to-apply/huawei-mate-20", - "https://dbrand.com/how-to-apply/huawei-mate-20-pro", - "https://dbrand.com/how-to-apply/huawei-mate-30-pro", - "https://dbrand.com/how-to-apply/huawei-matebook-x-pro-2018", - "https://dbrand.com/how-to-apply/huawei-matebook-x-pro-2019", - "https://dbrand.com/how-to-apply/huawei-p10", - "https://dbrand.com/how-to-apply/huawei-p10-plus", - "https://dbrand.com/how-to-apply/huawei-p20", - "https://dbrand.com/how-to-apply/huawei-p20-pro", - "https://dbrand.com/how-to-apply/huawei-p30", - "https://dbrand.com/how-to-apply/huawei-p30-pro", - "https://dbrand.com/how-to-apply/huawei-p9", - "https://dbrand.com/how-to-apply/intel-nuc-mainstream-mini-pc", - "https://dbrand.com/how-to-apply/ipad-10.2-2019-gen-7", - "https://dbrand.com/how-to-apply/ipad-9.7-skins-2017-2018", - "https://dbrand.com/how-to-apply/ipad-air-2", - "https://dbrand.com/how-to-apply/ipad-air-3", - "https://dbrand.com/how-to-apply/ipad-mini-4", - "https://dbrand.com/how-to-apply/ipad-mini-5", - "https://dbrand.com/how-to-apply/ipad-pro-105", - "https://dbrand.com/how-to-apply/ipad-pro-11", - "https://dbrand.com/how-to-apply/ipad-pro-12.9-2018-gen-3", - "https://dbrand.com/how-to-apply/ipad-pro-129-2016-gen-1", - "https://dbrand.com/how-to-apply/ipad-pro-129-2017-gen-2", - "https://dbrand.com/how-to-apply/ipad-pro-97-2016", - "https://dbrand.com/how-to-apply/iphone-11", - "https://dbrand.com/how-to-apply/iphone-11-pro", - "https://dbrand.com/how-to-apply/iphone-11-pro-max", - "https://dbrand.com/how-to-apply/iphone-4-4s", - "https://dbrand.com/how-to-apply/iphone-5", - "https://dbrand.com/how-to-apply/iphone-5s", - "https://dbrand.com/how-to-apply/iphone-6", - "https://dbrand.com/how-to-apply/iphone-6-plus", - "https://dbrand.com/how-to-apply/iphone-6s", - "https://dbrand.com/how-to-apply/iphone-6s-plus", - "https://dbrand.com/how-to-apply/iphone-7", - "https://dbrand.com/how-to-apply/iphone-7-plus", - "https://dbrand.com/how-to-apply/iphone-8", - "https://dbrand.com/how-to-apply/iphone-8-plus", - "https://dbrand.com/how-to-apply/iphone-se", - "https://dbrand.com/how-to-apply/iphone-x", - "https://dbrand.com/how-to-apply/iphone-xr", - "https://dbrand.com/how-to-apply/iphone-xs", - "https://dbrand.com/how-to-apply/iphone-xs-max", - "https://dbrand.com/how-to-apply/juul", - "https://dbrand.com/how-to-apply/juul-c1", - "https://dbrand.com/how-to-apply/lenovo-thinkpad-x1-carbon-6th-gen", - "https://dbrand.com/how-to-apply/lenovo-thinkpad-x1-carbon-7th-gen", - "https://dbrand.com/how-to-apply/lg-g3", - "https://dbrand.com/how-to-apply/lg-g4", - "https://dbrand.com/how-to-apply/lg-g5", - "https://dbrand.com/how-to-apply/lg-g6", - "https://dbrand.com/how-to-apply/lg-g7", - "https://dbrand.com/how-to-apply/lg-v20", - "https://dbrand.com/how-to-apply/lg-v30", - "https://dbrand.com/how-to-apply/m40x", - "https://dbrand.com/how-to-apply/m50", - "https://dbrand.com/how-to-apply/m50x", - "https://dbrand.com/how-to-apply/macbook-12-2015-2018-retina", - "https://dbrand.com/how-to-apply/macbook-air-11", - "https://dbrand.com/how-to-apply/macbook-air-13", - "https://dbrand.com/how-to-apply/macbook-air-13-2018-2019", - "https://dbrand.com/how-to-apply/macbook-pro-13-2013-2015-retina", - "https://dbrand.com/how-to-apply/macbook-pro-13-skins-2016-2018-four-thunderbolt", - "https://dbrand.com/how-to-apply/macbook-pro-13-skins-2016-2018-two-thunderbolt", - "https://dbrand.com/how-to-apply/macbook-pro-13-skins-2019-four-thunderbolt", - "https://dbrand.com/how-to-apply/macbook-pro-13-skins-2019-two-thunderbolt", - "https://dbrand.com/how-to-apply/macbook-pro-15-2013-2015-retina", - "https://dbrand.com/how-to-apply/macbook-pro-15-touch-bar", - "https://dbrand.com/how-to-apply/macbook-pro-16-2019", - "https://dbrand.com/how-to-apply/mac-pro-and-pro-display-xdr", - "https://dbrand.com/how-to-apply/maingear-element", - "https://dbrand.com/how-to-apply/moto-g-2013", - "https://dbrand.com/how-to-apply/moto-g-2014", - "https://dbrand.com/how-to-apply/moto-x-2013", - "https://dbrand.com/how-to-apply/moto-x-2014", - "https://dbrand.com/how-to-apply/moto-x4", - "https://dbrand.com/how-to-apply/moto-x-play", - "https://dbrand.com/how-to-apply/moto-x-style-pure", - "https://dbrand.com/how-to-apply/moto-z", - "https://dbrand.com/how-to-apply/moto-z-force", - "https://dbrand.com/how-to-apply/nextbit-robin", - "https://dbrand.com/how-to-apply/nexus-4", - "https://dbrand.com/how-to-apply/nexus-5", - "https://dbrand.com/how-to-apply/nexus-5x", - "https://dbrand.com/how-to-apply/nexus-6", - "https://dbrand.com/how-to-apply/nexus-6p", - "https://dbrand.com/how-to-apply/nexus-7-2012", - "https://dbrand.com/how-to-apply/nexus-7-2013", - "https://dbrand.com/how-to-apply/nexus-9", - "https://dbrand.com/how-to-apply/nintendo-switch", - "https://dbrand.com/how-to-apply/nintendo-switch-lite", - "https://dbrand.com/how-to-apply/nintendo-switch-pro-controller", - "https://dbrand.com/how-to-apply/oneplus-2", - "https://dbrand.com/how-to-apply/oneplus-3", - "https://dbrand.com/how-to-apply/oneplus-3t", - "https://dbrand.com/how-to-apply/oneplus-5", - "https://dbrand.com/how-to-apply/oneplus-5t", - "https://dbrand.com/how-to-apply/oneplus-6", - "https://dbrand.com/how-to-apply/oneplus-6t", - "https://dbrand.com/how-to-apply/oneplus-7", - "https://dbrand.com/how-to-apply/oneplus-7-pro", - "https://dbrand.com/how-to-apply/oneplus-7t", - "https://dbrand.com/how-to-apply/oneplus-7t-pro", - "https://dbrand.com/how-to-apply/oneplus-one", - "https://dbrand.com/how-to-apply/oneplus-x", - "https://dbrand.com/how-to-apply/pebble-time", - "https://dbrand.com/how-to-apply/pebble-watch", - "https://dbrand.com/how-to-apply/pixel", - "https://dbrand.com/how-to-apply/pixel-2", - "https://dbrand.com/how-to-apply/pixel-2-xl", - "https://dbrand.com/how-to-apply/pixel-3", - "https://dbrand.com/how-to-apply/pixel-3a", - "https://dbrand.com/how-to-apply/pixel-3a-xl", - "https://dbrand.com/how-to-apply/pixel-3-xl", - "https://dbrand.com/how-to-apply/pixel-4", - "https://dbrand.com/how-to-apply/pixel-4-xl", - "https://dbrand.com/how-to-apply/pixelbook", - "https://dbrand.com/how-to-apply/pixelbook-go", - "https://dbrand.com/how-to-apply/pixel-xl", - "https://dbrand.com/how-to-apply/playstation-3", - "https://dbrand.com/how-to-apply/playstation-4", - "https://dbrand.com/how-to-apply/playstation-4-pro", - "https://dbrand.com/how-to-apply/playstation-4-slim", - "https://dbrand.com/how-to-apply/playstation-vita", - "https://dbrand.com/how-to-apply/pocophone-f1", - "https://dbrand.com/how-to-apply/razer-blade-15.6-skins-2018-advanced-no-ethernet-gtx", - "https://dbrand.com/how-to-apply/razer-blade-15.6-skins-2018-base-with-ethernet-gtx", - "https://dbrand.com/how-to-apply/razer-blade-15.6-skins-2019-advanced-no-ethernet-rtx", - "https://dbrand.com/how-to-apply/razer-blade-pro-17-2019", - "https://dbrand.com/how-to-apply/razer-phone", - "https://dbrand.com/how-to-apply/razer-phone-2", - "https://dbrand.com/how-to-apply/redmi-k20", - "https://dbrand.com/how-to-apply/redmi-k20-pro", - "https://dbrand.com/how-to-apply/surface-book", - "https://dbrand.com/how-to-apply/surface-book-2-13", - "https://dbrand.com/how-to-apply/surface-book-2-15", - "https://dbrand.com/how-to-apply/surface-go", - "https://dbrand.com/how-to-apply/surface-laptop", - "https://dbrand.com/how-to-apply/surface-laptop-2", - "https://dbrand.com/how-to-apply/surface-laptop-3-13", - "https://dbrand.com/how-to-apply/surface-laptop-3-15", - "https://dbrand.com/how-to-apply/surface-pro-2017", - "https://dbrand.com/how-to-apply/surface-pro-4", - "https://dbrand.com/how-to-apply/surface-pro-6", - "https://dbrand.com/how-to-apply/surface-pro-7", - "https://dbrand.com/how-to-apply/surface-pro-x", - "https://dbrand.com/how-to-apply/tesla-cybertruck", - "https://dbrand.com/how-to-apply/xbox-360", - "https://dbrand.com/how-to-apply/xbox-one", - "https://dbrand.com/how-to-apply/xbox-one-s", - "https://dbrand.com/how-to-apply/xbox-one-x", - "https://dbrand.com/how-to-apply/xiaomi-mi-9t", - "https://dbrand.com/how-to-apply/xiaomi-mi-9t-pro", - "https://dbrand.com/how-to-apply/xperia-z1", - "https://dbrand.com/how-to-apply/xperia-z2", - "https://dbrand.com/how-to-apply/xperia-z3", - "https://dbrand.com/how-to-apply/xperia-z3-compact", - "https://dbrand.com/how-to-apply/xperia-z5", - "https://dbrand.com/how-to-apply/xperia-z5-compact", - "https://dbrand.com/how-to-apply/xperia-z5-premium", - "https://dbrand.com/how-to-apply/xperia-z-ultra", - "https://dbrand.com/how-to-apply/xps-13-9370", - "https://dbrand.com/how-to-apply/xps-13-9380", - "https://dbrand.com/how-to-apply/xps-15-2-in-1-9575", - "https://dbrand.com/how-to-apply/xps-15-7590", - "https://dbrand.com/how-to-apply/xps-15-9570", - "https://dbrand.com/how-to-apply/zenfone-2", -] diff --git a/jarvis/utils/__init__.py b/jarvis/utils/__init__.py index 44319f7..3b8dfbe 100644 --- a/jarvis/utils/__init__.py +++ b/jarvis/utils/__init__.py @@ -45,7 +45,7 @@ def modlog_embed( fields = [ EmbedField( name="Moderator", - value=f"{admin.mention} ({admin.username}#{admin.discriminator})", + value=f"{admin.mention} ({admin.username})", ), ] if log and log.reason: @@ -59,7 +59,7 @@ def modlog_embed( timestamp=log.created_at, ) embed.set_author(name=f"{member.username}", icon_url=member.display_avatar.url) - embed.set_footer(text=f"{member.username}#{member.discriminator} | {member.id}") + embed.set_footer(text=f"{member.username} | {member.id}") return embed diff --git a/jarvis/utils/cogs.py b/jarvis/utils/cogs.py index 5a527cb..ae53619 100644 --- a/jarvis/utils/cogs.py +++ b/jarvis/utils/cogs.py @@ -68,19 +68,31 @@ class ModcaseCog(Extension): return action = await coll.find_one( - coll.user == user.id, coll.guild == ctx.guild.id, coll.active == True, sort=[("_id", -1)] + coll.user == user.id, + coll.guild == ctx.guild.id, + coll.active == True, + sort=[("_id", -1)], ) if not action: self.logger.warning("Missing action %s, exiting", name) return notify = await Setting.find_one( - Setting.guild == ctx.guild.id, Setting.setting == "notify", Setting.value == True + Setting.guild == ctx.guild.id, + Setting.setting == "notify", + Setting.value == True, ) - if notify and name not in ("Kick", "Ban"): # Ignore Kick and Ban, as these are unique + if notify and name not in ( + "Kick", + "Ban", + ): # Ignore Kick and Ban, as these are unique fields = ( EmbedField(name="Action Type", value=name, inline=False), - EmbedField(name="Reason", value=kwargs.get("reason", None) or "N/A", inline=False), + EmbedField( + name="Reason", + value=kwargs.get("reason", None) or "N/A", + inline=False, + ), ) embed = build_embed( title="Admin action taken", @@ -89,16 +101,24 @@ class ModcaseCog(Extension): ) if name == "Mute": mts = int(user.communication_disabled_until.timestamp()) - embed.add_field(name="Muted Until", value=f" ()") + embed.add_field( + name="Muted Until", value=f" ()" + ) guild_url = f"https://discord.com/channels/{ctx.guild.id}" - embed.set_author(name=ctx.guild.name, icon_url=ctx.guild.icon.url, url=guild_url) + embed.set_author( + name=ctx.guild.name, icon_url=ctx.guild.icon.url, url=guild_url + ) embed.set_thumbnail(url=ctx.guild.icon.url) try: await user.send(embeds=embed) except Exception: self.logger.debug("User not warned of action due to closed DMs") - modlog = await Modlog.find_one(Modlog.user == user.id, Modlog.guild == ctx.guild.id, Modlog.open == True) + modlog = await Modlog.find_one( + Modlog.user == user.id, + Modlog.guild == ctx.guild.id, + Modlog.open == True, + ) if modlog: m_action = Action(action_type=name.lower(), parent=action.id) @@ -106,7 +126,9 @@ class ModcaseCog(Extension): await modlog.save() return - modlog = await Setting.find_one(Setting.guild == ctx.guild.id, Setting.setting == "modlog") + modlog = await Setting.find_one( + Setting.guild == ctx.guild.id, Setting.setting == "modlog" + ) if not modlog: return @@ -114,7 +136,11 @@ class ModcaseCog(Extension): if channel: fields = ( EmbedField(name="Action Type", value=name, inline=False), - EmbedField(name="Reason", value=kwargs.get("reason", None) or "N/A", inline=False), + EmbedField( + name="Reason", + value=kwargs.get("reason", None) or "N/A", + inline=False, + ), EmbedField(name="Admin", value=ctx.author.mention, inline=False), ) embed = build_embed( @@ -122,23 +148,31 @@ class ModcaseCog(Extension): description=f"Admin action has been taken against {user.mention}", fields=fields, ) - embed.set_author(name=f"{user.username}#{user.discriminator}", icon_url=user.display_avatar.url) + embed.set_author( + name=f"{user.username}", icon_url=user.display_avatar.url + ) embed.set_footer(text=f"User ID: {user.id}") if name == "Mute": mts = int(user.communication_disabled_until.timestamp()) - embed.add_field(name="Muted Until", value=f" ()") + embed.add_field( + name="Muted Until", value=f" ()" + ) await channel.send(embeds=embed) lookup_key = f"{user.id}|{ctx.guild.id}" async with self.bot.redis.lock("lock|" + lookup_key): if await self.bot.redis.get(lookup_key): - self.logger.debug(f"User {user.id} in {ctx.guild.id} already has pending case") + self.logger.debug( + f"User {user.id} in {ctx.guild.id} already has pending case" + ) return channel = await ctx.guild.fetch_channel(modlog.value) if not channel: - self.logger.warn(f"Guild {ctx.guild.id} modlog channel no longer exists, deleting") + self.logger.warn( + f"Guild {ctx.guild.id} modlog channel no longer exists, deleting" + ) await modlog.delete() return @@ -150,14 +184,22 @@ class ModcaseCog(Extension): avatar_url = user.avatar.url if isinstance(user, Member): avatar_url = user.display_avatar.url - embed.set_author(name=user.username + "#" + user.discriminator, icon_url=avatar_url) + embed.set_author(name=user.username, icon_url=avatar_url) components = [ ActionRow( - Button(style=ButtonStyle.RED, emoji="✖️", custom_id="modcase|no"), - Button(style=ButtonStyle.GREEN, emoji="✔️", custom_id="modcase|yes"), + Button( + style=ButtonStyle.RED, emoji="✖️", custom_id="modcase|no" + ), + Button( + style=ButtonStyle.GREEN, emoji="✔️", custom_id="modcase|yes" + ), ) ] message = await channel.send(embeds=embed, components=components) - await self.bot.redis.set(lookup_key, f"{name.lower()}|{action.id}", ex=timedelta(days=7)) - await self.bot.redis.set(f"msg|{message.id}", user.id, ex=timedelta(days=7)) + await self.bot.redis.set( + lookup_key, f"{name.lower()}|{action.id}", ex=timedelta(days=7) + ) + await self.bot.redis.set( + f"msg|{message.id}", user.id, ex=timedelta(days=7) + ) diff --git a/poetry.lock b/poetry.lock index 051517e..b673662 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,10 +1,9 @@ -# This file is automatically @generated by Poetry and should not be changed by hand. +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. [[package]] name = "aiofile" version = "3.8.5" description = "Asynchronous file operations." -category = "main" optional = false python-versions = ">=3.7, <4" files = [ @@ -22,7 +21,6 @@ develop = ["aiomisc-pytest", "coveralls", "pytest", "pytest-cov", "pytest-rst"] name = "aiofiles" version = "0.8.0" description = "File support for asyncio." -category = "main" optional = false python-versions = ">=3.6,<4.0" files = [ @@ -34,7 +32,6 @@ files = [ name = "aiohttp" version = "3.8.4" description = "Async http client/server framework (asyncio)" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -143,7 +140,6 @@ speedups = ["Brotli", "aiodns", "cchardet"] name = "aiosignal" version = "1.3.1" description = "aiosignal: a list of registered asynchronous callbacks" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -158,7 +154,6 @@ frozenlist = ">=1.1.0" name = "aiosqlite" version = "0.17.0" description = "asyncio bridge to the standard sqlite3 module" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -173,7 +168,6 @@ typing_extensions = ">=3.7.2" name = "ansicon" version = "1.89.0" description = "Python wrapper for loading Jason Hood's ANSICON" -category = "main" optional = false python-versions = "*" files = [ @@ -185,7 +179,6 @@ files = [ name = "ansitoimg" version = "2022.2" description = "Convert an ANSI string to an image. Great for adding terminal output into a readme." -category = "main" optional = false python-versions = ">=3.7,<4.0" files = [ @@ -202,7 +195,6 @@ rich = ">=12.5.1,<13" name = "appdirs" version = "1.4.4" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "main" optional = false python-versions = "*" files = [ @@ -214,7 +206,6 @@ files = [ name = "async-generator" version = "1.10" description = "Async generators and context managers for Python 3.5+" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -226,7 +217,6 @@ files = [ name = "async-timeout" version = "4.0.2" description = "Timeout context manager for asyncio programs" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -238,7 +228,6 @@ files = [ name = "asyncio-extras" version = "1.3.2" description = "Asynchronous generators, context managers and more for asyncio" -category = "main" optional = false python-versions = "*" files = [ @@ -257,7 +246,6 @@ test = ["pytest", "pytest-asyncio", "pytest-cov"] name = "asyncpraw" version = "7.7.0" description = "Async PRAW, an abbreviation for \"Asynchronous Python Reddit API Wrapper\", is a python package that allows for simple access to Reddit's API." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -275,16 +263,15 @@ update-checker = ">=0.18" [package.extras] ci = ["coveralls"] -dev = ["asynctest (>=0.13.0,<0.14.0)", "mock (>=4.0.0,<5.0.0)", "packaging", "pre-commit", "pytest (>=7.0.0,<8.0.0)", "pytest-asyncio (>=0.18.0,<0.19.0)", "pytest-vcr (>=1.0.0,<2.0.0)", "sphinx", "sphinx-rtd-dark-mode", "sphinx-rtd-theme", "sphinxcontrib-trio", "testfixtures (>=6.0.0,<7.0.0)", "vcrpy (>=4.0.0,<5.0.0)"] +dev = ["asynctest (==0.13.*)", "mock (==4.*)", "packaging", "pre-commit", "pytest (==7.*)", "pytest-asyncio (==0.18.*)", "pytest-vcr (==1.*)", "sphinx", "sphinx-rtd-dark-mode", "sphinx-rtd-theme", "sphinxcontrib-trio", "testfixtures (==6.*)", "vcrpy (==4.*)"] lint = ["pre-commit", "sphinx", "sphinx-rtd-dark-mode", "sphinx-rtd-theme", "sphinxcontrib-trio"] readthedocs = ["sphinx", "sphinx-rtd-dark-mode", "sphinx-rtd-theme", "sphinxcontrib-trio"] -test = ["asynctest (>=0.13.0,<0.14.0)", "mock (>=4.0.0,<5.0.0)", "pytest (>=7.0.0,<8.0.0)", "pytest-asyncio (>=0.18.0,<0.19.0)", "pytest-vcr (>=1.0.0,<2.0.0)", "testfixtures (>=6.0.0,<7.0.0)", "vcrpy (>=4.0.0,<5.0.0)"] +test = ["asynctest (==0.13.*)", "mock (==4.*)", "pytest (==7.*)", "pytest-asyncio (==0.18.*)", "pytest-vcr (==1.*)", "testfixtures (==6.*)", "vcrpy (==4.*)"] [[package]] name = "asyncprawcore" version = "2.3.0" description = "Low-level asynchronous communication layer for Async PRAW 7+." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -304,33 +291,31 @@ test = ["asynctest (>=0.13.0)", "mock (>=0.8)", "pytest", "pytest-vcr", "testfix [[package]] name = "attrs" -version = "22.2.0" +version = "23.1.0" description = "Classes Without Boilerplate" -category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"}, - {file = "attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"}, + {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, + {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, ] [package.extras] -cov = ["attrs[tests]", "coverage-enable-subprocess", "coverage[toml] (>=5.3)"] -dev = ["attrs[docs,tests]"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope.interface"] -tests = ["attrs[tests-no-zope]", "zope.interface"] -tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy (>=0.971,<0.990)", "mypy (>=0.971,<0.990)", "pympler", "pympler", "pytest (>=4.3.0)", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-mypy-plugins", "pytest-xdist[psutil]", "pytest-xdist[psutil]"] +cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] +dev = ["attrs[docs,tests]", "pre-commit"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] +tests = ["attrs[tests-no-zope]", "zope-interface"] +tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] [[package]] name = "beanie" -version = "1.17.0" +version = "1.19.0" description = "Asynchronous Python ODM for MongoDB" -category = "main" optional = false python-versions = ">=3.7,<4.0" files = [ - {file = "beanie-1.17.0-py3-none-any.whl", hash = "sha256:a0711775051c72324fc4555120355da9a3c081d41db14ddaa8e9f368303436ef"}, - {file = "beanie-1.17.0.tar.gz", hash = "sha256:5f758785ce813838a0f25e171957afb6e70fa142dda937531427e0a530d03c64"}, + {file = "beanie-1.19.0-py3-none-any.whl", hash = "sha256:b8f61c1e15eac43e0fe62b01d1b5f520b8f69ece5ca5b8672c0bfeb560ca873c"}, + {file = "beanie-1.19.0.tar.gz", hash = "sha256:31a95a17b3059f232510279f09ebb1221c5fa5d71e28368752f600bc05a10046"}, ] [package.dependencies] @@ -342,14 +327,13 @@ toml = "*" [[package]] name = "beautifulsoup4" -version = "4.12.0" +version = "4.12.2" description = "Screen-scraping library" -category = "main" optional = false python-versions = ">=3.6.0" files = [ - {file = "beautifulsoup4-4.12.0-py3-none-any.whl", hash = "sha256:2130a5ad7f513200fae61a17abb5e338ca980fa28c439c0571014bc0217e9591"}, - {file = "beautifulsoup4-4.12.0.tar.gz", hash = "sha256:c5fceeaec29d09c84970e47c65f2f0efe57872f7cff494c9691a26ec0ff13234"}, + {file = "beautifulsoup4-4.12.2-py3-none-any.whl", hash = "sha256:bd2520ca0d9d7d12694a53d44ac482d181b4ec1888909b035a3dbf40d0f57d4a"}, + {file = "beautifulsoup4-4.12.2.tar.gz", hash = "sha256:492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da"}, ] [package.dependencies] @@ -361,37 +345,36 @@ lxml = ["lxml"] [[package]] name = "black" -version = "23.1.0" +version = "23.3.0" description = "The uncompromising code formatter." -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "black-23.1.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:b6a92a41ee34b883b359998f0c8e6eb8e99803aa8bf3123bf2b2e6fec505a221"}, - {file = "black-23.1.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:57c18c5165c1dbe291d5306e53fb3988122890e57bd9b3dcb75f967f13411a26"}, - {file = "black-23.1.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:9880d7d419bb7e709b37e28deb5e68a49227713b623c72b2b931028ea65f619b"}, - {file = "black-23.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e6663f91b6feca5d06f2ccd49a10f254f9298cc1f7f49c46e498a0771b507104"}, - {file = "black-23.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:9afd3f493666a0cd8f8df9a0200c6359ac53940cbde049dcb1a7eb6ee2dd7074"}, - {file = "black-23.1.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:bfffba28dc52a58f04492181392ee380e95262af14ee01d4bc7bb1b1c6ca8d27"}, - {file = "black-23.1.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:c1c476bc7b7d021321e7d93dc2cbd78ce103b84d5a4cf97ed535fbc0d6660648"}, - {file = "black-23.1.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:382998821f58e5c8238d3166c492139573325287820963d2f7de4d518bd76958"}, - {file = "black-23.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bf649fda611c8550ca9d7592b69f0637218c2369b7744694c5e4902873b2f3a"}, - {file = "black-23.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:121ca7f10b4a01fd99951234abdbd97728e1240be89fde18480ffac16503d481"}, - {file = "black-23.1.0-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:a8471939da5e824b891b25751955be52ee7f8a30a916d570a5ba8e0f2eb2ecad"}, - {file = "black-23.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8178318cb74f98bc571eef19068f6ab5613b3e59d4f47771582f04e175570ed8"}, - {file = "black-23.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:a436e7881d33acaf2536c46a454bb964a50eff59b21b51c6ccf5a40601fbef24"}, - {file = "black-23.1.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:a59db0a2094d2259c554676403fa2fac3473ccf1354c1c63eccf7ae65aac8ab6"}, - {file = "black-23.1.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:0052dba51dec07ed029ed61b18183942043e00008ec65d5028814afaab9a22fd"}, - {file = "black-23.1.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:49f7b39e30f326a34b5c9a4213213a6b221d7ae9d58ec70df1c4a307cf2a1580"}, - {file = "black-23.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:162e37d49e93bd6eb6f1afc3e17a3d23a823042530c37c3c42eeeaf026f38468"}, - {file = "black-23.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b70eb40a78dfac24842458476135f9b99ab952dd3f2dab738c1881a9b38b753"}, - {file = "black-23.1.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:a29650759a6a0944e7cca036674655c2f0f63806ddecc45ed40b7b8aa314b651"}, - {file = "black-23.1.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:bb460c8561c8c1bec7824ecbc3ce085eb50005883a6203dcfb0122e95797ee06"}, - {file = "black-23.1.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:c91dfc2c2a4e50df0026f88d2215e166616e0c80e86004d0003ece0488db2739"}, - {file = "black-23.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a951cc83ab535d248c89f300eccbd625e80ab880fbcfb5ac8afb5f01a258ac9"}, - {file = "black-23.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:0680d4380db3719ebcfb2613f34e86c8e6d15ffeabcf8ec59355c5e7b85bb555"}, - {file = "black-23.1.0-py3-none-any.whl", hash = "sha256:7a0f701d314cfa0896b9001df70a530eb2472babb76086344e688829efd97d32"}, - {file = "black-23.1.0.tar.gz", hash = "sha256:b0bd97bea8903f5a2ba7219257a44e3f1f9d00073d6cc1add68f0beec69692ac"}, + {file = "black-23.3.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:0945e13506be58bf7db93ee5853243eb368ace1c08a24c65ce108986eac65915"}, + {file = "black-23.3.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:67de8d0c209eb5b330cce2469503de11bca4085880d62f1628bd9972cc3366b9"}, + {file = "black-23.3.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:7c3eb7cea23904399866c55826b31c1f55bbcd3890ce22ff70466b907b6775c2"}, + {file = "black-23.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32daa9783106c28815d05b724238e30718f34155653d4d6e125dc7daec8e260c"}, + {file = "black-23.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:35d1381d7a22cc5b2be2f72c7dfdae4072a3336060635718cc7e1ede24221d6c"}, + {file = "black-23.3.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:a8a968125d0a6a404842fa1bf0b349a568634f856aa08ffaff40ae0dfa52e7c6"}, + {file = "black-23.3.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:c7ab5790333c448903c4b721b59c0d80b11fe5e9803d8703e84dcb8da56fec1b"}, + {file = "black-23.3.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:a6f6886c9869d4daae2d1715ce34a19bbc4b95006d20ed785ca00fa03cba312d"}, + {file = "black-23.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f3c333ea1dd6771b2d3777482429864f8e258899f6ff05826c3a4fcc5ce3f70"}, + {file = "black-23.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:11c410f71b876f961d1de77b9699ad19f939094c3a677323f43d7a29855fe326"}, + {file = "black-23.3.0-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:1d06691f1eb8de91cd1b322f21e3bfc9efe0c7ca1f0e1eb1db44ea367dff656b"}, + {file = "black-23.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50cb33cac881766a5cd9913e10ff75b1e8eb71babf4c7104f2e9c52da1fb7de2"}, + {file = "black-23.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:e114420bf26b90d4b9daa597351337762b63039752bdf72bf361364c1aa05925"}, + {file = "black-23.3.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:48f9d345675bb7fbc3dd85821b12487e1b9a75242028adad0333ce36ed2a6d27"}, + {file = "black-23.3.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:714290490c18fb0126baa0fca0a54ee795f7502b44177e1ce7624ba1c00f2331"}, + {file = "black-23.3.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:064101748afa12ad2291c2b91c960be28b817c0c7eaa35bec09cc63aa56493c5"}, + {file = "black-23.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:562bd3a70495facf56814293149e51aa1be9931567474993c7942ff7d3533961"}, + {file = "black-23.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:e198cf27888ad6f4ff331ca1c48ffc038848ea9f031a3b40ba36aced7e22f2c8"}, + {file = "black-23.3.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:3238f2aacf827d18d26db07524e44741233ae09a584273aa059066d644ca7b30"}, + {file = "black-23.3.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:f0bd2f4a58d6666500542b26354978218a9babcdc972722f4bf90779524515f3"}, + {file = "black-23.3.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:92c543f6854c28a3c7f39f4d9b7694f9a6eb9d3c5e2ece488c327b6e7ea9b266"}, + {file = "black-23.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a150542a204124ed00683f0db1f5cf1c2aaaa9cc3495b7a3b5976fb136090ab"}, + {file = "black-23.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:6b39abdfb402002b8a7d030ccc85cf5afff64ee90fa4c5aebc531e3ad0175ddb"}, + {file = "black-23.3.0-py3-none-any.whl", hash = "sha256:ec751418022185b0c1bb7d7736e6933d40bbb14c14a0abcf9123d1b159f98dd4"}, + {file = "black-23.3.0.tar.gz", hash = "sha256:1c7b8d606e728a41ea1ccbd7264677e494e87cf630e399262ced92d4a8dac940"}, ] [package.dependencies] @@ -400,7 +383,6 @@ mypy-extensions = ">=0.4.3" packaging = ">=22.0" pathspec = ">=0.9.0" platformdirs = ">=2" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} [package.extras] colorama = ["colorama (>=0.4.3)"] @@ -412,7 +394,6 @@ uvloop = ["uvloop (>=0.15.2)"] name = "blessed" version = "1.20.0" description = "Easy, practical library for making terminal apps, by providing an elegant, well-documented interface to Colors, Keyboard input, and screen Positioning capabilities." -category = "main" optional = false python-versions = ">=2.7" files = [ @@ -429,7 +410,6 @@ wcwidth = ">=0.1.4" name = "caio" version = "0.9.12" description = "Asynchronous file IO for Linux MacOS or Windows." -category = "main" optional = false python-versions = ">=3.7, <4" files = [ @@ -463,7 +443,6 @@ develop = ["aiomisc-pytest", "pytest", "pytest-cov"] name = "calculator" version = "1.0.0" description = "A simple calculator" -category = "main" optional = false python-versions = ">=3.10" files = [] @@ -477,21 +456,19 @@ resolved_reference = "b317d35788c6a06f2b496844d5fdf4e3414453e6" [[package]] name = "certifi" -version = "2022.12.7" +version = "2023.5.7" description = "Python package for providing Mozilla's CA Bundle." -category = "main" optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"}, - {file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"}, + {file = "certifi-2023.5.7-py3-none-any.whl", hash = "sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"}, + {file = "certifi-2023.5.7.tar.gz", hash = "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7"}, ] [[package]] name = "cfgv" version = "3.3.1" description = "Validate configuration and produce human readable error messages." -category = "dev" optional = false python-versions = ">=3.6.1" files = [ @@ -503,7 +480,6 @@ files = [ name = "charset-normalizer" version = "3.1.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "main" optional = false python-versions = ">=3.7.0" files = [ @@ -588,7 +564,6 @@ files = [ name = "click" version = "8.1.3" description = "Composable command line interface toolkit" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -603,7 +578,6 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} name = "codefind" version = "0.1.3" description = "Find code objects and their referents" -category = "main" optional = false python-versions = ">=3.8,<4.0" files = [ @@ -615,7 +589,6 @@ files = [ name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ @@ -627,7 +600,6 @@ files = [ name = "commonmark" version = "0.9.1" description = "Python parser for the CommonMark Markdown spec" -category = "main" optional = false python-versions = "*" files = [ @@ -638,11 +610,24 @@ files = [ [package.extras] test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"] +[[package]] +name = "croniter" +version = "1.4.1" +description = "croniter provides iteration for datetime object with cron like format" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "croniter-1.4.1-py2.py3-none-any.whl", hash = "sha256:9595da48af37ea06ec3a9f899738f1b2c1c13da3c38cea606ef7cd03ea421128"}, + {file = "croniter-1.4.1.tar.gz", hash = "sha256:1a6df60eacec3b7a0aa52a8f2ef251ae3dd2a7c7c8b9874e73e791636d55a361"}, +] + +[package.dependencies] +python-dateutil = "*" + [[package]] name = "dateparser" version = "1.1.8" description = "Date parsing library designed to parse dates from HTML pages" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -665,7 +650,6 @@ langdetect = ["langdetect"] name = "discord-typings" version = "0.5.1" description = "Maintained typings of payloads that Discord sends" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -680,7 +664,6 @@ typing_extensions = ">=4.3,<5" name = "distlib" version = "0.3.6" description = "Distribution utilities" -category = "dev" optional = false python-versions = "*" files = [ @@ -692,7 +675,6 @@ files = [ name = "dnspython" version = "2.3.0" description = "DNS toolkit" -category = "main" optional = false python-versions = ">=3.7,<4.0" files = [ @@ -713,7 +695,6 @@ wmi = ["wmi (>=1.5.1,<2.0.0)"] name = "emoji" version = "2.2.0" description = "Emoji for Python" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -723,27 +704,44 @@ files = [ [package.extras] dev = ["coverage", "coveralls", "pytest"] +[[package]] +name = "erapi" +version = "0.1.0" +description = "" +optional = false +python-versions = ">=3.10,<4" +files = [] +develop = false + +[package.dependencies] +aiohttp = ">=3.8.4" +requests = ">=2.31.0" + +[package.source] +type = "git" +url = "https://git.zevaryx.com/zevaryx-technologies/erapi.git" +reference = "HEAD" +resolved_reference = "0f13217902aaf3e575f3afabb09bd76e1134833b" + [[package]] name = "filelock" -version = "3.10.4" +version = "3.12.0" description = "A platform independent file lock." -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "filelock-3.10.4-py3-none-any.whl", hash = "sha256:6d332dc5c896f18ba93a21d987155e97c434a96d3fe4042ca70d0b3b46e3b470"}, - {file = "filelock-3.10.4.tar.gz", hash = "sha256:9fc1734dbddcdcd4aaa02c160dd94db5272b92dfa859b44ec8df28e160b751f0"}, + {file = "filelock-3.12.0-py3-none-any.whl", hash = "sha256:ad98852315c2ab702aeb628412cbf7e95b7ce8c3bf9565670b4eaecf1db370a9"}, + {file = "filelock-3.12.0.tar.gz", hash = "sha256:fc03ae43288c013d2ea83c8597001b1129db351aad9c57fe2409327916b8e718"}, ] [package.extras] -docs = ["furo (>=2022.12.7)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.2.2)", "pytest (>=7.2.2)", "pytest-cov (>=4)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2023.3.27)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] [[package]] name = "frozenlist" version = "1.3.3" description = "A list-like structure which implements collections.abc.MutableSequence" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -827,7 +825,6 @@ files = [ name = "gitdb" version = "4.0.10" description = "Git Object Database" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -842,7 +839,6 @@ smmap = ">=3.0.1,<6" name = "gitpython" version = "3.1.31" description = "GitPython is a Python library used to interact with Git repositories" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -855,14 +851,13 @@ gitdb = ">=4.0.1,<5" [[package]] name = "identify" -version = "2.5.21" +version = "2.5.24" description = "File identification library for Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "identify-2.5.21-py2.py3-none-any.whl", hash = "sha256:69edcaffa8e91ae0f77d397af60f148b6b45a8044b2cc6d99cafa5b04793ff00"}, - {file = "identify-2.5.21.tar.gz", hash = "sha256:7671a05ef9cfaf8ff63b15d45a91a1147a03aaccb2976d4e9bd047cbbc508471"}, + {file = "identify-2.5.24-py2.py3-none-any.whl", hash = "sha256:986dbfb38b1140e763e413e6feb44cd731faf72d1909543178aa79b0e258265d"}, + {file = "identify-2.5.24.tar.gz", hash = "sha256:0aac67d5b4812498056d28a9a512a483f5085cc28640b02b258a59dac34301d4"}, ] [package.extras] @@ -872,7 +867,6 @@ license = ["ukkonen"] name = "idna" version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -882,14 +876,13 @@ files = [ [[package]] name = "importlib-metadata" -version = "6.1.0" +version = "6.6.0" description = "Read metadata from Python packages" -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "importlib_metadata-6.1.0-py3-none-any.whl", hash = "sha256:ff80f3b5394912eb1b108fcfd444dc78b7f1f3e16b16188054bd01cb9cb86f09"}, - {file = "importlib_metadata-6.1.0.tar.gz", hash = "sha256:43ce9281e097583d758c2c708c4376371261a02c34682491a8e98352365aad20"}, + {file = "importlib_metadata-6.6.0-py3-none-any.whl", hash = "sha256:43dd286a2cd8995d5eaef7fee2066340423b818ed3fd70adf0bad5f1fac53fed"}, + {file = "importlib_metadata-6.6.0.tar.gz", hash = "sha256:92501cdf9cc66ebd3e612f1b4f0c0765dfa42f0fa38ffb319b6bd84dd675d705"}, ] [package.dependencies] @@ -901,70 +894,65 @@ perf = ["ipython"] testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] [[package]] -name = "interactions" -version = "5.0.0" +name = "interactions-py" +version = "5.3.1" description = "Easy, simple, scalable and modular: a Python API wrapper for interactions." -category = "main" optional = false -python-versions = ">=3.10,<4.0" -files = [] -develop = false +python-versions = ">=3.10" +files = [ + {file = "interactions.py-5.3.1-py3-none-any.whl", hash = "sha256:dbc6e15b46926987e3cbd198b536976ea7bc2b87355848c3b96e77da0ad120c1"}, + {file = "interactions.py-5.3.1.tar.gz", hash = "sha256:c09b505630a33b52b3facc44837eb6c55e88e916c6302e1d6ce45b6c2d237c02"}, +] [package.dependencies] -aiohttp = "^3.8.3" -attrs = ">=22.1.0" -discord-typings = "^0.5.1" -emoji = "^2.1.0" -mypy = ">0.930" -tomli = "^2.0.1" +aiohttp = "*" +attrs = "*" +discord-typings = ">=0.5.1" +emoji = "*" +tomli = "*" [package.extras] -console = [] -docs = ["mkdocs-autorefs", "mkdocs-awesome-pages-plugin", "mkdocs-git-committers-plugin-2", "mkdocs-git-revision-date-localized-plugin", "mkdocs-material", "mkdocs-minify-plugin", "mkdocstrings-python"] -jurigged = [] -sentry = [] +all = ["Brotli", "PyNaCl (>=1.5.0,<1.6)", "aioconsole (>=0.6.0)", "aiodns", "faust-cchardet", "jurigged", "orjson", "sentry-sdk", "uvloop"] +console = ["aioconsole (>=0.6.0)"] +dev = ["Brotli", "PyNaCl (>=1.5.0,<1.6)", "aioconsole (>=0.6.0)", "aiodns", "faust-cchardet", "jurigged", "mkdocs-autorefs", "mkdocs-awesome-pages-plugin", "mkdocs-git-committers-plugin-2", "mkdocs-git-revision-date-localized-plugin", "mkdocs-material", "mkdocs-minify-plugin", "mkdocstrings-python", "orjson", "pre-commit", "pytest", "pytest-asyncio", "pytest-cov", "python-dotenv", "sentry-sdk", "typeguard", "uvloop"] +docs = ["Brotli", "PyNaCl (>=1.5.0,<1.6)", "aioconsole (>=0.6.0)", "aiodns", "faust-cchardet", "jurigged", "mkdocs-autorefs", "mkdocs-awesome-pages-plugin", "mkdocs-git-committers-plugin-2", "mkdocs-git-revision-date-localized-plugin", "mkdocs-material", "mkdocs-minify-plugin", "mkdocstrings-python", "orjson", "sentry-sdk", "uvloop"] +jurigged = ["jurigged"] +sentry = ["sentry-sdk"] speedup = ["Brotli", "aiodns", "faust-cchardet", "orjson", "uvloop"] -tests = ["pytest", "pytest-asyncio", "pytest-cov", "pytest-recording", "python-dotenv", "typeguard"] -voice = [] - -[package.source] -type = "git" -url = "https://github.com/interactions-py/interactions.py" -reference = "5.x" -resolved_reference = "8879c856ba45c419b5ac274ea1023b583d1a86b5" +tests = ["pytest", "pytest-asyncio", "pytest-cov", "python-dotenv", "typeguard"] +voice = ["PyNaCl (>=1.5.0,<1.6)"] [[package]] name = "jarvis-core" -version = "0.16.1" +version = "0.17.0" description = "JARVIS core" -category = "main" optional = false -python-versions = "^3.10" +python-versions = ">=3.10,<4" files = [] develop = false [package.dependencies] aiohttp = "^3.8.1" +beanie = "^1.17.0" motor = "^3.1.1" nanoid = "^2.0.0" orjson = "^3.6.6" +pydantic = "^1.10.7" python-dotenv = "^0.21.0" pytz = "^2022.1" PyYAML = "^6.0" rich = "^12.3.0" -umongo = "^3.1.0" [package.source] type = "git" url = "https://git.zevaryx.com/stark-industries/jarvis/jarvis-core.git" -reference = "main" -resolved_reference = "ec4219e5a54bea78ff19f23f1754a036e8d0eae3" +reference = "beanie" +resolved_reference = "e04661bc46fd67ba062948ec7958d2e8c0f22f7f" [[package]] name = "jinxed" version = "1.2.0" description = "Jinxed Terminal Library" -category = "main" optional = false python-versions = "*" files = [ @@ -979,7 +967,6 @@ ansicon = {version = "*", markers = "platform_system == \"Windows\""} name = "jurigged" version = "0.5.5" description = "Live update of Python functions" -category = "main" optional = false python-versions = ">=3.8,<4.0" files = [ @@ -1000,7 +987,6 @@ develoop = ["giving (>=0.4.1,<0.5.0)", "rich (>=10.13.0)"] name = "lazy-model" version = "0.0.5" description = "" -category = "main" optional = false python-versions = ">=3.7,<4.0" files = [ @@ -1013,150 +999,127 @@ pydantic = ">=1.9.0" [[package]] name = "levenshtein" -version = "0.20.9" +version = "0.21.0" description = "Python extension for computing string edit distances and similarities." -category = "main" optional = false python-versions = ">=3.6" files = [ - {file = "Levenshtein-0.20.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:105c239ec786750cd5136991c58196b440cc39b6acf3ec8227f6562c9a94e4b9"}, - {file = "Levenshtein-0.20.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f7728bea7fe6dc55ceecde0dcda4287e74fe3b6733ad42530f46aaa8d2f81d0"}, - {file = "Levenshtein-0.20.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cc7eca755c13c92814c8cce8175524cf764ce38f39228b602f59eac58cfdc51a"}, - {file = "Levenshtein-0.20.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8a552e79d053dc1324fb90d342447fd4e15736f4cbc5363b6fbd5577f53dce9"}, - {file = "Levenshtein-0.20.9-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5474b2681ee0b7944fb1e7fe281cd44e2dfe75b03ba4558dca49c96fa0861b62"}, - {file = "Levenshtein-0.20.9-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:56e132c203b0dd8fc72a33e791c39ad0d5a25bcf24b130a1e202abbf489a3e75"}, - {file = "Levenshtein-0.20.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3badc94708ac05b405e795fde58a53272b90a9ee6099ecd54a345658b7b812e1"}, - {file = "Levenshtein-0.20.9-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48b9b3ae095b14dad7bc4bd219c7cd9113a7aa123a033337c85b00fe2ed565d3"}, - {file = "Levenshtein-0.20.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0d3a1f7328c91caeb1f857ddd2787e3f19d60cc2c688339d249ca8841da61454"}, - {file = "Levenshtein-0.20.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ef67c50428c99caf67d31bd209da21d9378da5f0cc3ad4f7bafb6caa78aee6f2"}, - {file = "Levenshtein-0.20.9-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:47f6d1592c0891f7355e38a302becd233336ca2f55f9a8be3a8635f946a6784f"}, - {file = "Levenshtein-0.20.9-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:2891019740e874f05e0349e9f27b6af8ad837b1612f42e9c90c296d54d1404fd"}, - {file = "Levenshtein-0.20.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c554704eec4f4ba742febdcc79a85491f8f9a1d493cb103bb2af18536d6cf122"}, - {file = "Levenshtein-0.20.9-cp310-cp310-win32.whl", hash = "sha256:7628e356b3f9c78ad7272c3b9137f0641a1368849e749ff6f2c8fe372795806b"}, - {file = "Levenshtein-0.20.9-cp310-cp310-win_amd64.whl", hash = "sha256:ba2bafe3511194a37044cae4e7d328cca70657933052691c37eba2ca428a379d"}, - {file = "Levenshtein-0.20.9-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7605a94145198d19fdaaa7e29c0f8a56ad719b12386f3ae8cd8ed4cb9fa6c2e4"}, - {file = "Levenshtein-0.20.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:29db4dabfad2ddf33c7986eb6fd525c7587cca4c4d9e187365cff0a5281f5a35"}, - {file = "Levenshtein-0.20.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:965336c1772a4fc5fb2686a2a0bfaf3455dced96f19f50f278da8bc139076d31"}, - {file = "Levenshtein-0.20.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67235753035ac898d6475c0b29540521018db2e0027a3c1deb9aa0af0a84fd74"}, - {file = "Levenshtein-0.20.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:120dca58136aee3d8c7b190e30db7b6a6eb9579ea5712df84ad076a389801743"}, - {file = "Levenshtein-0.20.9-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6496ea66a6f755e48c0d82f1eee396d16edcd5592d4b3677d26fa789a636a728"}, - {file = "Levenshtein-0.20.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0af20327acc2c904d11611cb3a0d8d17f80c279a12e0b84189eafc35297186d"}, - {file = "Levenshtein-0.20.9-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:34d2f891ef53afbab6cf2eeb92ff13151884d17dc80a2d6d3c7ae74d7738b772"}, - {file = "Levenshtein-0.20.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:2ab9c72380582bf4745d1c5b055b1df0c85f7a980a04bd7603a855dd91478c0f"}, - {file = "Levenshtein-0.20.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6de13be3eb5ac48053fb1635a7b4daa936b9114ad4b264942e9eb709fcaa41dd"}, - {file = "Levenshtein-0.20.9-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:a9fc296860588251d8d72b4f4637cca4eef7351e042a7a23d44e6385aef1e160"}, - {file = "Levenshtein-0.20.9-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:35777b20fe35858248c22da37984469e6dd1278f55d17c53378312853d5d683d"}, - {file = "Levenshtein-0.20.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6b9e0642ddb4c431f77c38cec9edbd0317e26c3f37d072ccf281ab58926dce69"}, - {file = "Levenshtein-0.20.9-cp311-cp311-win32.whl", hash = "sha256:f88ec322d86d3cc9d3936dbf6b421ad813950c2658599d48ac4ede59f2a6047e"}, - {file = "Levenshtein-0.20.9-cp311-cp311-win_amd64.whl", hash = "sha256:2907a6888455f9915d5b656f5d058f63eaf6063b2c7f0f1ff6bc05706ae5bc39"}, - {file = "Levenshtein-0.20.9-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6bcebc79760be08488cb921732af34ade6abc7476a94866881c68b45ec4b6c82"}, - {file = "Levenshtein-0.20.9-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47d8d4f3825d1d8f3b19382537a8536e689cf57aaa224d2cb4f44cf844811885"}, - {file = "Levenshtein-0.20.9-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d40e18a5817ee7f0675401613a26c492fd4ea68d2103c1480fb5a6ab1b8763d"}, - {file = "Levenshtein-0.20.9-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4d258f3d44f6bac17f33002fea34570049507d3476c3716b5267170c666b20b4"}, - {file = "Levenshtein-0.20.9-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c621e0c389546147ed43c33ca4168de0f91c920508ab8a94a400835fa084f486"}, - {file = "Levenshtein-0.20.9-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57a31527dc7994353091626e62b7d82d53290cb00df48d3e5d29cb291fb4c03c"}, - {file = "Levenshtein-0.20.9-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:129c8f192e656b7c2c543bf0d704d677720771b8bc2f30c50db02fbc2001bac2"}, - {file = "Levenshtein-0.20.9-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:5a01fca58255be6bf724a40af2575d7cf644c099c28a00d1f5f6a81675e60e7d"}, - {file = "Levenshtein-0.20.9-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:4c13749ea39a228f05d5bd9d473e76f726fc2dcd493cafc322f740921a6eeffb"}, - {file = "Levenshtein-0.20.9-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:69daa0f8eefa5b947255a81346741ed86fe7030e0909741dbd978e38b30da3fd"}, - {file = "Levenshtein-0.20.9-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:fcc78a73ed423bbb09ac902dd2e1ff1094d159d1c6766e5e52da5f376a4cba18"}, - {file = "Levenshtein-0.20.9-cp36-cp36m-win32.whl", hash = "sha256:d82ae57982a9f33c55778f1f0f63d5e51e291aee236abed3b90497578b944202"}, - {file = "Levenshtein-0.20.9-cp36-cp36m-win_amd64.whl", hash = "sha256:4082379b406752fc1173ed1f8c3a122c5d5491e10e564ed721602e4e049e3d4c"}, - {file = "Levenshtein-0.20.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cb499783b7126e6fc45c39ab34c8114148425c5d975b1ce35e6c47c0eda58a94"}, - {file = "Levenshtein-0.20.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ce747b296aad3bd8a563cccf2119cf37bf72f668076bfdad6ec55f0a0596dd9"}, - {file = "Levenshtein-0.20.9-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1347c3ebbe8f42f7a487e8d23a95bde6529379b4939ad51d32246d001565c499"}, - {file = "Levenshtein-0.20.9-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a2f1c1e8360603a6da29416da61d1907a27656843e269413091c8c3a3e6286e"}, - {file = "Levenshtein-0.20.9-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73c1caaedbee3617fd29139aac8dab7743776b59c3c1fed2790308ecb43c7b25"}, - {file = "Levenshtein-0.20.9-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a1f24133df69f8b618fc508d6023695130ad3c3c8968ef43aaeca21835eb337a"}, - {file = "Levenshtein-0.20.9-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:cf7260722f8170c09af5cfa714bb45626a4dfc85d71d1c1c9c52c2a6901cc501"}, - {file = "Levenshtein-0.20.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:01668178fd9244df290db0340293982fe7641162a12a35ad9ffb3fe145ce6377"}, - {file = "Levenshtein-0.20.9-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:1e46f9d3483dc4991ac60ff3711b0d40f93e352cc8edc16b68df57ccc472bd6c"}, - {file = "Levenshtein-0.20.9-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:680cd250dc1875eb80cf2a0cca742bd13f6f9ab11c48317244fcc483eba1dd67"}, - {file = "Levenshtein-0.20.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2346e2f7dfbbc2936bd81e19f7734984e72486ffc086760c897b39b9f674b2fa"}, - {file = "Levenshtein-0.20.9-cp37-cp37m-win32.whl", hash = "sha256:7f31bcf257fec9719d0d97185c419d315f6f20a194f0b442919e352d19418b2e"}, - {file = "Levenshtein-0.20.9-cp37-cp37m-win_amd64.whl", hash = "sha256:48262bc9830ad60de96411fcb2e96a522c7206e7069169e04d89dd79364a7722"}, - {file = "Levenshtein-0.20.9-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:eba5696e1f8e8da225498fd1d743886d639400cafd0e5be3c553978cbb54c345"}, - {file = "Levenshtein-0.20.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:679333188f9791c85109d2981e97e8721a99b2b975b5c52d16aca50ac9c70757"}, - {file = "Levenshtein-0.20.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:06c9cfc61cf66833692d1ed258ec5a0871221b0779f1281c32a10348c492e2c5"}, - {file = "Levenshtein-0.20.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5d80d949168df406f2ac9ade1a5d0419cef0a8df611c8c2efe88f0248c9d0c0"}, - {file = "Levenshtein-0.20.9-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9275c6e601ff7f659116e2235e8585950c9c39d72504006077be85bf27950b35"}, - {file = "Levenshtein-0.20.9-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6414eea342d9632045e12b66bef043dbc6557189a283dc4dcc5966f63fa48998"}, - {file = "Levenshtein-0.20.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56571c58700600a382ecdf3f9efcb132ed16a0476cbb4e23a9478ab0ae788fd9"}, - {file = "Levenshtein-0.20.9-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7ccb76ffd9b851384f9cf1595b90b17cae46f0ab895e234de11ea48f9d9f73a"}, - {file = "Levenshtein-0.20.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:109172943cff7fb10f28a9eb819eb3eaf9c88fe38661fb1d0f230a8ae68a615c"}, - {file = "Levenshtein-0.20.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:534c8bbdfd033fa20575d57332d9ac0447b5afbeca7db975ba169762ece2051f"}, - {file = "Levenshtein-0.20.9-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:381a725963c392585135654caa3c7fc32cb1755ed977fb9db72e8838fee261be"}, - {file = "Levenshtein-0.20.9-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:7e4a44b1223980a9880e6f2bbf19121a125928580df9e4e81207199190343e11"}, - {file = "Levenshtein-0.20.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fc0ced58ee6d07351cde140a7ec88e5f2ceb053c805af1f90514d21914d21cad"}, - {file = "Levenshtein-0.20.9-cp38-cp38-win32.whl", hash = "sha256:5eec0868ffcd825564dd5e3399305eaa159220554d1aedbff13af0de1fe01f6c"}, - {file = "Levenshtein-0.20.9-cp38-cp38-win_amd64.whl", hash = "sha256:e9db476e40a3aa184631d102b716a019f70837eb0fcdd5b5d1504f099f91359c"}, - {file = "Levenshtein-0.20.9-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d5a20ecc20a09a32c72128c43d7df23877a2469b3c17780ae83f9a9d55873c08"}, - {file = "Levenshtein-0.20.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8b7b772f2f62a19a15ccb1b09c6c7754ca7430bb7e19d4ca4ff232958786873b"}, - {file = "Levenshtein-0.20.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af92326b90ea6fe4521cf6a5dfe450e21150393c573ef3ad9ee446f1009fbfbd"}, - {file = "Levenshtein-0.20.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b48554dad328e198a636f937e2f4c057aac8e4bfcb8467b10e0f5daa94307b17"}, - {file = "Levenshtein-0.20.9-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:82304821e128d5453d1755d1c2f3d9cdf75e9def3517cf913b09df174e20283b"}, - {file = "Levenshtein-0.20.9-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2052357c5da195ede7dbc81a4e3408ebd6374a1ff1b86a0a9d8b8ce9562b32c3"}, - {file = "Levenshtein-0.20.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44d60c6b47ccd6841c990418f7f4f58c28f7da9b07b81eaafc99b836cf351df1"}, - {file = "Levenshtein-0.20.9-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8dc2194c917e4466cb604580b16e42286f04e3fe0424489459e68f0834f5c527"}, - {file = "Levenshtein-0.20.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bb1e20965d759d89318cac7ff7eb045eb1fafcb5c3fa3047a23f6ae20c810ad7"}, - {file = "Levenshtein-0.20.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:74e959035da10a54e7a2eee28408eff672297ce96cdadd6f4a2f269a06e395c4"}, - {file = "Levenshtein-0.20.9-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:4a441b23d9704f57eb34af6a300ae5c335b9e77e6a065ada36ca69d6fc582af9"}, - {file = "Levenshtein-0.20.9-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:f59470c49114a5da064712a427317f2b1fa5bb89aa2dfd0e300f8289e26aec28"}, - {file = "Levenshtein-0.20.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:06191f5d0527e3224107aea260b5cffc8a78722e0efb4e793f0e45c449b813a2"}, - {file = "Levenshtein-0.20.9-cp39-cp39-win32.whl", hash = "sha256:3235c461904fe94b4f62fee78a1658c1316344411c81b02400c27d692a893f8f"}, - {file = "Levenshtein-0.20.9-cp39-cp39-win_amd64.whl", hash = "sha256:8b852def43d165c2f2b468239d66b847d9e6f52a775fc657773ced04d26062bd"}, - {file = "Levenshtein-0.20.9-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f674cc75f127692525563155e500a3fa16aaf24dafd33a9bcda46e2979f793a1"}, - {file = "Levenshtein-0.20.9-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a34e3fd21acb31fcd29a0c8353dca74dfbb59957210a6f142505907a9dff3d59"}, - {file = "Levenshtein-0.20.9-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0ddddf2beafd1a2e17a87f80be562a7f7478e6098ccfc15de4c879972dfa2f9"}, - {file = "Levenshtein-0.20.9-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9649af1a896a4a7fc7f6f1fd093e8a92f463297f56c7bd0f8d7d16dfabeb236d"}, - {file = "Levenshtein-0.20.9-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:d7bd7f25336849027fbe5ed32b6ffd404436727d78a014e348dcd17347c73fd8"}, - {file = "Levenshtein-0.20.9-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0371d996ae81089296f42b6e886c7bf138d1cb0f002b0c724a9e5d689b29b5a0"}, - {file = "Levenshtein-0.20.9-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7e00e2fda9f225b5f4537647f6195cf220d468532739d3390eaf082b1d76c87"}, - {file = "Levenshtein-0.20.9-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1600f5ebe2f2aebf13e88cf488ec2e5ce25f7a42b5846335018693baf4ea63bd"}, - {file = "Levenshtein-0.20.9-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bcd59fcf06aaedda98da185ec289dc2c2c9922ce789f6a9c101709d4a22cac9"}, - {file = "Levenshtein-0.20.9-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:1549e307028fa5c3a8cf28ae8bcb1f6072df2abf7f36b9d7adf7fd60690fe372"}, - {file = "Levenshtein-0.20.9-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:795f2e95d09a33c66c73cd49be3ee632fb4b8c41be72c0cb8df29a329ce7d111"}, - {file = "Levenshtein-0.20.9-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:726bfb361d3b6786bea31392752f0ffcca568db7dc3f1e274f1b529489b8ad05"}, - {file = "Levenshtein-0.20.9-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e0fd315132786375de532355fa06b2f11c4b4af5784b7e064dc54b6ee0c3281"}, - {file = "Levenshtein-0.20.9-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0674bc0549d5ea9edb934b3b03a160a116cc410feb5739a51f9c4f618ee674e3"}, - {file = "Levenshtein-0.20.9-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1ef8f3ecdfca5d6f0538226338d58617270439a1cc9b6cacb30a388984bb1608"}, - {file = "Levenshtein-0.20.9.tar.gz", hash = "sha256:70a8ad5e28bb76d87da1eb3f31de940836596547d6d01317c2289f5b7cd0b0ea"}, + {file = "Levenshtein-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1f19fe25ea0dd845d0f48505e8947f6080728e10b7642ba0dad34e9b48c81130"}, + {file = "Levenshtein-0.21.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d23c647b03acbb5783f9bdfd51cfa5365d51f7df9f4029717a35eff5cc32bbcc"}, + {file = "Levenshtein-0.21.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:668ea30b311944c643f866ce5e45edf346f05e920075c0056f2ba7f74dde6071"}, + {file = "Levenshtein-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f42b8dba2cce257cd34efd1ce9678d06f3248cb0bb2a92a5db8402e1e4a6f30"}, + {file = "Levenshtein-0.21.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c27a5178ce322b56527a451185b4224217aa81955d9b0dad6f5a8de81ffe80f"}, + {file = "Levenshtein-0.21.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:92bf2370b01d7a4862abf411f8f60f39f064cebebce176e3e9ee14e744db8288"}, + {file = "Levenshtein-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32dfda2e64d0c50553e47d0ab2956413970f940253351c196827ad46f17916d5"}, + {file = "Levenshtein-0.21.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f55623094b665d79a3b82ba77386ac34fa85049163edfe65387063e5127d4184"}, + {file = "Levenshtein-0.21.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:25576ad9c337ecb342306fe87166b54b2f49e713d4ff592c752cc98e0046296e"}, + {file = "Levenshtein-0.21.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fae24c875c4ecc8c5f34a9715eb2a459743b4ca21d35c51819b640ee2f71cb51"}, + {file = "Levenshtein-0.21.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:4b2156f32e46d16b74a055ccb4f64ee3c64399372a6aaf1ee98f6dccfadecee1"}, + {file = "Levenshtein-0.21.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:04046878a57129da4e2352c032df7c1fceaa54870916d12772cad505ef998290"}, + {file = "Levenshtein-0.21.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:608beb1683508c3cdbfff669c1c872ea02b47965e1bbb8a630de548e2490f96a"}, + {file = "Levenshtein-0.21.0-cp310-cp310-win32.whl", hash = "sha256:cc36ba40027b4f8821155c9e3e0afadffccdccbe955556039d1d1169dfc659c9"}, + {file = "Levenshtein-0.21.0-cp310-cp310-win_amd64.whl", hash = "sha256:80e67bd73a05592ecd52aede4afa8ea49575de70f9d5bfbe2c52ebd3541b20be"}, + {file = "Levenshtein-0.21.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3305262cb85ff78ace9e2d8d2dfc029b34dc5f93aa2d24fd20b6ed723e2ad501"}, + {file = "Levenshtein-0.21.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:023ca95c833ca548280e444e9a4c34fdecb3be3851e96af95bad290ae0c708b9"}, + {file = "Levenshtein-0.21.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8476862a5c3150b8d63a7475563a4bff6dc50bbc0447894eb6b6a116ced0809d"}, + {file = "Levenshtein-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0236c8ff4648c50ebd81ac3692430d2241b134936ac9d86d7ca32ba6ab4a4e63"}, + {file = "Levenshtein-0.21.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cfbc4ed7ee2965e305bf81388fea377b795dabc82ee07f04f31d1fb8677a885"}, + {file = "Levenshtein-0.21.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6338a47b6f8c7f1ee8b5636cc8b245ad2d1d0ee47f7bb6f33f38a522ef0219cc"}, + {file = "Levenshtein-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4dc79033140f82acaca40712a6d26ed190cc2dd403e104020a87c24f2771aa72"}, + {file = "Levenshtein-0.21.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88ccdc8dc20c16e8059ace00fb58d353346a04fd24c0733b009678b2554801d2"}, + {file = "Levenshtein-0.21.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c031cbe3685b0343f5cc2dcf2172fd21b82f8ccc5c487179a895009bf0e4ea8"}, + {file = "Levenshtein-0.21.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eab6c253983a6659e749f4c44fcc2215194c2e00bf7b1c5e90fe683ea3b7b00f"}, + {file = "Levenshtein-0.21.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:8bdbcd1570340b07549f71e8a5ba3f0a6d84408bf86c4051dc7b70a29ae342bb"}, + {file = "Levenshtein-0.21.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4357bf8146cbadb10016ad3a950bba16e042f79015362a575f966181d95b4bc7"}, + {file = "Levenshtein-0.21.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:be038321695267a8faa5ae1b1a83deb3748827f0b6f72471e0beed36afcbd72a"}, + {file = "Levenshtein-0.21.0-cp311-cp311-win32.whl", hash = "sha256:be87998ffcbb5fb0c37a76d100f63b4811f48527192677da0ec3624b49ab8a64"}, + {file = "Levenshtein-0.21.0-cp311-cp311-win_amd64.whl", hash = "sha256:f873af54014cac12082c7f5ccec6bbbeb5b57f63466e7f9c61a34588621313fb"}, + {file = "Levenshtein-0.21.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:4ec2ef9836a34a3bb009a81e5efe4d9d43515455fb5f182c5d2cf8ae61c79496"}, + {file = "Levenshtein-0.21.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e748c2349719cb1bc90f802d9d7f07310633dcf166d468a5bd821f78ed17698"}, + {file = "Levenshtein-0.21.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:37a99d858fa1d88b1a917b4059a186becd728534e5e889d583086482356b7ca1"}, + {file = "Levenshtein-0.21.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:742b785c93d16c63289902607219c200bd2b6077dafc788073c74337cae382fb"}, + {file = "Levenshtein-0.21.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cefd5a668f6d7af1279aca10104b43882fdd83f9bdc68933ba5429257a628abe"}, + {file = "Levenshtein-0.21.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3e1723d515ab287b9b2c2e4a111894dc6b474f5d28826fff379647486cae98d2"}, + {file = "Levenshtein-0.21.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:3e22d31375d5fea5797c9b7aa0f8cc36579c31dcf5754e9931ca86c27d9011f8"}, + {file = "Levenshtein-0.21.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:31cb59d86a5f99147cd4a67ebced8d6df574b5d763dcb63c033a642e29568746"}, + {file = "Levenshtein-0.21.0-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:76d5d34a8e21de8073c66ae801f053520f946d499fa533fbba654712775f8132"}, + {file = "Levenshtein-0.21.0-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:46dab8c6e8fae563ca77acfaeb3824c4dd4b599996328b8a081b06f16befa6a0"}, + {file = "Levenshtein-0.21.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:ee62ec5882a857b252faffeb7867679f7e418052ca6bf7d6b56099f6498a2b0e"}, + {file = "Levenshtein-0.21.0-cp36-cp36m-win32.whl", hash = "sha256:7e40a4bac848c9a8883225f926cfa7b2bc9f651e989a8b7006cdb596edc7ac9b"}, + {file = "Levenshtein-0.21.0-cp36-cp36m-win_amd64.whl", hash = "sha256:709a727f58d31a5ee1e5e83b247972fe55ef0014f6222256c9692c5efa471785"}, + {file = "Levenshtein-0.21.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:01dd427cf72b4978b09558e3d36e3f92c8eef467e3eb4653c3fdccd8d70aaa08"}, + {file = "Levenshtein-0.21.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9ff1255c499fcb41ba37a578ad8c1b8dab5c44f78941b8e1c1d7fab5b5e831bc"}, + {file = "Levenshtein-0.21.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8aa92b05156dfa2e248c3743670d5deb41a45b5789416d5fa31be009f4f043ab"}, + {file = "Levenshtein-0.21.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d932cb21e40beb93cfc8973de7f25fbf25ba4a07d1dccac3b9ba977164cf9887"}, + {file = "Levenshtein-0.21.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d4ba0df46bb41d660d77e7cc6b4d38c8d5b6f977d51c48ed1217db6a8474cde"}, + {file = "Levenshtein-0.21.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c8eaaa6f0df2838437d1d8739629486b145f7a3405d3ef0874301a9f5bc7dcd"}, + {file = "Levenshtein-0.21.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6ede583155f24c8b2456a7720fbbfa5d9c1154ae04b4da3cf63368e2406ea099"}, + {file = "Levenshtein-0.21.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a18c8e4d1aae3f9950797d049020c64a8a63cc8b4e43afcca91ec400bf6304c5"}, + {file = "Levenshtein-0.21.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:8cf87a5e2962431d7260dd81dc1ca0697f61aad81036145d3666f4c0d514ce3a"}, + {file = "Levenshtein-0.21.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:bd0bfa71b1441be359e99e77709885b79c22857bf9bb7f4e84c09e501f6c5fad"}, + {file = "Levenshtein-0.21.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e9a6251818b9eb6d519bffd7a0b745f3a99b3e99563a4c9d3cad26e34f6ac880"}, + {file = "Levenshtein-0.21.0-cp37-cp37m-win32.whl", hash = "sha256:8dd8ef4239b24fb1c9f0b536e48e55194d5966d351d349af23e67c9eb3875c68"}, + {file = "Levenshtein-0.21.0-cp37-cp37m-win_amd64.whl", hash = "sha256:26c6fb012538a245d78adea786d2cfe3c1506b835762c1c523a4ed6b9e08dc0b"}, + {file = "Levenshtein-0.21.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b0ba9723c7d67a61e160b3457259552f7d679d74aaa144b892eb68b7e2a5ebb6"}, + {file = "Levenshtein-0.21.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:426883be613d912495cf6ee2a776d2ab84aa6b3de5a8d82c43a994267ea6e0e3"}, + {file = "Levenshtein-0.21.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5369827ace536c6df04e0e670d782999bc17bf9eb111e77435fdcdaecb10c2a3"}, + {file = "Levenshtein-0.21.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ebabcf982ae161534f8729d13fe05eebc977b497ac34936551f97cf8b07dd9e"}, + {file = "Levenshtein-0.21.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:13e8a5b1b58de49befea555bb913dc394614f2d3553bc5b86bc672c69ef1a85a"}, + {file = "Levenshtein-0.21.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d647f1e0c30c7a73f70f4de7376ed7dafc2b856b67fe480d32a81af133edbaeb"}, + {file = "Levenshtein-0.21.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5378a8139ba61d7271c0f9350201259c11eb90bfed0ac45539c4aeaed3907230"}, + {file = "Levenshtein-0.21.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df9b0f8f511270ad259c7bfba22ab6d5a0c33d81cd594461668e67cd80dd9052"}, + {file = "Levenshtein-0.21.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9485f2a5c88113410153256657072bc93b81bf5c8690d47e4cc3df58135dbadb"}, + {file = "Levenshtein-0.21.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:aa39bb773915e4df330d311bb6c100a8613e265cc50d5b25b015c8db824e1c47"}, + {file = "Levenshtein-0.21.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:de2dfd6498454c7d89036d56a53c0a01fd9bcf1c2970253e469b5e8bb938b69f"}, + {file = "Levenshtein-0.21.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4515f9511cb91c66d254ee30154206aad76b57d8b25f64ba1402aad43efdb251"}, + {file = "Levenshtein-0.21.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f622f542bd065ffec7d26b26d44d0c9a25c9c1295fd8ba6e4d77778e2293a12c"}, + {file = "Levenshtein-0.21.0-cp38-cp38-win32.whl", hash = "sha256:ee757fd36bad66ad8b961958840894021ecaad22194f65219a666432739393ff"}, + {file = "Levenshtein-0.21.0-cp38-cp38-win_amd64.whl", hash = "sha256:457442911df185e28a32fd8b788b14ca22ab3a552256b556e7687173d5f18bc4"}, + {file = "Levenshtein-0.21.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b646ace5085a60d4f89b28c81301c9d9e8cd6a9bdda908181b2fa3dfac7fc10d"}, + {file = "Levenshtein-0.21.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0cc3679978cd0250bf002963cf2e08855b93f70fa0fc9f74956115c343983fbb"}, + {file = "Levenshtein-0.21.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:84b55b732e311629a8308ad2778a0f9824e29e3c35987eb35610fc52eb6d4634"}, + {file = "Levenshtein-0.21.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7adaabe07c5ceb6228332b9184f06eb9cda89c227d198a1b8a6f78c05b3c672"}, + {file = "Levenshtein-0.21.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac8b6266799645827980ab1af4e0bfae209c1f747a10bdf6e5da96a6ebe511a2"}, + {file = "Levenshtein-0.21.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c2d67220867d640e36931b3d63b8349369b485d52cf6f4a2635bec8da92d678"}, + {file = "Levenshtein-0.21.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb26e69fc6c12534fbaa1657efed3b6482f1a166ba8e31227fa6f6f062a59070"}, + {file = "Levenshtein-0.21.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a68b05614d25cc2a5fbcc4d2fd124be7668d075fd5ac3d82f292eec573157361"}, + {file = "Levenshtein-0.21.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b167b32b3e336c5ec5e0212f025587f9248344ae6e73ed668270eba5c6a506e5"}, + {file = "Levenshtein-0.21.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:04850a0719e503014acb3fee6d4ec7d7f170a2c7375ffbc5833c7256b7cd10ee"}, + {file = "Levenshtein-0.21.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:ce7e76c6341abb498368d42b8081f2f45c245ac2a221af6a0394349d41302c08"}, + {file = "Levenshtein-0.21.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:ec64b7b3fb95bc9c20c72548277794b81281a6ba9da85eda2c87324c218441ff"}, + {file = "Levenshtein-0.21.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:24843f28cbbdcbcfc18b08e7d3409dbaad7896fb7113442592fa978590a7bbf0"}, + {file = "Levenshtein-0.21.0-cp39-cp39-win32.whl", hash = "sha256:c290a7211f1b4f87c300df4424cc46b7379cead3b6f37fa8d3e7e6c6212ccd39"}, + {file = "Levenshtein-0.21.0-cp39-cp39-win_amd64.whl", hash = "sha256:1fde464f937878e6f5c30c234b95ce2cb969331a175b3089367e077113428062"}, + {file = "Levenshtein-0.21.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:66d303cd485710fe6d62108209219b7a695bdd10a722f4e86abdaf26f4bf2202"}, + {file = "Levenshtein-0.21.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bc550d0986ace95bde003b8a60e622449baf2bdf24d8412f7a50f401a289ec3"}, + {file = "Levenshtein-0.21.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c6858cfd84568bc1df3ad545553b5c27af6ed3346973e8f4b57d23c318cf8f4"}, + {file = "Levenshtein-0.21.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ce3f14a8e006fb7e3fc7bab965ab7da5817f48fc48d25cf735fcec8f1d2e39a"}, + {file = "Levenshtein-0.21.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:024302c82d49fc1f1d044794997ef7aa9d01b509a9040e222480b64a01cd4b80"}, + {file = "Levenshtein-0.21.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e043b79e39f165026bc941c95582bfc4bfdd297a1de6f13ace0d0a7abf486288"}, + {file = "Levenshtein-0.21.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8446f8da38857482ec0cfd616fe5e7dcd3695fd323cc65f37366a9ff6a31c9cb"}, + {file = "Levenshtein-0.21.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:587ad51770de41eb491bea1bfb676abc7ff9a94dbec0e2bc51fc6a25abef99c4"}, + {file = "Levenshtein-0.21.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ac4ed77d3263eac7f9b6ed89d451644332aecd55cda921201e348803a1e5c57"}, + {file = "Levenshtein-0.21.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:cf2dee0f8c71598f8be51e3feceb9142ac01576277b9e691e25740987761c86e"}, + {file = "Levenshtein-0.21.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4bbceef2caba4b2ae613b0e853a7aaab990c1a13bddb9054ba1328a84bccdbf7"}, + {file = "Levenshtein-0.21.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2290732763e3b75979888364b26acce79d72b8677441b5762a4e97b3630cc3d9"}, + {file = "Levenshtein-0.21.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db7567997ffbc2feb999e30002a92461a76f17a596a142bdb463b5f7037f160c"}, + {file = "Levenshtein-0.21.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c270487d60b33102efea73be6dcd5835f3ddc3dc06e77499f0963df6cba2ec71"}, + {file = "Levenshtein-0.21.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e2686c37d22faf27d02a19e83b55812d248b32b7ba3aa638e768d0ea032e1f3c"}, + {file = "Levenshtein-0.21.0.tar.gz", hash = "sha256:545635d9e857711d049dcdb0b8609fb707b34b032517376c531ca159fcd46265"}, ] [package.dependencies] -rapidfuzz = ">=2.3.0,<3.0.0" - -[[package]] -name = "marshmallow" -version = "3.19.0" -description = "A lightweight library for converting complex datatypes to and from native Python datatypes." -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "marshmallow-3.19.0-py3-none-any.whl", hash = "sha256:93f0958568da045b0021ec6aeb7ac37c81bfcccbb9a0e7ed8559885070b3a19b"}, - {file = "marshmallow-3.19.0.tar.gz", hash = "sha256:90032c0fd650ce94b6ec6dc8dfeb0e3ff50c144586462c389b81a07205bedb78"}, -] - -[package.dependencies] -packaging = ">=17.0" - -[package.extras] -dev = ["flake8 (==5.0.4)", "flake8-bugbear (==22.10.25)", "mypy (==0.990)", "pre-commit (>=2.4,<3.0)", "pytest", "pytz", "simplejson", "tox"] -docs = ["alabaster (==0.7.12)", "autodocsumm (==0.2.9)", "sphinx (==5.3.0)", "sphinx-issues (==3.0.1)", "sphinx-version-warning (==1.1.2)"] -lint = ["flake8 (==5.0.4)", "flake8-bugbear (==22.10.25)", "mypy (==0.990)", "pre-commit (>=2.4,<3.0)"] -tests = ["pytest", "pytz", "simplejson"] +rapidfuzz = ">=2.3.0,<4.0.0" [[package]] name = "motor" -version = "3.1.1" +version = "3.1.2" description = "Non-blocking MongoDB driver for Tornado or asyncio" -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "motor-3.1.1-py3-none-any.whl", hash = "sha256:01d93d7c512810dcd85f4d634a7244ba42ff6be7340c869791fe793561e734da"}, - {file = "motor-3.1.1.tar.gz", hash = "sha256:a4bdadf8a08ebb186ba16e557ba432aa867f689a42b80f2e9f8b24bbb1604742"}, + {file = "motor-3.1.2-py3-none-any.whl", hash = "sha256:4bfc65230853ad61af447088527c1197f91c20ee957cfaea3144226907335716"}, + {file = "motor-3.1.2.tar.gz", hash = "sha256:80c08477c09e70db4f85c99d484f2bafa095772f1d29b3ccb253270f9041da9a"}, ] [package.dependencies] @@ -1175,7 +1138,6 @@ zstd = ["pymongo[zstd] (>=4.1,<5)"] name = "multidict" version = "6.0.4" description = "multidict implementation" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1255,58 +1217,10 @@ files = [ {file = "multidict-6.0.4.tar.gz", hash = "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49"}, ] -[[package]] -name = "mypy" -version = "1.1.1" -description = "Optional static typing for Python" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "mypy-1.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39c7119335be05630611ee798cc982623b9e8f0cff04a0b48dfc26100e0b97af"}, - {file = "mypy-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:61bf08362e93b6b12fad3eab68c4ea903a077b87c90ac06c11e3d7a09b56b9c1"}, - {file = "mypy-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbb19c9f662e41e474e0cff502b7064a7edc6764f5262b6cd91d698163196799"}, - {file = "mypy-1.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:315ac73cc1cce4771c27d426b7ea558fb4e2836f89cb0296cbe056894e3a1f78"}, - {file = "mypy-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:5cb14ff9919b7df3538590fc4d4c49a0f84392237cbf5f7a816b4161c061829e"}, - {file = "mypy-1.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:26cdd6a22b9b40b2fd71881a8a4f34b4d7914c679f154f43385ca878a8297389"}, - {file = "mypy-1.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5b5f81b40d94c785f288948c16e1f2da37203c6006546c5d947aab6f90aefef2"}, - {file = "mypy-1.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21b437be1c02712a605591e1ed1d858aba681757a1e55fe678a15c2244cd68a5"}, - {file = "mypy-1.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d809f88734f44a0d44959d795b1e6f64b2bbe0ea4d9cc4776aa588bb4229fc1c"}, - {file = "mypy-1.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:a380c041db500e1410bb5b16b3c1c35e61e773a5c3517926b81dfdab7582be54"}, - {file = "mypy-1.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b7c7b708fe9a871a96626d61912e3f4ddd365bf7f39128362bc50cbd74a634d5"}, - {file = "mypy-1.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1c10fa12df1232c936830839e2e935d090fc9ee315744ac33b8a32216b93707"}, - {file = "mypy-1.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0a28a76785bf57655a8ea5eb0540a15b0e781c807b5aa798bd463779988fa1d5"}, - {file = "mypy-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:ef6a01e563ec6a4940784c574d33f6ac1943864634517984471642908b30b6f7"}, - {file = "mypy-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d64c28e03ce40d5303450f547e07418c64c241669ab20610f273c9e6290b4b0b"}, - {file = "mypy-1.1.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:64cc3afb3e9e71a79d06e3ed24bb508a6d66f782aff7e56f628bf35ba2e0ba51"}, - {file = "mypy-1.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce61663faf7a8e5ec6f456857bfbcec2901fbdb3ad958b778403f63b9e606a1b"}, - {file = "mypy-1.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2b0c373d071593deefbcdd87ec8db91ea13bd8f1328d44947e88beae21e8d5e9"}, - {file = "mypy-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:2888ce4fe5aae5a673386fa232473014056967f3904f5abfcf6367b5af1f612a"}, - {file = "mypy-1.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:19ba15f9627a5723e522d007fe708007bae52b93faab00f95d72f03e1afa9598"}, - {file = "mypy-1.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:59bbd71e5c58eed2e992ce6523180e03c221dcd92b52f0e792f291d67b15a71c"}, - {file = "mypy-1.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9401e33814cec6aec8c03a9548e9385e0e228fc1b8b0a37b9ea21038e64cdd8a"}, - {file = "mypy-1.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4b398d8b1f4fba0e3c6463e02f8ad3346f71956b92287af22c9b12c3ec965a9f"}, - {file = "mypy-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:69b35d1dcb5707382810765ed34da9db47e7f95b3528334a3c999b0c90fe523f"}, - {file = "mypy-1.1.1-py3-none-any.whl", hash = "sha256:4e4e8b362cdf99ba00c2b218036002bdcdf1e0de085cdb296a49df03fb31dfc4"}, - {file = "mypy-1.1.1.tar.gz", hash = "sha256:ae9ceae0f5b9059f33dbc62dea087e942c0ccab4b7a003719cb70f9b8abfa32f"}, -] - -[package.dependencies] -mypy-extensions = ">=1.0.0" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = ">=3.10" - -[package.extras] -dmypy = ["psutil (>=4.0)"] -install-types = ["pip"] -python2 = ["typed-ast (>=1.4.0,<2)"] -reports = ["lxml"] - [[package]] name = "mypy-extensions" version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -1318,7 +1232,6 @@ files = [ name = "nanoid" version = "2.0.0" description = "A tiny, secure, URL-friendly, unique string ID generator for Python" -category = "main" optional = false python-versions = "*" files = [ @@ -1330,7 +1243,6 @@ files = [ name = "nest-asyncio" version = "1.5.6" description = "Patch asyncio to allow nested event loops" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -1342,7 +1254,6 @@ files = [ name = "nodeenv" version = "1.7.0" description = "Node.js virtual environment builder" -category = "dev" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" files = [ @@ -1355,47 +1266,45 @@ setuptools = "*" [[package]] name = "numpy" -version = "1.24.2" +version = "1.24.3" description = "Fundamental package for array computing in Python" -category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "numpy-1.24.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eef70b4fc1e872ebddc38cddacc87c19a3709c0e3e5d20bf3954c147b1dd941d"}, - {file = "numpy-1.24.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8d2859428712785e8a8b7d2b3ef0a1d1565892367b32f915c4a4df44d0e64f5"}, - {file = "numpy-1.24.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6524630f71631be2dabe0c541e7675db82651eb998496bbe16bc4f77f0772253"}, - {file = "numpy-1.24.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a51725a815a6188c662fb66fb32077709a9ca38053f0274640293a14fdd22978"}, - {file = "numpy-1.24.2-cp310-cp310-win32.whl", hash = "sha256:2620e8592136e073bd12ee4536149380695fbe9ebeae845b81237f986479ffc9"}, - {file = "numpy-1.24.2-cp310-cp310-win_amd64.whl", hash = "sha256:97cf27e51fa078078c649a51d7ade3c92d9e709ba2bfb97493007103c741f1d0"}, - {file = "numpy-1.24.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7de8fdde0003f4294655aa5d5f0a89c26b9f22c0a58790c38fae1ed392d44a5a"}, - {file = "numpy-1.24.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4173bde9fa2a005c2c6e2ea8ac1618e2ed2c1c6ec8a7657237854d42094123a0"}, - {file = "numpy-1.24.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cecaed30dc14123020f77b03601559fff3e6cd0c048f8b5289f4eeabb0eb281"}, - {file = "numpy-1.24.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a23f8440561a633204a67fb44617ce2a299beecf3295f0d13c495518908e910"}, - {file = "numpy-1.24.2-cp311-cp311-win32.whl", hash = "sha256:e428c4fbfa085f947b536706a2fc349245d7baa8334f0c5723c56a10595f9b95"}, - {file = "numpy-1.24.2-cp311-cp311-win_amd64.whl", hash = "sha256:557d42778a6869c2162deb40ad82612645e21d79e11c1dc62c6e82a2220ffb04"}, - {file = "numpy-1.24.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d0a2db9d20117bf523dde15858398e7c0858aadca7c0f088ac0d6edd360e9ad2"}, - {file = "numpy-1.24.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c72a6b2f4af1adfe193f7beb91ddf708ff867a3f977ef2ec53c0ffb8283ab9f5"}, - {file = "numpy-1.24.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c29e6bd0ec49a44d7690ecb623a8eac5ab8a923bce0bea6293953992edf3a76a"}, - {file = "numpy-1.24.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2eabd64ddb96a1239791da78fa5f4e1693ae2dadc82a76bc76a14cbb2b966e96"}, - {file = "numpy-1.24.2-cp38-cp38-win32.whl", hash = "sha256:e3ab5d32784e843fc0dd3ab6dcafc67ef806e6b6828dc6af2f689be0eb4d781d"}, - {file = "numpy-1.24.2-cp38-cp38-win_amd64.whl", hash = "sha256:76807b4063f0002c8532cfeac47a3068a69561e9c8715efdad3c642eb27c0756"}, - {file = "numpy-1.24.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4199e7cfc307a778f72d293372736223e39ec9ac096ff0a2e64853b866a8e18a"}, - {file = "numpy-1.24.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:adbdce121896fd3a17a77ab0b0b5eedf05a9834a18699db6829a64e1dfccca7f"}, - {file = "numpy-1.24.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:889b2cc88b837d86eda1b17008ebeb679d82875022200c6e8e4ce6cf549b7acb"}, - {file = "numpy-1.24.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f64bb98ac59b3ea3bf74b02f13836eb2e24e48e0ab0145bbda646295769bd780"}, - {file = "numpy-1.24.2-cp39-cp39-win32.whl", hash = "sha256:63e45511ee4d9d976637d11e6c9864eae50e12dc9598f531c035265991910468"}, - {file = "numpy-1.24.2-cp39-cp39-win_amd64.whl", hash = "sha256:a77d3e1163a7770164404607b7ba3967fb49b24782a6ef85d9b5f54126cc39e5"}, - {file = "numpy-1.24.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:92011118955724465fb6853def593cf397b4a1367495e0b59a7e69d40c4eb71d"}, - {file = "numpy-1.24.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9006288bcf4895917d02583cf3411f98631275bc67cce355a7f39f8c14338fa"}, - {file = "numpy-1.24.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:150947adbdfeceec4e5926d956a06865c1c690f2fd902efede4ca6fe2e657c3f"}, - {file = "numpy-1.24.2.tar.gz", hash = "sha256:003a9f530e880cb2cd177cba1af7220b9aa42def9c4afc2a2fc3ee6be7eb2b22"}, + {file = "numpy-1.24.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3c1104d3c036fb81ab923f507536daedc718d0ad5a8707c6061cdfd6d184e570"}, + {file = "numpy-1.24.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:202de8f38fc4a45a3eea4b63e2f376e5f2dc64ef0fa692838e31a808520efaf7"}, + {file = "numpy-1.24.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8535303847b89aa6b0f00aa1dc62867b5a32923e4d1681a35b5eef2d9591a463"}, + {file = "numpy-1.24.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d926b52ba1367f9acb76b0df6ed21f0b16a1ad87c6720a1121674e5cf63e2b6"}, + {file = "numpy-1.24.3-cp310-cp310-win32.whl", hash = "sha256:f21c442fdd2805e91799fbe044a7b999b8571bb0ab0f7850d0cb9641a687092b"}, + {file = "numpy-1.24.3-cp310-cp310-win_amd64.whl", hash = "sha256:ab5f23af8c16022663a652d3b25dcdc272ac3f83c3af4c02eb8b824e6b3ab9d7"}, + {file = "numpy-1.24.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9a7721ec204d3a237225db3e194c25268faf92e19338a35f3a224469cb6039a3"}, + {file = "numpy-1.24.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d6cc757de514c00b24ae8cf5c876af2a7c3df189028d68c0cb4eaa9cd5afc2bf"}, + {file = "numpy-1.24.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76e3f4e85fc5d4fd311f6e9b794d0c00e7002ec122be271f2019d63376f1d385"}, + {file = "numpy-1.24.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1d3c026f57ceaad42f8231305d4653d5f05dc6332a730ae5c0bea3513de0950"}, + {file = "numpy-1.24.3-cp311-cp311-win32.whl", hash = "sha256:c91c4afd8abc3908e00a44b2672718905b8611503f7ff87390cc0ac3423fb096"}, + {file = "numpy-1.24.3-cp311-cp311-win_amd64.whl", hash = "sha256:5342cf6aad47943286afa6f1609cad9b4266a05e7f2ec408e2cf7aea7ff69d80"}, + {file = "numpy-1.24.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7776ea65423ca6a15255ba1872d82d207bd1e09f6d0894ee4a64678dd2204078"}, + {file = "numpy-1.24.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ae8d0be48d1b6ed82588934aaaa179875e7dc4f3d84da18d7eae6eb3f06c242c"}, + {file = "numpy-1.24.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecde0f8adef7dfdec993fd54b0f78183051b6580f606111a6d789cd14c61ea0c"}, + {file = "numpy-1.24.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4749e053a29364d3452c034827102ee100986903263e89884922ef01a0a6fd2f"}, + {file = "numpy-1.24.3-cp38-cp38-win32.whl", hash = "sha256:d933fabd8f6a319e8530d0de4fcc2e6a61917e0b0c271fded460032db42a0fe4"}, + {file = "numpy-1.24.3-cp38-cp38-win_amd64.whl", hash = "sha256:56e48aec79ae238f6e4395886b5eaed058abb7231fb3361ddd7bfdf4eed54289"}, + {file = "numpy-1.24.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4719d5aefb5189f50887773699eaf94e7d1e02bf36c1a9d353d9f46703758ca4"}, + {file = "numpy-1.24.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0ec87a7084caa559c36e0a2309e4ecb1baa03b687201d0a847c8b0ed476a7187"}, + {file = "numpy-1.24.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea8282b9bcfe2b5e7d491d0bf7f3e2da29700cec05b49e64d6246923329f2b02"}, + {file = "numpy-1.24.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210461d87fb02a84ef243cac5e814aad2b7f4be953b32cb53327bb49fd77fbb4"}, + {file = "numpy-1.24.3-cp39-cp39-win32.whl", hash = "sha256:784c6da1a07818491b0ffd63c6bbe5a33deaa0e25a20e1b3ea20cf0e43f8046c"}, + {file = "numpy-1.24.3-cp39-cp39-win_amd64.whl", hash = "sha256:d5036197ecae68d7f491fcdb4df90082b0d4960ca6599ba2659957aafced7c17"}, + {file = "numpy-1.24.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:352ee00c7f8387b44d19f4cada524586f07379c0d49270f87233983bc5087ca0"}, + {file = "numpy-1.24.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a7d6acc2e7524c9955e5c903160aa4ea083736fde7e91276b0e5d98e6332812"}, + {file = "numpy-1.24.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:35400e6a8d102fd07c71ed7dcadd9eb62ee9a6e84ec159bd48c28235bbb0f8e4"}, + {file = "numpy-1.24.3.tar.gz", hash = "sha256:ab344f1bf21f140adab8e47fdbc7c35a477dc01408791f8ba00d018dd0bc5155"}, ] [[package]] name = "oauthlib" version = "3.2.2" description = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1412,7 +1321,6 @@ signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"] name = "opencv-python" version = "4.7.0.72" description = "Wrapper package for OpenCV python bindings." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1437,68 +1345,63 @@ numpy = [ [[package]] name = "orjson" -version = "3.8.8" +version = "3.8.12" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "orjson-3.8.8-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:18fcdea75d8b571dc9b185652b81397b62878ae7934fd62e6a0103a5b8448e34"}, - {file = "orjson-3.8.8-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:306618884929b596e2e083f82b5617da812df25b0c467542371f1d51f0c5a6f5"}, - {file = "orjson-3.8.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edc65ddb6ae6f8fbb2bbf78ac98f75b729c9eeb0776d5508dd76d3a948dda1dd"}, - {file = "orjson-3.8.8-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e6a6d55e01bce74516dff15302627a13b1f4edcb1c3942dd660978dee423ccf2"}, - {file = "orjson-3.8.8-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:28075c4b502d792fb6703e983d456b2a30d5d6f332d26092eb312dc782e64c64"}, - {file = "orjson-3.8.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eda4c37e48ff549763183a1549c10eec6ea40439520b17d09359cd74a425069"}, - {file = "orjson-3.8.8-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a3eac485a15493164867729f44e1e1247b3094ff19d37708e8cdc9c88a93c623"}, - {file = "orjson-3.8.8-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:88bf40e5468444c04374d1b8f1877cebbaef6bb7406cb6b4a34a570c5cbb87bc"}, - {file = "orjson-3.8.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:747bd4e09d8aa61e1ff677a7dd1cffd28a5d13c22f3769123c58ec988bf1b83d"}, - {file = "orjson-3.8.8-cp310-none-win_amd64.whl", hash = "sha256:dd7d86c5f5f820ac9d4783477e86eb984b63bdb32359935609eb33cf65049c54"}, - {file = "orjson-3.8.8-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:52293a6097750c2d434737966fe6e2a1ed489ac70cc8e584f5944af83de0b787"}, - {file = "orjson-3.8.8-cp311-cp311-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:9322450f392dceb49810d2f820b1932af22d66f67f1d45c31f160067dd06359f"}, - {file = "orjson-3.8.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68d59e3ae84a9b6f14b45a89f7fde4a08a87ea5eb76bfc854b354640de8156f5"}, - {file = "orjson-3.8.8-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:022347dad2253081eaa25366834bb8b06a5aceb0e83b39c6b0aa865759e49d69"}, - {file = "orjson-3.8.8-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ddfcc54793e266056fe1c257d0804c336bca1c5c1ee7979d674e1fc19cfb0a6a"}, - {file = "orjson-3.8.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:449d8ed1e0e6b24e9df5a06b59fd66ea7f7293e141257069601ae8ff9fad705c"}, - {file = "orjson-3.8.8-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:0204bc414bc6f7a595211569840b422d96649fd8686efa1fbbcb12eed5dd9521"}, - {file = "orjson-3.8.8-cp311-none-win_amd64.whl", hash = "sha256:e991a5c2c5f2f299c77e1d07ef2812ff5b68e1d97a2aab01aca29cf756473aa3"}, - {file = "orjson-3.8.8-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:2006d9c046bbf335c951f61e016a27bd4f17323dd116f601e4a8a11739cd0a62"}, - {file = "orjson-3.8.8-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:4553d85bad4cbd634a40b7b5d36daaa197a6025f9ce3e2165b371e528759093d"}, - {file = "orjson-3.8.8-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57ee45d2cc6c11c50afb5a0c09d7cd559aea76c77250dbe996be6a03464d4a50"}, - {file = "orjson-3.8.8-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:02f5b5db1e424706eb9f70f1c25699ff4cef16fadfc64af5b70f8628eafe4771"}, - {file = "orjson-3.8.8-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4d7c9f3b1598a1ccd806ef02257a76a00c7ede09662ddb54eec2b4bd92874254"}, - {file = "orjson-3.8.8-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b90d171932b6a9d50e79fa2762cb303e3556bbf25c08bb316fe346ec58af9c19"}, - {file = "orjson-3.8.8-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:28dfe774c345130f1117c4d023644ec52d9d50e3eaadb9bd1c668d91dc109bb5"}, - {file = "orjson-3.8.8-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8f84116fcc3714e7ba3cbeb1b11ac5e4549e7d2726c50142f8299fff9dea7d53"}, - {file = "orjson-3.8.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:f989f8580db86166aaaa938ccd1597ba1817e3f5df14c047baafe783e3d24173"}, - {file = "orjson-3.8.8-cp37-none-win_amd64.whl", hash = "sha256:66045850f286090800a18662d81d44f88c3fcb60ea3a9947d5caeab5d1efc92e"}, - {file = "orjson-3.8.8-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:2c2c5f3d3bbd61dba646e2b9c54a0dd7941b03fba49726bd31c1c23fedf0b9aa"}, - {file = "orjson-3.8.8-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:9cb36d4a14f3a911369219d5abc19b907bc41ed2730f7bfe0847b0fd3e834c87"}, - {file = "orjson-3.8.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:343124f84da0a33c83ee106a98b3e3c42767c88323d4a2809683cbe83816e8be"}, - {file = "orjson-3.8.8-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:24ad122d8dd057acf2a9965a2ffc1bc12fb310ae1cfe2912db930cbb9ef7eaba"}, - {file = "orjson-3.8.8-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c2f28a92a9bcb4e8635524b20db1b539bda8613872f306b36cdfd9d3577d03ac"}, - {file = "orjson-3.8.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81d3c5b253eebfc4a61cea1f255a576cb2b889afa99f4510f30ec13201d4f457"}, - {file = "orjson-3.8.8-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:317164f7d4c0540a6eb8b0a0faeec84ef011d359da05188423db762b65f84e1d"}, - {file = "orjson-3.8.8-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5e7e39357371d4ae5649f33c01886508a4c8e5fa5c7344554af041dc0f004c01"}, - {file = "orjson-3.8.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:60fefd4bbd796b4296f478e705fe2c2c7defd28da98d3017743eb87c3238a380"}, - {file = "orjson-3.8.8-cp38-none-win_amd64.whl", hash = "sha256:0dc4a52f1087baeec6b58248fd6b01f17c124fb99f6f770596851ea434a7be0b"}, - {file = "orjson-3.8.8-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:a6bcb449537a99f55c5f05187bac00b4549a795e89c10dcca0d7629548852357"}, - {file = "orjson-3.8.8-cp39-cp39-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:9c98dc791aa44268ba7f6e21124cf885c813b155316c6bf257560571d243fe15"}, - {file = "orjson-3.8.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b2abf93b727a6af7c5ec8816168cbdff39c716af18ced425dd50ae46d69765c"}, - {file = "orjson-3.8.8-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:23447d38375a19d57975d4e32d9ce9f533803c197fd4292e10d3234c052037a8"}, - {file = "orjson-3.8.8-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c2e19d2b46cc93c7218bf8180807bf922ff61dc9883458a06edc66d22970fff"}, - {file = "orjson-3.8.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e480d74d7bf415e6548a364669404119a85dbe0e3c6cd5f7cb4c7003eac20164"}, - {file = "orjson-3.8.8-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:8e0bff5656b99dd975cae2e5230b39e5909d06c0692fd1f6f06dc46f1fe705d0"}, - {file = "orjson-3.8.8-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:56bb6eb7a254eec3b15feba9b20f4172ccbe6ea50a54cf66cbc8e1e4a19585c2"}, - {file = "orjson-3.8.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1af1cfad5d90b68e15fd625c889c4f9f91d7a88f49512cdb89f01c3881e0c9d9"}, - {file = "orjson-3.8.8-cp39-none-win_amd64.whl", hash = "sha256:d5514dfe200356a1d5a6039e00dca78d87d063f3da1eb6a371253e5a8b7ab5b0"}, - {file = "orjson-3.8.8.tar.gz", hash = "sha256:c096d7a523bae6ffb9c4a228ba4691d66113f0f2231579dc945523fbef09c6da"}, + {file = "orjson-3.8.12-cp310-cp310-macosx_11_0_x86_64.macosx_11_0_arm64.macosx_11_0_universal2.whl", hash = "sha256:c84046e890e13a119404a83f2e09e622509ed4692846ff94c4ca03654fbc7fb5"}, + {file = "orjson-3.8.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29706dd8189835bcf1781faed286e99ae54fd6165437d364dfdbf0276bf39b19"}, + {file = "orjson-3.8.12-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f4e22b0aa70c963ac01fcd620de15be21a5027711b0e5d4b96debcdeea43e3ae"}, + {file = "orjson-3.8.12-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6d1acf52d3a4b9384af09a5c2658c3a7a472a4d62a0ad1fe2c8fab8ef460c9b4"}, + {file = "orjson-3.8.12-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a72b50719bdd6bb0acfca3d4d1c841aa4b191f3ff37268e7aba04e5d6be44ccd"}, + {file = "orjson-3.8.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83e8c740a718fa6d511a82e463adc7ab17631c6eea81a716b723e127a9c51d57"}, + {file = "orjson-3.8.12-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ebb03e4c7648f7bb299872002a6120082da018f41ba7a9ebf4ceae8d765443d2"}, + {file = "orjson-3.8.12-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:44f7bb4c995652106276442de1147c9993716d1e2d79b7fd435afa154ff236b9"}, + {file = "orjson-3.8.12-cp310-none-win_amd64.whl", hash = "sha256:06e528f9a84fbb4000fd0eee573b5db543ee70ae586fdbc53e740b0ac981701c"}, + {file = "orjson-3.8.12-cp311-cp311-macosx_11_0_x86_64.macosx_11_0_arm64.macosx_11_0_universal2.whl", hash = "sha256:9a6c1594d5a9ff56e5babc4a87ac372af38d37adef9e06744e9f158431e33f43"}, + {file = "orjson-3.8.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6390ce0bce24c107fc275736aa8a4f768ef7eb5df935d7dca0cc99815eb5d99"}, + {file = "orjson-3.8.12-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:efb3a10030462a22c731682434df5c137a67632a8339f821cd501920b169007e"}, + {file = "orjson-3.8.12-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7e405d54c84c30d9b1c918c290bcf4ef484a45c69d5583a95db81ffffba40b44"}, + {file = "orjson-3.8.12-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd6fbd1413559572e81b5ac64c45388147c3ba85cc3df2eaa11002945e0dbd1f"}, + {file = "orjson-3.8.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f480ae7b84369b1860d8867f0baf8d885fede400fda390ce088bfa8edf97ffdc"}, + {file = "orjson-3.8.12-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:355055e0977c43b0e5325b9312b7208c696fe20cd54eed1d6fc80b0a4d6721f5"}, + {file = "orjson-3.8.12-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d937503e4dfba5edc8d5e0426d3cc97ed55716e93212b2e12a198664487b9965"}, + {file = "orjson-3.8.12-cp311-none-win_amd64.whl", hash = "sha256:eb16e0195febd24b44f4db1ab3be85ecf6038f92fd511370cebc004b3d422294"}, + {file = "orjson-3.8.12-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:dc27a8ec13f28e92dc1ea89bf1232d77e7d3ebfd5c1ccf4f3729a70561cb63bd"}, + {file = "orjson-3.8.12-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77710774faed337ac4ad919dadc5f3b655b0cd40518e5386e6f1f116de9c6c25"}, + {file = "orjson-3.8.12-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7e549468867991f6f9cfbd9c5bbc977330173bd8f6ceb79973bbd4634e13e1b9"}, + {file = "orjson-3.8.12-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:96fb1eb82b578eb6c0e53e3cf950839fe98ea210626f87c8204bd4fc2cc6ba02"}, + {file = "orjson-3.8.12-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d153b228b6e24f8bccf732a51e01e8e938eef59efed9030c5c257778fbe0804"}, + {file = "orjson-3.8.12-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:becbd5af6d035a7ec2ee3239d4700929d52d8517806b97dd04efcc37289403f7"}, + {file = "orjson-3.8.12-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7d63f524048825e05950db3b6998c756d5377a5e8c469b2e3bdb9f3217523d74"}, + {file = "orjson-3.8.12-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ec4f0130d9a27cb400423e09e0f9e46480e9e977f05fdcf663a7a2c68735513e"}, + {file = "orjson-3.8.12-cp37-none-win_amd64.whl", hash = "sha256:6f1b01f641f5e87168b819ac1cbd81aa6278e7572c326f3d27e92dea442a2c0d"}, + {file = "orjson-3.8.12-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:062e67108c218fdb9475edd5272b1629c05b56c66416fa915de5656adde30e73"}, + {file = "orjson-3.8.12-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ba645c92801417933fa74448622ba614a275ea82df05e888095c7742d913bb4"}, + {file = "orjson-3.8.12-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7d50d9b1ae409ea15534365fec0ce8a5a5f7dc94aa790aacfb8cfec87ab51aa4"}, + {file = "orjson-3.8.12-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f00038bf5d07439d13c0c2c5cd6ad48eb86df7dbd7a484013ce6a113c421b14"}, + {file = "orjson-3.8.12-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:397670665f94cf5cff779054781d80395084ba97191d82f7b3a86f0a20e6102b"}, + {file = "orjson-3.8.12-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f568205519bb0197ca91915c5da6058cfbb59993e557b02dfc3b2718b34770a"}, + {file = "orjson-3.8.12-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4fd240e736ce52cd757d74142d9933fd35a3184396be887c435f0574e0388654"}, + {file = "orjson-3.8.12-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6cae2ff288a80e81ce30313e735c5436495ab58cf8d4fbe84900e616d0ee7a78"}, + {file = "orjson-3.8.12-cp38-none-win_amd64.whl", hash = "sha256:710c40c214b753392e46f9275fd795e9630dd737a5ab4ac6e4ee1a02fe83cc0d"}, + {file = "orjson-3.8.12-cp39-cp39-macosx_11_0_x86_64.macosx_11_0_arm64.macosx_11_0_universal2.whl", hash = "sha256:aff761de5ed5543a0a51e9f703668624749aa2239de5d7d37d9c9693daeaf5dc"}, + {file = "orjson-3.8.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:135f29cf936283a0cd1b8bce86540ca181108f2a4d4483eedad6b8026865d2a9"}, + {file = "orjson-3.8.12-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:62f999798f2fa55e567d483864ebfc30120fb055c2696a255979439323a5b15c"}, + {file = "orjson-3.8.12-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fa58ca064c640fa9d823f98fbbc8e71940ecb78cea3ac2507da1cbf49d60b51"}, + {file = "orjson-3.8.12-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8682f752c19f6a7d9fc727fd98588b4c8b0dce791b5794bb814c7379ccd64a79"}, + {file = "orjson-3.8.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de3d096dde3e46d01841abc1982b906694ab3c92f338d37a2e6184739dc8a958"}, + {file = "orjson-3.8.12-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:834b50df79f1fe89bbaced3a1c1d8c8c92cc99e84cdcd374d8da4974b3560d2a"}, + {file = "orjson-3.8.12-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2ad149ed76dce2bbdfbadd61c35959305e77141badf364a158beb4ef3d88ec37"}, + {file = "orjson-3.8.12-cp39-none-win_amd64.whl", hash = "sha256:82d65e478a21f98107b4eb8390104746bb3024c27084b57edab7d427385f1f70"}, + {file = "orjson-3.8.12.tar.gz", hash = "sha256:9f0f042cf002a474a6aea006dd9f8d7a5497e35e5fb190ec78eb4d232ec19955"}, ] [[package]] name = "ovld" version = "0.3.2" description = "Overloading Python functions" -category = "main" optional = false python-versions = ">=3.6,<4.0" files = [ @@ -1508,21 +1411,19 @@ files = [ [[package]] name = "packaging" -version = "23.0" +version = "23.1" description = "Core utilities for Python packages" -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"}, - {file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"}, + {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, + {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, ] [[package]] name = "pandas" version = "1.5.3" description = "Powerful data structures for data analysis, time series, and statistics" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1570,7 +1471,6 @@ test = ["hypothesis (>=5.5.3)", "pytest (>=6.0)", "pytest-xdist (>=1.31)"] name = "pastypy" version = "1.0.3.post1" description = "Pasty API wrapper" -category = "main" optional = false python-versions = ">=3.10,<4" files = [ @@ -1588,7 +1488,6 @@ tomli = ">=2.0.1,<3.0.0" name = "pathspec" version = "0.11.1" description = "Utility library for gitignore style pattern matching of file paths." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1598,116 +1497,102 @@ files = [ [[package]] name = "pillow" -version = "9.4.0" +version = "9.5.0" description = "Python Imaging Library (Fork)" -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "Pillow-9.4.0-1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1b4b4e9dda4f4e4c4e6896f93e84a8f0bcca3b059de9ddf67dac3c334b1195e1"}, - {file = "Pillow-9.4.0-1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:fb5c1ad6bad98c57482236a21bf985ab0ef42bd51f7ad4e4538e89a997624e12"}, - {file = "Pillow-9.4.0-1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:f0caf4a5dcf610d96c3bd32932bfac8aee61c96e60481c2a0ea58da435e25acd"}, - {file = "Pillow-9.4.0-1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:3f4cc516e0b264c8d4ccd6b6cbc69a07c6d582d8337df79be1e15a5056b258c9"}, - {file = "Pillow-9.4.0-1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:b8c2f6eb0df979ee99433d8b3f6d193d9590f735cf12274c108bd954e30ca858"}, - {file = "Pillow-9.4.0-1-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b70756ec9417c34e097f987b4d8c510975216ad26ba6e57ccb53bc758f490dab"}, - {file = "Pillow-9.4.0-1-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:43521ce2c4b865d385e78579a082b6ad1166ebed2b1a2293c3be1d68dd7ca3b9"}, - {file = "Pillow-9.4.0-2-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:9d9a62576b68cd90f7075876f4e8444487db5eeea0e4df3ba298ee38a8d067b0"}, - {file = "Pillow-9.4.0-2-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:87708d78a14d56a990fbf4f9cb350b7d89ee8988705e58e39bdf4d82c149210f"}, - {file = "Pillow-9.4.0-2-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:8a2b5874d17e72dfb80d917213abd55d7e1ed2479f38f001f264f7ce7bae757c"}, - {file = "Pillow-9.4.0-2-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:83125753a60cfc8c412de5896d10a0a405e0bd88d0470ad82e0869ddf0cb3848"}, - {file = "Pillow-9.4.0-2-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:9e5f94742033898bfe84c93c831a6f552bb629448d4072dd312306bab3bd96f1"}, - {file = "Pillow-9.4.0-2-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:013016af6b3a12a2f40b704677f8b51f72cb007dac785a9933d5c86a72a7fe33"}, - {file = "Pillow-9.4.0-2-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:99d92d148dd03fd19d16175b6d355cc1b01faf80dae93c6c3eb4163709edc0a9"}, - {file = "Pillow-9.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:2968c58feca624bb6c8502f9564dd187d0e1389964898f5e9e1fbc8533169157"}, - {file = "Pillow-9.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c5c1362c14aee73f50143d74389b2c158707b4abce2cb055b7ad37ce60738d47"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd752c5ff1b4a870b7661234694f24b1d2b9076b8bf337321a814c612665f343"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a3049a10261d7f2b6514d35bbb7a4dfc3ece4c4de14ef5876c4b7a23a0e566d"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16a8df99701f9095bea8a6c4b3197da105df6f74e6176c5b410bc2df2fd29a57"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:94cdff45173b1919350601f82d61365e792895e3c3a3443cf99819e6fbf717a5"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:ed3e4b4e1e6de75fdc16d3259098de7c6571b1a6cc863b1a49e7d3d53e036070"}, - {file = "Pillow-9.4.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5b2f8a31bd43e0f18172d8ac82347c8f37ef3e0b414431157718aa234991b28"}, - {file = "Pillow-9.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:09b89ddc95c248ee788328528e6a2996e09eaccddeeb82a5356e92645733be35"}, - {file = "Pillow-9.4.0-cp310-cp310-win32.whl", hash = "sha256:f09598b416ba39a8f489c124447b007fe865f786a89dbfa48bb5cf395693132a"}, - {file = "Pillow-9.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:f6e78171be3fb7941f9910ea15b4b14ec27725865a73c15277bc39f5ca4f8391"}, - {file = "Pillow-9.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:3fa1284762aacca6dc97474ee9c16f83990b8eeb6697f2ba17140d54b453e133"}, - {file = "Pillow-9.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:eaef5d2de3c7e9b21f1e762f289d17b726c2239a42b11e25446abf82b26ac132"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4dfdae195335abb4e89cc9762b2edc524f3c6e80d647a9a81bf81e17e3fb6f0"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6abfb51a82e919e3933eb137e17c4ae9c0475a25508ea88993bb59faf82f3b35"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:451f10ef963918e65b8869e17d67db5e2f4ab40e716ee6ce7129b0cde2876eab"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:6663977496d616b618b6cfa43ec86e479ee62b942e1da76a2c3daa1c75933ef4"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:60e7da3a3ad1812c128750fc1bc14a7ceeb8d29f77e0a2356a8fb2aa8925287d"}, - {file = "Pillow-9.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:19005a8e58b7c1796bc0167862b1f54a64d3b44ee5d48152b06bb861458bc0f8"}, - {file = "Pillow-9.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f715c32e774a60a337b2bb8ad9839b4abf75b267a0f18806f6f4f5f1688c4b5a"}, - {file = "Pillow-9.4.0-cp311-cp311-win32.whl", hash = "sha256:b222090c455d6d1a64e6b7bb5f4035c4dff479e22455c9eaa1bdd4c75b52c80c"}, - {file = "Pillow-9.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:ba6612b6548220ff5e9df85261bddc811a057b0b465a1226b39bfb8550616aee"}, - {file = "Pillow-9.4.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:5f532a2ad4d174eb73494e7397988e22bf427f91acc8e6ebf5bb10597b49c493"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dd5a9c3091a0f414a963d427f920368e2b6a4c2f7527fdd82cde8ef0bc7a327"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef21af928e807f10bf4141cad4746eee692a0dd3ff56cfb25fce076ec3cc8abe"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:847b114580c5cc9ebaf216dd8c8dbc6b00a3b7ab0131e173d7120e6deade1f57"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:653d7fb2df65efefbcbf81ef5fe5e5be931f1ee4332c2893ca638c9b11a409c4"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:46f39cab8bbf4a384ba7cb0bc8bae7b7062b6a11cfac1ca4bc144dea90d4a9f5"}, - {file = "Pillow-9.4.0-cp37-cp37m-win32.whl", hash = "sha256:7ac7594397698f77bce84382929747130765f66406dc2cd8b4ab4da68ade4c6e"}, - {file = "Pillow-9.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:46c259e87199041583658457372a183636ae8cd56dbf3f0755e0f376a7f9d0e6"}, - {file = "Pillow-9.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:0e51f608da093e5d9038c592b5b575cadc12fd748af1479b5e858045fff955a9"}, - {file = "Pillow-9.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:765cb54c0b8724a7c12c55146ae4647e0274a839fb6de7bcba841e04298e1011"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:519e14e2c49fcf7616d6d2cfc5c70adae95682ae20f0395e9280db85e8d6c4df"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d197df5489004db87d90b918033edbeee0bd6df3848a204bca3ff0a903bef837"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0845adc64fe9886db00f5ab68c4a8cd933ab749a87747555cec1c95acea64b0b"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:e1339790c083c5a4de48f688b4841f18df839eb3c9584a770cbd818b33e26d5d"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:a96e6e23f2b79433390273eaf8cc94fec9c6370842e577ab10dabdcc7ea0a66b"}, - {file = "Pillow-9.4.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7cfc287da09f9d2a7ec146ee4d72d6ea1342e770d975e49a8621bf54eaa8f30f"}, - {file = "Pillow-9.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d7081c084ceb58278dd3cf81f836bc818978c0ccc770cbbb202125ddabec6628"}, - {file = "Pillow-9.4.0-cp38-cp38-win32.whl", hash = "sha256:df41112ccce5d47770a0c13651479fbcd8793f34232a2dd9faeccb75eb5d0d0d"}, - {file = "Pillow-9.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:7a21222644ab69ddd9967cfe6f2bb420b460dae4289c9d40ff9a4896e7c35c9a"}, - {file = "Pillow-9.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0f3269304c1a7ce82f1759c12ce731ef9b6e95b6df829dccd9fe42912cc48569"}, - {file = "Pillow-9.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cb362e3b0976dc994857391b776ddaa8c13c28a16f80ac6522c23d5257156bed"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2e0f87144fcbbe54297cae708c5e7f9da21a4646523456b00cc956bd4c65815"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:28676836c7796805914b76b1837a40f76827ee0d5398f72f7dcc634bae7c6264"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0884ba7b515163a1a05440a138adeb722b8a6ae2c2b33aea93ea3118dd3a899e"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:53dcb50fbdc3fb2c55431a9b30caeb2f7027fcd2aeb501459464f0214200a503"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:e8c5cf126889a4de385c02a2c3d3aba4b00f70234bfddae82a5eaa3ee6d5e3e6"}, - {file = "Pillow-9.4.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6c6b1389ed66cdd174d040105123a5a1bc91d0aa7059c7261d20e583b6d8cbd2"}, - {file = "Pillow-9.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0dd4c681b82214b36273c18ca7ee87065a50e013112eea7d78c7a1b89a739153"}, - {file = "Pillow-9.4.0-cp39-cp39-win32.whl", hash = "sha256:6d9dfb9959a3b0039ee06c1a1a90dc23bac3b430842dcb97908ddde05870601c"}, - {file = "Pillow-9.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:54614444887e0d3043557d9dbc697dbb16cfb5a35d672b7a0fcc1ed0cf1c600b"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b9b752ab91e78234941e44abdecc07f1f0d8f51fb62941d32995b8161f68cfe5"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d3b56206244dc8711f7e8b7d6cad4663917cd5b2d950799425076681e8766286"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aabdab8ec1e7ca7f1434d042bf8b1e92056245fb179790dc97ed040361f16bfd"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:db74f5562c09953b2c5f8ec4b7dfd3f5421f31811e97d1dbc0a7c93d6e3a24df"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e9d7747847c53a16a729b6ee5e737cf170f7a16611c143d95aa60a109a59c336"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b52ff4f4e002f828ea6483faf4c4e8deea8d743cf801b74910243c58acc6eda3"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:575d8912dca808edd9acd6f7795199332696d3469665ef26163cd090fa1f8bfa"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3c4ed2ff6760e98d262e0cc9c9a7f7b8a9f61aa4d47c58835cdaf7b0b8811bb"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e621b0246192d3b9cb1dc62c78cfa4c6f6d2ddc0ec207d43c0dedecb914f152a"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8f127e7b028900421cad64f51f75c051b628db17fb00e099eb148761eed598c9"}, - {file = "Pillow-9.4.0.tar.gz", hash = "sha256:a1c2d7780448eb93fbcc3789bf3916aa5720d942e37945f4056680317f1cd23e"}, + {file = "Pillow-9.5.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:ace6ca218308447b9077c14ea4ef381ba0b67ee78d64046b3f19cf4e1139ad16"}, + {file = "Pillow-9.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d3d403753c9d5adc04d4694d35cf0391f0f3d57c8e0030aac09d7678fa8030aa"}, + {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ba1b81ee69573fe7124881762bb4cd2e4b6ed9dd28c9c60a632902fe8db8b38"}, + {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe7e1c262d3392afcf5071df9afa574544f28eac825284596ac6db56e6d11062"}, + {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f36397bf3f7d7c6a3abdea815ecf6fd14e7fcd4418ab24bae01008d8d8ca15e"}, + {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:252a03f1bdddce077eff2354c3861bf437c892fb1832f75ce813ee94347aa9b5"}, + {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:85ec677246533e27770b0de5cf0f9d6e4ec0c212a1f89dfc941b64b21226009d"}, + {file = "Pillow-9.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b416f03d37d27290cb93597335a2f85ed446731200705b22bb927405320de903"}, + {file = "Pillow-9.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1781a624c229cb35a2ac31cc4a77e28cafc8900733a864870c49bfeedacd106a"}, + {file = "Pillow-9.5.0-cp310-cp310-win32.whl", hash = "sha256:8507eda3cd0608a1f94f58c64817e83ec12fa93a9436938b191b80d9e4c0fc44"}, + {file = "Pillow-9.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:d3c6b54e304c60c4181da1c9dadf83e4a54fd266a99c70ba646a9baa626819eb"}, + {file = "Pillow-9.5.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:7ec6f6ce99dab90b52da21cf0dc519e21095e332ff3b399a357c187b1a5eee32"}, + {file = "Pillow-9.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:560737e70cb9c6255d6dcba3de6578a9e2ec4b573659943a5e7e4af13f298f5c"}, + {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96e88745a55b88a7c64fa49bceff363a1a27d9a64e04019c2281049444a571e3"}, + {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d9c206c29b46cfd343ea7cdfe1232443072bbb270d6a46f59c259460db76779a"}, + {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cfcc2c53c06f2ccb8976fb5c71d448bdd0a07d26d8e07e321c103416444c7ad1"}, + {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:a0f9bb6c80e6efcde93ffc51256d5cfb2155ff8f78292f074f60f9e70b942d99"}, + {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8d935f924bbab8f0a9a28404422da8af4904e36d5c33fc6f677e4c4485515625"}, + {file = "Pillow-9.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fed1e1cf6a42577953abbe8e6cf2fe2f566daebde7c34724ec8803c4c0cda579"}, + {file = "Pillow-9.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c1170d6b195555644f0616fd6ed929dfcf6333b8675fcca044ae5ab110ded296"}, + {file = "Pillow-9.5.0-cp311-cp311-win32.whl", hash = "sha256:54f7102ad31a3de5666827526e248c3530b3a33539dbda27c6843d19d72644ec"}, + {file = "Pillow-9.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:cfa4561277f677ecf651e2b22dc43e8f5368b74a25a8f7d1d4a3a243e573f2d4"}, + {file = "Pillow-9.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:965e4a05ef364e7b973dd17fc765f42233415974d773e82144c9bbaaaea5d089"}, + {file = "Pillow-9.5.0-cp312-cp312-win32.whl", hash = "sha256:22baf0c3cf0c7f26e82d6e1adf118027afb325e703922c8dfc1d5d0156bb2eeb"}, + {file = "Pillow-9.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:432b975c009cf649420615388561c0ce7cc31ce9b2e374db659ee4f7d57a1f8b"}, + {file = "Pillow-9.5.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:5d4ebf8e1db4441a55c509c4baa7a0587a0210f7cd25fcfe74dbbce7a4bd1906"}, + {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:375f6e5ee9620a271acb6820b3d1e94ffa8e741c0601db4c0c4d3cb0a9c224bf"}, + {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99eb6cafb6ba90e436684e08dad8be1637efb71c4f2180ee6b8f940739406e78"}, + {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dfaaf10b6172697b9bceb9a3bd7b951819d1ca339a5ef294d1f1ac6d7f63270"}, + {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:763782b2e03e45e2c77d7779875f4432e25121ef002a41829d8868700d119392"}, + {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:35f6e77122a0c0762268216315bf239cf52b88865bba522999dc38f1c52b9b47"}, + {file = "Pillow-9.5.0-cp37-cp37m-win32.whl", hash = "sha256:aca1c196f407ec7cf04dcbb15d19a43c507a81f7ffc45b690899d6a76ac9fda7"}, + {file = "Pillow-9.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:322724c0032af6692456cd6ed554bb85f8149214d97398bb80613b04e33769f6"}, + {file = "Pillow-9.5.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:a0aa9417994d91301056f3d0038af1199eb7adc86e646a36b9e050b06f526597"}, + {file = "Pillow-9.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f8286396b351785801a976b1e85ea88e937712ee2c3ac653710a4a57a8da5d9c"}, + {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c830a02caeb789633863b466b9de10c015bded434deb3ec87c768e53752ad22a"}, + {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fbd359831c1657d69bb81f0db962905ee05e5e9451913b18b831febfe0519082"}, + {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8fc330c3370a81bbf3f88557097d1ea26cd8b019d6433aa59f71195f5ddebbf"}, + {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:7002d0797a3e4193c7cdee3198d7c14f92c0836d6b4a3f3046a64bd1ce8df2bf"}, + {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:229e2c79c00e85989a34b5981a2b67aa079fd08c903f0aaead522a1d68d79e51"}, + {file = "Pillow-9.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9adf58f5d64e474bed00d69bcd86ec4bcaa4123bfa70a65ce72e424bfb88ed96"}, + {file = "Pillow-9.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:662da1f3f89a302cc22faa9f14a262c2e3951f9dbc9617609a47521c69dd9f8f"}, + {file = "Pillow-9.5.0-cp38-cp38-win32.whl", hash = "sha256:6608ff3bf781eee0cd14d0901a2b9cc3d3834516532e3bd673a0a204dc8615fc"}, + {file = "Pillow-9.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:e49eb4e95ff6fd7c0c402508894b1ef0e01b99a44320ba7d8ecbabefddcc5569"}, + {file = "Pillow-9.5.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:482877592e927fd263028c105b36272398e3e1be3269efda09f6ba21fd83ec66"}, + {file = "Pillow-9.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3ded42b9ad70e5f1754fb7c2e2d6465a9c842e41d178f262e08b8c85ed8a1d8e"}, + {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c446d2245ba29820d405315083d55299a796695d747efceb5717a8b450324115"}, + {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8aca1152d93dcc27dc55395604dcfc55bed5f25ef4c98716a928bacba90d33a3"}, + {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:608488bdcbdb4ba7837461442b90ea6f3079397ddc968c31265c1e056964f1ef"}, + {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:60037a8db8750e474af7ffc9faa9b5859e6c6d0a50e55c45576bf28be7419705"}, + {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:07999f5834bdc404c442146942a2ecadd1cb6292f5229f4ed3b31e0a108746b1"}, + {file = "Pillow-9.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a127ae76092974abfbfa38ca2d12cbeddcdeac0fb71f9627cc1135bedaf9d51a"}, + {file = "Pillow-9.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:489f8389261e5ed43ac8ff7b453162af39c3e8abd730af8363587ba64bb2e865"}, + {file = "Pillow-9.5.0-cp39-cp39-win32.whl", hash = "sha256:9b1af95c3a967bf1da94f253e56b6286b50af23392a886720f563c547e48e964"}, + {file = "Pillow-9.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:77165c4a5e7d5a284f10a6efaa39a0ae8ba839da344f20b111d62cc932fa4e5d"}, + {file = "Pillow-9.5.0-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:833b86a98e0ede388fa29363159c9b1a294b0905b5128baf01db683672f230f5"}, + {file = "Pillow-9.5.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aaf305d6d40bd9632198c766fb64f0c1a83ca5b667f16c1e79e1661ab5060140"}, + {file = "Pillow-9.5.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0852ddb76d85f127c135b6dd1f0bb88dbb9ee990d2cd9aa9e28526c93e794fba"}, + {file = "Pillow-9.5.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:91ec6fe47b5eb5a9968c79ad9ed78c342b1f97a091677ba0e012701add857829"}, + {file = "Pillow-9.5.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:cb841572862f629b99725ebaec3287fc6d275be9b14443ea746c1dd325053cbd"}, + {file = "Pillow-9.5.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:c380b27d041209b849ed246b111b7c166ba36d7933ec6e41175fd15ab9eb1572"}, + {file = "Pillow-9.5.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c9af5a3b406a50e313467e3565fc99929717f780164fe6fbb7704edba0cebbe"}, + {file = "Pillow-9.5.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5671583eab84af046a397d6d0ba25343c00cd50bce03787948e0fff01d4fd9b1"}, + {file = "Pillow-9.5.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:84a6f19ce086c1bf894644b43cd129702f781ba5751ca8572f08aa40ef0ab7b7"}, + {file = "Pillow-9.5.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1e7723bd90ef94eda669a3c2c19d549874dd5badaeefabefd26053304abe5799"}, + {file = "Pillow-9.5.0.tar.gz", hash = "sha256:bf548479d336726d7a0eceb6e767e179fbde37833ae42794602631a070d630f1"}, ] [package.extras] -docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-issues (>=3.0.1)", "sphinx-removed-in", "sphinxext-opengraph"] +docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] [[package]] name = "platformdirs" -version = "3.1.1" +version = "3.5.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-3.1.1-py3-none-any.whl", hash = "sha256:e5986afb596e4bb5bde29a79ac9061aa955b94fca2399b7aaac4090860920dd8"}, - {file = "platformdirs-3.1.1.tar.gz", hash = "sha256:024996549ee88ec1a9aa99ff7f8fc819bb59e2c3477b410d90a16d32d6e707aa"}, + {file = "platformdirs-3.5.0-py3-none-any.whl", hash = "sha256:47692bc24c1958e8b0f13dd727307cff1db103fca36399f457da8e05f222fdc4"}, + {file = "platformdirs-3.5.0.tar.gz", hash = "sha256:7954a68d0ba23558d753f73437c55f89027cf8f5108c19844d4b82e5af396335"}, ] [package.extras] -docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] +docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] [[package]] name = "pre-commit" version = "2.21.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1724,26 +1609,25 @@ virtualenv = ">=20.10.0" [[package]] name = "psutil" -version = "5.9.4" +version = "5.9.5" description = "Cross-platform lib for process and system monitoring in Python." -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ - {file = "psutil-5.9.4-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:c1ca331af862803a42677c120aff8a814a804e09832f166f226bfd22b56feee8"}, - {file = "psutil-5.9.4-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:68908971daf802203f3d37e78d3f8831b6d1014864d7a85937941bb35f09aefe"}, - {file = "psutil-5.9.4-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:3ff89f9b835100a825b14c2808a106b6fdcc4b15483141482a12c725e7f78549"}, - {file = "psutil-5.9.4-cp27-cp27m-win32.whl", hash = "sha256:852dd5d9f8a47169fe62fd4a971aa07859476c2ba22c2254d4a1baa4e10b95ad"}, - {file = "psutil-5.9.4-cp27-cp27m-win_amd64.whl", hash = "sha256:9120cd39dca5c5e1c54b59a41d205023d436799b1c8c4d3ff71af18535728e94"}, - {file = "psutil-5.9.4-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:6b92c532979bafc2df23ddc785ed116fced1f492ad90a6830cf24f4d1ea27d24"}, - {file = "psutil-5.9.4-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:efeae04f9516907be44904cc7ce08defb6b665128992a56957abc9b61dca94b7"}, - {file = "psutil-5.9.4-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:54d5b184728298f2ca8567bf83c422b706200bcbbfafdc06718264f9393cfeb7"}, - {file = "psutil-5.9.4-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:16653106f3b59386ffe10e0bad3bb6299e169d5327d3f187614b1cb8f24cf2e1"}, - {file = "psutil-5.9.4-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54c0d3d8e0078b7666984e11b12b88af2db11d11249a8ac8920dd5ef68a66e08"}, - {file = "psutil-5.9.4-cp36-abi3-win32.whl", hash = "sha256:149555f59a69b33f056ba1c4eb22bb7bf24332ce631c44a319cec09f876aaeff"}, - {file = "psutil-5.9.4-cp36-abi3-win_amd64.whl", hash = "sha256:fd8522436a6ada7b4aad6638662966de0d61d241cb821239b2ae7013d41a43d4"}, - {file = "psutil-5.9.4-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:6001c809253a29599bc0dfd5179d9f8a5779f9dffea1da0f13c53ee568115e1e"}, - {file = "psutil-5.9.4.tar.gz", hash = "sha256:3d7f9739eb435d4b1338944abe23f49584bde5395f27487d2ee25ad9a8774a62"}, + {file = "psutil-5.9.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:be8929ce4313f9f8146caad4272f6abb8bf99fc6cf59344a3167ecd74f4f203f"}, + {file = "psutil-5.9.5-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ab8ed1a1d77c95453db1ae00a3f9c50227ebd955437bcf2a574ba8adbf6a74d5"}, + {file = "psutil-5.9.5-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:4aef137f3345082a3d3232187aeb4ac4ef959ba3d7c10c33dd73763fbc063da4"}, + {file = "psutil-5.9.5-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:ea8518d152174e1249c4f2a1c89e3e6065941df2fa13a1ab45327716a23c2b48"}, + {file = "psutil-5.9.5-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:acf2aef9391710afded549ff602b5887d7a2349831ae4c26be7c807c0a39fac4"}, + {file = "psutil-5.9.5-cp27-none-win32.whl", hash = "sha256:5b9b8cb93f507e8dbaf22af6a2fd0ccbe8244bf30b1baad6b3954e935157ae3f"}, + {file = "psutil-5.9.5-cp27-none-win_amd64.whl", hash = "sha256:8c5f7c5a052d1d567db4ddd231a9d27a74e8e4a9c3f44b1032762bd7b9fdcd42"}, + {file = "psutil-5.9.5-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:3c6f686f4225553615612f6d9bc21f1c0e305f75d7d8454f9b46e901778e7217"}, + {file = "psutil-5.9.5-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a7dd9997128a0d928ed4fb2c2d57e5102bb6089027939f3b722f3a210f9a8da"}, + {file = "psutil-5.9.5-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89518112647f1276b03ca97b65cc7f64ca587b1eb0278383017c2a0dcc26cbe4"}, + {file = "psutil-5.9.5-cp36-abi3-win32.whl", hash = "sha256:104a5cc0e31baa2bcf67900be36acde157756b9c44017b86b2c049f11957887d"}, + {file = "psutil-5.9.5-cp36-abi3-win_amd64.whl", hash = "sha256:b258c0c1c9d145a1d5ceffab1134441c4c5113b2417fafff7315a917a026c3c9"}, + {file = "psutil-5.9.5-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:c607bb3b57dc779d55e1554846352b4e358c10fff3abf3514a7a6601beebdb30"}, + {file = "psutil-5.9.5.tar.gz", hash = "sha256:5410638e4df39c54d957fc51ce03048acd8e6d60abc0f5107af51e5fb566eb3c"}, ] [package.extras] @@ -1753,7 +1637,6 @@ test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] name = "pycryptodome" version = "3.17" description = "Cryptographic library for Python" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -1794,48 +1677,47 @@ files = [ [[package]] name = "pydantic" -version = "1.10.7" +version = "1.10.12" description = "Data validation and settings management using python type hints" -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic-1.10.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e79e999e539872e903767c417c897e729e015872040e56b96e67968c3b918b2d"}, - {file = "pydantic-1.10.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:01aea3a42c13f2602b7ecbbea484a98169fb568ebd9e247593ea05f01b884b2e"}, - {file = "pydantic-1.10.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:516f1ed9bc2406a0467dd777afc636c7091d71f214d5e413d64fef45174cfc7a"}, - {file = "pydantic-1.10.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae150a63564929c675d7f2303008d88426a0add46efd76c3fc797cd71cb1b46f"}, - {file = "pydantic-1.10.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ecbbc51391248116c0a055899e6c3e7ffbb11fb5e2a4cd6f2d0b93272118a209"}, - {file = "pydantic-1.10.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f4a2b50e2b03d5776e7f21af73e2070e1b5c0d0df255a827e7c632962f8315af"}, - {file = "pydantic-1.10.7-cp310-cp310-win_amd64.whl", hash = "sha256:a7cd2251439988b413cb0a985c4ed82b6c6aac382dbaff53ae03c4b23a70e80a"}, - {file = "pydantic-1.10.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:68792151e174a4aa9e9fc1b4e653e65a354a2fa0fed169f7b3d09902ad2cb6f1"}, - {file = "pydantic-1.10.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe2507b8ef209da71b6fb5f4e597b50c5a34b78d7e857c4f8f3115effaef5fe"}, - {file = "pydantic-1.10.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10a86d8c8db68086f1e30a530f7d5f83eb0685e632e411dbbcf2d5c0150e8dcd"}, - {file = "pydantic-1.10.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d75ae19d2a3dbb146b6f324031c24f8a3f52ff5d6a9f22f0683694b3afcb16fb"}, - {file = "pydantic-1.10.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:464855a7ff7f2cc2cf537ecc421291b9132aa9c79aef44e917ad711b4a93163b"}, - {file = "pydantic-1.10.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:193924c563fae6ddcb71d3f06fa153866423ac1b793a47936656e806b64e24ca"}, - {file = "pydantic-1.10.7-cp311-cp311-win_amd64.whl", hash = "sha256:b4a849d10f211389502059c33332e91327bc154acc1845f375a99eca3afa802d"}, - {file = "pydantic-1.10.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cc1dde4e50a5fc1336ee0581c1612215bc64ed6d28d2c7c6f25d2fe3e7c3e918"}, - {file = "pydantic-1.10.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0cfe895a504c060e5d36b287ee696e2fdad02d89e0d895f83037245218a87fe"}, - {file = "pydantic-1.10.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:670bb4683ad1e48b0ecb06f0cfe2178dcf74ff27921cdf1606e527d2617a81ee"}, - {file = "pydantic-1.10.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:950ce33857841f9a337ce07ddf46bc84e1c4946d2a3bba18f8280297157a3fd1"}, - {file = "pydantic-1.10.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c15582f9055fbc1bfe50266a19771bbbef33dd28c45e78afbe1996fd70966c2a"}, - {file = "pydantic-1.10.7-cp37-cp37m-win_amd64.whl", hash = "sha256:82dffb306dd20bd5268fd6379bc4bfe75242a9c2b79fec58e1041fbbdb1f7914"}, - {file = "pydantic-1.10.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8c7f51861d73e8b9ddcb9916ae7ac39fb52761d9ea0df41128e81e2ba42886cd"}, - {file = "pydantic-1.10.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6434b49c0b03a51021ade5c4daa7d70c98f7a79e95b551201fff682fc1661245"}, - {file = "pydantic-1.10.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64d34ab766fa056df49013bb6e79921a0265204c071984e75a09cbceacbbdd5d"}, - {file = "pydantic-1.10.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:701daea9ffe9d26f97b52f1d157e0d4121644f0fcf80b443248434958fd03dc3"}, - {file = "pydantic-1.10.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cf135c46099ff3f919d2150a948ce94b9ce545598ef2c6c7bf55dca98a304b52"}, - {file = "pydantic-1.10.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b0f85904f73161817b80781cc150f8b906d521fa11e3cdabae19a581c3606209"}, - {file = "pydantic-1.10.7-cp38-cp38-win_amd64.whl", hash = "sha256:9f6f0fd68d73257ad6685419478c5aece46432f4bdd8d32c7345f1986496171e"}, - {file = "pydantic-1.10.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c230c0d8a322276d6e7b88c3f7ce885f9ed16e0910354510e0bae84d54991143"}, - {file = "pydantic-1.10.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:976cae77ba6a49d80f461fd8bba183ff7ba79f44aa5cfa82f1346b5626542f8e"}, - {file = "pydantic-1.10.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d45fc99d64af9aaf7e308054a0067fdcd87ffe974f2442312372dfa66e1001d"}, - {file = "pydantic-1.10.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d2a5ebb48958754d386195fe9e9c5106f11275867051bf017a8059410e9abf1f"}, - {file = "pydantic-1.10.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:abfb7d4a7cd5cc4e1d1887c43503a7c5dd608eadf8bc615413fc498d3e4645cd"}, - {file = "pydantic-1.10.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:80b1fab4deb08a8292d15e43a6edccdffa5377a36a4597bb545b93e79c5ff0a5"}, - {file = "pydantic-1.10.7-cp39-cp39-win_amd64.whl", hash = "sha256:d71e69699498b020ea198468e2480a2f1e7433e32a3a99760058c6520e2bea7e"}, - {file = "pydantic-1.10.7-py3-none-any.whl", hash = "sha256:0cd181f1d0b1d00e2b705f1bf1ac7799a2d938cce3376b8007df62b29be3c2c6"}, - {file = "pydantic-1.10.7.tar.gz", hash = "sha256:cfc83c0678b6ba51b0532bea66860617c4cd4251ecf76e9846fa5a9f3454e97e"}, + {file = "pydantic-1.10.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a1fcb59f2f355ec350073af41d927bf83a63b50e640f4dbaa01053a28b7a7718"}, + {file = "pydantic-1.10.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b7ccf02d7eb340b216ec33e53a3a629856afe1c6e0ef91d84a4e6f2fb2ca70fe"}, + {file = "pydantic-1.10.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8fb2aa3ab3728d950bcc885a2e9eff6c8fc40bc0b7bb434e555c215491bcf48b"}, + {file = "pydantic-1.10.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:771735dc43cf8383959dc9b90aa281f0b6092321ca98677c5fb6125a6f56d58d"}, + {file = "pydantic-1.10.12-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ca48477862372ac3770969b9d75f1bf66131d386dba79506c46d75e6b48c1e09"}, + {file = "pydantic-1.10.12-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a5e7add47a5b5a40c49b3036d464e3c7802f8ae0d1e66035ea16aa5b7a3923ed"}, + {file = "pydantic-1.10.12-cp310-cp310-win_amd64.whl", hash = "sha256:e4129b528c6baa99a429f97ce733fff478ec955513630e61b49804b6cf9b224a"}, + {file = "pydantic-1.10.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b0d191db0f92dfcb1dec210ca244fdae5cbe918c6050b342d619c09d31eea0cc"}, + {file = "pydantic-1.10.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:795e34e6cc065f8f498c89b894a3c6da294a936ee71e644e4bd44de048af1405"}, + {file = "pydantic-1.10.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69328e15cfda2c392da4e713443c7dbffa1505bc9d566e71e55abe14c97ddc62"}, + {file = "pydantic-1.10.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2031de0967c279df0d8a1c72b4ffc411ecd06bac607a212892757db7462fc494"}, + {file = "pydantic-1.10.12-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ba5b2e6fe6ca2b7e013398bc7d7b170e21cce322d266ffcd57cca313e54fb246"}, + {file = "pydantic-1.10.12-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2a7bac939fa326db1ab741c9d7f44c565a1d1e80908b3797f7f81a4f86bc8d33"}, + {file = "pydantic-1.10.12-cp311-cp311-win_amd64.whl", hash = "sha256:87afda5539d5140cb8ba9e8b8c8865cb5b1463924d38490d73d3ccfd80896b3f"}, + {file = "pydantic-1.10.12-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:549a8e3d81df0a85226963611950b12d2d334f214436a19537b2efed61b7639a"}, + {file = "pydantic-1.10.12-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:598da88dfa127b666852bef6d0d796573a8cf5009ffd62104094a4fe39599565"}, + {file = "pydantic-1.10.12-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba5c4a8552bff16c61882db58544116d021d0b31ee7c66958d14cf386a5b5350"}, + {file = "pydantic-1.10.12-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c79e6a11a07da7374f46970410b41d5e266f7f38f6a17a9c4823db80dadf4303"}, + {file = "pydantic-1.10.12-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ab26038b8375581dc832a63c948f261ae0aa21f1d34c1293469f135fa92972a5"}, + {file = "pydantic-1.10.12-cp37-cp37m-win_amd64.whl", hash = "sha256:e0a16d274b588767602b7646fa05af2782576a6cf1022f4ba74cbb4db66f6ca8"}, + {file = "pydantic-1.10.12-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6a9dfa722316f4acf4460afdf5d41d5246a80e249c7ff475c43a3a1e9d75cf62"}, + {file = "pydantic-1.10.12-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a73f489aebd0c2121ed974054cb2759af8a9f747de120acd2c3394cf84176ccb"}, + {file = "pydantic-1.10.12-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b30bcb8cbfccfcf02acb8f1a261143fab622831d9c0989707e0e659f77a18e0"}, + {file = "pydantic-1.10.12-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fcfb5296d7877af406ba1547dfde9943b1256d8928732267e2653c26938cd9c"}, + {file = "pydantic-1.10.12-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:2f9a6fab5f82ada41d56b0602606a5506aab165ca54e52bc4545028382ef1c5d"}, + {file = "pydantic-1.10.12-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:dea7adcc33d5d105896401a1f37d56b47d443a2b2605ff8a969a0ed5543f7e33"}, + {file = "pydantic-1.10.12-cp38-cp38-win_amd64.whl", hash = "sha256:1eb2085c13bce1612da8537b2d90f549c8cbb05c67e8f22854e201bde5d98a47"}, + {file = "pydantic-1.10.12-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ef6c96b2baa2100ec91a4b428f80d8f28a3c9e53568219b6c298c1125572ebc6"}, + {file = "pydantic-1.10.12-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6c076be61cd0177a8433c0adcb03475baf4ee91edf5a4e550161ad57fc90f523"}, + {file = "pydantic-1.10.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d5a58feb9a39f481eda4d5ca220aa8b9d4f21a41274760b9bc66bfd72595b86"}, + {file = "pydantic-1.10.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5f805d2d5d0a41633651a73fa4ecdd0b3d7a49de4ec3fadf062fe16501ddbf1"}, + {file = "pydantic-1.10.12-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:1289c180abd4bd4555bb927c42ee42abc3aee02b0fb2d1223fb7c6e5bef87dbe"}, + {file = "pydantic-1.10.12-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5d1197e462e0364906cbc19681605cb7c036f2475c899b6f296104ad42b9f5fb"}, + {file = "pydantic-1.10.12-cp39-cp39-win_amd64.whl", hash = "sha256:fdbdd1d630195689f325c9ef1a12900524dceb503b00a987663ff4f58669b93d"}, + {file = "pydantic-1.10.12-py3-none-any.whl", hash = "sha256:b749a43aa51e32839c9d71dc67eb1e4221bb04af1033a32e3923d46f9effa942"}, + {file = "pydantic-1.10.12.tar.gz", hash = "sha256:0fe8a415cea8f340e7a9af9c54fc71a649b43e8ca3cc732986116b3cb135d303"}, ] [package.dependencies] @@ -1849,7 +1731,6 @@ email = ["email-validator (>=1.0.3)"] name = "pyee" version = "8.2.2" description = "A port of node.js's EventEmitter to python." -category = "main" optional = false python-versions = "*" files = [ @@ -1859,14 +1740,13 @@ files = [ [[package]] name = "pygments" -version = "2.14.0" +version = "2.15.1" description = "Pygments is a syntax highlighting package written in Python." -category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "Pygments-2.14.0-py3-none-any.whl", hash = "sha256:fa7bd7bd2771287c0de303af8bfdfc731f51bd2c6a47ab69d117138893b82717"}, - {file = "Pygments-2.14.0.tar.gz", hash = "sha256:b3ed06a9e8ac9a9aae5a6f5dbe78a8a58655d17b43b93c078f094ddc476ae297"}, + {file = "Pygments-2.15.1-py3-none-any.whl", hash = "sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1"}, + {file = "Pygments-2.15.1.tar.gz", hash = "sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c"}, ] [package.extras] @@ -1876,7 +1756,6 @@ plugins = ["importlib-metadata"] name = "pymongo" version = "4.3.3" description = "Python driver for MongoDB " -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1971,7 +1850,6 @@ zstd = ["zstandard"] name = "pyppeteer" version = "1.0.2" description = "Headless chrome/chromium automation library (unofficial port of puppeteer)" -category = "main" optional = false python-versions = ">=3.7,<4.0" files = [ @@ -1992,7 +1870,6 @@ websockets = ">=10.0,<11.0" name = "python-dateutil" version = "2.8.2" description = "Extensions to the standard Python datetime module" -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ @@ -2007,7 +1884,6 @@ six = ">=1.5" name = "python-dotenv" version = "0.21.1" description = "Read key-value pairs from a .env file and set them as environment variables" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2020,14 +1896,13 @@ cli = ["click (>=5.0)"] [[package]] name = "python-gitlab" -version = "3.13.0" +version = "3.14.0" description = "Interact with GitLab API" -category = "main" optional = false python-versions = ">=3.7.0" files = [ - {file = "python-gitlab-3.13.0.tar.gz", hash = "sha256:ad502b72b5d1137f4af37d4a68ae20fe7d6c9778f67cbe2aec566f7995053c7d"}, - {file = "python_gitlab-3.13.0-py3-none-any.whl", hash = "sha256:85ae778d8953aba87ad4b78aef7fbb5dae053980d2c20ff200bea29799685743"}, + {file = "python-gitlab-3.14.0.tar.gz", hash = "sha256:ef3b8960faeee9880f82b0872d807e3fab94ace12b0d2a8418a97875c8812d3c"}, + {file = "python_gitlab-3.14.0-py3-none-any.whl", hash = "sha256:da614c014c6860147783dde8c216218d8fc6bd83a8bd2e3929dcdf11b211aa58"}, ] [package.dependencies] @@ -2040,24 +1915,22 @@ yaml = ["PyYaml (>=5.2)"] [[package]] name = "python-levenshtein" -version = "0.20.9" +version = "0.21.0" description = "Python extension for computing string edit distances and similarities." -category = "main" optional = false python-versions = ">=3.6" files = [ - {file = "python-Levenshtein-0.20.9.tar.gz", hash = "sha256:4c507b1e26de29374153982fa477cea741edf095d892773343b4961beacac834"}, - {file = "python_Levenshtein-0.20.9-py3-none-any.whl", hash = "sha256:2a6f8c97ba554d7399e0b450e1fce5d90d6354b1c1762e419671de27f25736c5"}, + {file = "python-Levenshtein-0.21.0.tar.gz", hash = "sha256:c97f60e694dcfc4eae7fabc19490e0892b212d975d70d1b14fc109e58c33b0bf"}, + {file = "python_Levenshtein-0.21.0-py3-none-any.whl", hash = "sha256:2e05a10989cae751669dc08c5d4934e2da489c9afb1545ecc1d8c8edb822b5ae"}, ] [package.dependencies] -Levenshtein = "0.20.9" +Levenshtein = "0.21.0" [[package]] name = "pytz" version = "2022.7.1" description = "World timezone definitions, modern and historical" -category = "main" optional = false python-versions = "*" files = [ @@ -2069,7 +1942,6 @@ files = [ name = "pytz-deprecation-shim" version = "0.1.0.post0" description = "Shims to make deprecation of pytz easier" -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ @@ -2084,7 +1956,6 @@ tzdata = {version = "*", markers = "python_version >= \"3.6\""} name = "pyyaml" version = "6.0" description = "YAML parser and emitter for Python" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -2132,101 +2003,103 @@ files = [ [[package]] name = "rapidfuzz" -version = "2.13.7" +version = "3.0.0" description = "rapid fuzzy string matching" -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "rapidfuzz-2.13.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b75dd0928ce8e216f88660ab3d5c5ffe990f4dd682fd1709dba29d5dafdde6de"}, - {file = "rapidfuzz-2.13.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:24d3fea10680d085fd0a4d76e581bfb2b1074e66e78fd5964d4559e1fcd2a2d4"}, - {file = "rapidfuzz-2.13.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8109e0324d21993d5b2d111742bf5958f3516bf8c59f297c5d1cc25a2342eb66"}, - {file = "rapidfuzz-2.13.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5f705652360d520c2de52bee11100c92f59b3e3daca308ebb150cbc58aecdad"}, - {file = "rapidfuzz-2.13.7-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7496e8779905b02abc0ab4ba2a848e802ab99a6e20756ffc967a0de4900bd3da"}, - {file = "rapidfuzz-2.13.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:24eb6b843492bdc63c79ee4b2f104059b7a2201fef17f25177f585d3be03405a"}, - {file = "rapidfuzz-2.13.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:467c1505362823a5af12b10234cb1c4771ccf124c00e3fc9a43696512bd52293"}, - {file = "rapidfuzz-2.13.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53dcae85956853b787c27c1cb06f18bb450e22cf57a4ad3444cf03b8ff31724a"}, - {file = "rapidfuzz-2.13.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:46b9b8aa09998bc48dd800854e8d9b74bc534d7922c1d6e1bbf783e7fa6ac29c"}, - {file = "rapidfuzz-2.13.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:1fbad8fb28d98980f5bff33c7842efef0315d42f0cd59082108482a7e6b61410"}, - {file = "rapidfuzz-2.13.7-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:43fb8cb030f888c3f076d40d428ed5eb4331f5dd6cf1796cfa39c67bf0f0fc1e"}, - {file = "rapidfuzz-2.13.7-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:b6bad92de071cbffa2acd4239c1779f66851b60ffbbda0e4f4e8a2e9b17e7eef"}, - {file = "rapidfuzz-2.13.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d00df2e4a81ffa56a6b1ec4d2bc29afdcb7f565e0b8cd3092fece2290c4c7a79"}, - {file = "rapidfuzz-2.13.7-cp310-cp310-win32.whl", hash = "sha256:2c836f0f2d33d4614c3fbaf9a1eb5407c0fe23f8876f47fd15b90f78daa64c34"}, - {file = "rapidfuzz-2.13.7-cp310-cp310-win_amd64.whl", hash = "sha256:c36fd260084bb636b9400bb92016c6bd81fd80e59ed47f2466f85eda1fc9f782"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b34e8c0e492949ecdd5da46a1cfc856a342e2f0389b379b1a45a3cdcd3176a6e"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:875d51b3497439a72e2d76183e1cb5468f3f979ab2ddfc1d1f7dde3b1ecfb42f"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ae33a72336059213996fe4baca4e0e4860913905c2efb7c991eab33b95a98a0a"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5585189b3d90d81ccd62d4f18530d5ac8972021f0aaaa1ffc6af387ff1dce75"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:42085d4b154a8232767de8296ac39c8af5bccee6b823b0507de35f51c9cbc2d7"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:585206112c294e335d84de5d5f179c0f932837752d7420e3de21db7fdc476278"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f891b98f8bc6c9d521785816085e9657212621e93f223917fb8e32f318b2957e"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08590905a95ccfa43f4df353dcc5d28c15d70664299c64abcad8721d89adce4f"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b5dd713a1734574c2850c566ac4286594bacbc2d60b9170b795bee4b68656625"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:988f8f6abfba7ee79449f8b50687c174733b079521c3cc121d65ad2d38831846"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:b3210869161a864f3831635bb13d24f4708c0aa7208ef5baac1ac4d46e9b4208"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:f6fe570e20e293eb50491ae14ddeef71a6a7e5f59d7e791393ffa99b13f1f8c2"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6120f2995f5154057454c5de99d86b4ef3b38397899b5da1265467e8980b2f60"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-win32.whl", hash = "sha256:b20141fa6cee041917801de0bab503447196d372d4c7ee9a03721b0a8edf5337"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-win_amd64.whl", hash = "sha256:ec55a81ac2b0f41b8d6fb29aad16e55417036c7563bad5568686931aa4ff08f7"}, - {file = "rapidfuzz-2.13.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7d005e058d86f2a968a8d28ca6f2052fab1f124a39035aa0523261d6baf21e1f"}, - {file = "rapidfuzz-2.13.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe59a0c21a032024edb0c8e43f5dee5623fef0b65a1e3c1281836d9ce199af3b"}, - {file = "rapidfuzz-2.13.7-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cdfc04f7647c29fb48da7a04082c34cdb16f878d3c6d098d62d5715c0ad3000c"}, - {file = "rapidfuzz-2.13.7-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:68a89bb06d5a331511961f4d3fa7606f8e21237467ba9997cae6f67a1c2c2b9e"}, - {file = "rapidfuzz-2.13.7-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:effe182767d102cb65dfbbf74192237dbd22d4191928d59415aa7d7c861d8c88"}, - {file = "rapidfuzz-2.13.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25b4cedf2aa19fb7212894ce5f5219010cce611b60350e9a0a4d492122e7b351"}, - {file = "rapidfuzz-2.13.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:3a9bd02e1679c0fd2ecf69b72d0652dbe2a9844eaf04a36ddf4adfbd70010e95"}, - {file = "rapidfuzz-2.13.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:5e2b3d020219baa75f82a4e24b7c8adcb598c62f0e54e763c39361a9e5bad510"}, - {file = "rapidfuzz-2.13.7-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:cf62dacb3f9234f3fddd74e178e6d25c68f2067fde765f1d95f87b1381248f58"}, - {file = "rapidfuzz-2.13.7-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:fa263135b892686e11d5b84f6a1892523123a00b7e5882eff4fbdabb38667347"}, - {file = "rapidfuzz-2.13.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:fa4c598ed77f74ec973247ca776341200b0f93ec3883e34c222907ce72cb92a4"}, - {file = "rapidfuzz-2.13.7-cp37-cp37m-win32.whl", hash = "sha256:c2523f8180ebd9796c18d809e9a19075a1060b1a170fde3799e83db940c1b6d5"}, - {file = "rapidfuzz-2.13.7-cp37-cp37m-win_amd64.whl", hash = "sha256:5ada0a14c67452358c1ee52ad14b80517a87b944897aaec3e875279371a9cb96"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ca8a23097c1f50e0fdb4de9e427537ca122a18df2eead06ed39c3a0bef6d9d3a"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9be02162af0376d64b840f2fc8ee3366794fc149f1e06d095a6a1d42447d97c5"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:af4f7c3c904ca709493eb66ca9080b44190c38e9ecb3b48b96d38825d5672559"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f50d1227e6e2a0e3ae1fb1c9a2e1c59577d3051af72c7cab2bcc430cb5e18da"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c71d9d512b76f05fa00282227c2ae884abb60e09f08b5ca3132b7e7431ac7f0d"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b52ac2626945cd21a2487aeefed794c14ee31514c8ae69b7599170418211e6f6"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca00fafd2756bc9649bf80f1cf72c647dce38635f0695d7ce804bc0f759aa756"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d248a109699ce9992304e79c1f8735c82cc4c1386cd8e27027329c0549f248a2"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c88adbcb933f6b8612f6c593384bf824e562bb35fc8a0f55fac690ab5b3486e5"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c8601a66fbfc0052bb7860d2eacd303fcde3c14e87fdde409eceff516d659e77"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:27be9c63215d302ede7d654142a2e21f0d34ea6acba512a4ae4cfd52bbaa5b59"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:3dcffe1f3cbda0dc32133a2ae2255526561ca594f15f9644384549037b355245"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8450d15f7765482e86ef9be2ad1a05683cd826f59ad236ef7b9fb606464a56aa"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-win32.whl", hash = "sha256:460853983ab88f873173e27cc601c5276d469388e6ad6e08c4fd57b2a86f1064"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-win_amd64.whl", hash = "sha256:424f82c35dbe4f83bdc3b490d7d696a1dc6423b3d911460f5493b7ffae999fd2"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c3fbe449d869ea4d0909fc9d862007fb39a584fb0b73349a6aab336f0d90eaed"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:16080c05a63d6042643ae9b6cfec1aefd3e61cef53d0abe0df3069b9d4b72077"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dbcf5371ea704759fcce772c66a07647751d1f5dbdec7818331c9b31ae996c77"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:114810491efb25464016fd554fdf1e20d390309cecef62587494fc474d4b926f"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99a84ab9ac9a823e7e93b4414f86344052a5f3e23b23aa365cda01393ad895bd"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:81642a24798851b118f82884205fc1bd9ff70b655c04018c467824b6ecc1fabc"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3741cb0bf9794783028e8b0cf23dab917fa5e37a6093b94c4c2f805f8e36b9f"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:759a3361711586a29bc753d3d1bdb862983bd9b9f37fbd7f6216c24f7c972554"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1333fb3d603d6b1040e365dca4892ba72c7e896df77a54eae27dc07db90906e3"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:916bc2e6cf492c77ad6deb7bcd088f0ce9c607aaeabc543edeb703e1fbc43e31"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:23524635840500ce6f4d25005c9529a97621689c85d2f727c52eed1782839a6a"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:ebe303cd9839af69dd1f7942acaa80b1ba90bacef2e7ded9347fbed4f1654672"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:fe56659ccadbee97908132135de4b875543353351e0c92e736b7c57aee298b5a"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-win32.whl", hash = "sha256:3f11a7eff7bc6301cd6a5d43f309e22a815af07e1f08eeb2182892fca04c86cb"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-win_amd64.whl", hash = "sha256:e8914dad106dacb0775718e54bf15e528055c4e92fb2677842996f2d52da5069"}, - {file = "rapidfuzz-2.13.7-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7f7930adf84301797c3f09c94b9c5a9ed90a9e8b8ed19b41d2384937e0f9f5bd"}, - {file = "rapidfuzz-2.13.7-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c31022d9970177f6affc6d5dd757ed22e44a10890212032fabab903fdee3bfe7"}, - {file = "rapidfuzz-2.13.7-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f42b82f268689f429def9ecfb86fa65ceea0eaf3fed408b570fe113311bf5ce7"}, - {file = "rapidfuzz-2.13.7-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b477b43ced896301665183a5e0faec0f5aea2373005648da8bdcb3c4b73f280"}, - {file = "rapidfuzz-2.13.7-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:d63def9bbc6b35aef4d76dc740301a4185867e8870cbb8719ec9de672212fca8"}, - {file = "rapidfuzz-2.13.7-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c66546e30addb04a16cd864f10f5821272a1bfe6462ee5605613b4f1cb6f7b48"}, - {file = "rapidfuzz-2.13.7-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f799d1d6c33d81e983d3682571cc7d993ae7ff772c19b3aabb767039c33f6d1e"}, - {file = "rapidfuzz-2.13.7-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d82f20c0060ffdaadaf642b88ab0aa52365b56dffae812e188e5bdb998043588"}, - {file = "rapidfuzz-2.13.7-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:042644133244bfa7b20de635d500eb9f46af7097f3d90b1724f94866f17cb55e"}, - {file = "rapidfuzz-2.13.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:75c45dcd595f8178412367e302fd022860ea025dc4a78b197b35428081ed33d5"}, - {file = "rapidfuzz-2.13.7-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3d8b081988d0a49c486e4e845a547565fee7c6e7ad8be57ff29c3d7c14c6894c"}, - {file = "rapidfuzz-2.13.7-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16ffad751f43ab61001187b3fb4a9447ec2d1aedeff7c5bac86d3b95f9980cc3"}, - {file = "rapidfuzz-2.13.7-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:020858dd89b60ce38811cd6e37875c4c3c8d7fcd8bc20a0ad2ed1f464b34dc4e"}, - {file = "rapidfuzz-2.13.7-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cda1e2f66bb4ba7261a0f4c2d052d5d909798fca557cbff68f8a79a87d66a18f"}, - {file = "rapidfuzz-2.13.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b6389c50d8d214c9cd11a77f6d501529cb23279a9c9cafe519a3a4b503b5f72a"}, - {file = "rapidfuzz-2.13.7.tar.gz", hash = "sha256:8d3e252d4127c79b4d7c2ae47271636cbaca905c8bb46d80c7930ab906cf4b5c"}, + {file = "rapidfuzz-3.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3ab635a544243e1924508bfc3f294c28bdced6d74388ac25041d3dabcaefab75"}, + {file = "rapidfuzz-3.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cf8b1b29028dc1bc6a5654f22425ee6d3967bbd44bc3a117be0f43b03300f928"}, + {file = "rapidfuzz-3.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2bbf9aad86b70283362dc2db3cacb7dcde0ffe6027f54feb0ccb23cf87b6aa11"}, + {file = "rapidfuzz-3.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a9b7d22e46ada4e6a1f1404c267f3f023b44594929913d855f14bc5fb11b53d"}, + {file = "rapidfuzz-3.0.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c81891e570e50d0afe43f722f426b0bd602d3c5315f0f290514511d9520b1e6"}, + {file = "rapidfuzz-3.0.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:abc2f05c1f30b9533cb9b85d73c28d93aa99c7ae2992df04c1704fcaf248b59c"}, + {file = "rapidfuzz-3.0.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:339b94c536ab9c1b1bac245fb6814df3ba104603d2c1a97f8fb41922357bd772"}, + {file = "rapidfuzz-3.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8883267df996b42494f40d533ef3a3fea247531d137773a649fb851747ae12c8"}, + {file = "rapidfuzz-3.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:59c6c9d3ca7d84c5878a74d142816350a3bdfb51e4d10ac104afd396168481f6"}, + {file = "rapidfuzz-3.0.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5759bb0fd13ee030626e8bbb5b644092a043817fb192335ff4c481402b1edd0e"}, + {file = "rapidfuzz-3.0.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:1fe6ea9300f347fd3352c755aa04d71a2786afa008d1af1a35830e6a44e7fd5f"}, + {file = "rapidfuzz-3.0.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:481c0389c3b26cd2aa498b6924ca6e9a1d1dd5b15ad5f009d273292949e47e24"}, + {file = "rapidfuzz-3.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:658be4cabcc229f52a902f5e87205e1b9c29c66e463a267c8d8f237acde56002"}, + {file = "rapidfuzz-3.0.0-cp310-cp310-win32.whl", hash = "sha256:7f8d89b16b4752deeb66dd321548c4cfa59819982d43d2ae7ab5d6e0f15bee94"}, + {file = "rapidfuzz-3.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:2132d7724c03dd322035cf1b0c23ca9e7e449ec2b7225040a2ca2fa3f1a3bbfa"}, + {file = "rapidfuzz-3.0.0-cp310-cp310-win_arm64.whl", hash = "sha256:0bf1953a4c32ce6e2f3ed1897d0a8dbbbf19456ef0a8e37bae26e007d9fb5096"}, + {file = "rapidfuzz-3.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:526df35d07083480e751f9679fd1f3e8a0819e8a13586e3860db5b65549a408a"}, + {file = "rapidfuzz-3.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:88c9e93508128168708aae3ef98eeb422a88204d81ac4492fcea1e1162a6af74"}, + {file = "rapidfuzz-3.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:562caa39652c72156574fcf60ce7adf29964a031a57ae977c180947e00425b4a"}, + {file = "rapidfuzz-3.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a149c944f3c349f6279a8cc4cbfa3e80cc2baaec9d983359698aa792faa44653"}, + {file = "rapidfuzz-3.0.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c40a626050e37c2f74e2ba00538578d3c4a6baa171d08ed5091b6a03512ac4a"}, + {file = "rapidfuzz-3.0.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6ee35eddeddb5f5750d2a9cc55894926969fa0bac80bbe57211ae6fd0d34b39f"}, + {file = "rapidfuzz-3.0.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c94fe53da481d8580e6410f3e7e4ba4e9c5786cad1f289fbb6c9c9585c6d78e1"}, + {file = "rapidfuzz-3.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4032713943c32fff97d863e6618162923e3b3c31917d437126d9fcf7e33c83d2"}, + {file = "rapidfuzz-3.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:dc1a39d1cc8e679c7240b2d1ed8366cf740ab8429cc9b582ebd94a5c6ededbe5"}, + {file = "rapidfuzz-3.0.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f213bb5d4cd0b1fddf209bafe2d2896320a737fbded3a567d454e54875e4d9cc"}, + {file = "rapidfuzz-3.0.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:c9ca5f4ae767605cefa5156f5fa8561bee61849f9b2ccfb165d7087b4f9af90c"}, + {file = "rapidfuzz-3.0.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:938cc766d0ce9eca95549593b6ca7ff86a2917b9e68c1989ad95485aed0f49dd"}, + {file = "rapidfuzz-3.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:87eb7e9fb49265c33bda0417cc74c474a891cae60735fbbd75d79a106483888e"}, + {file = "rapidfuzz-3.0.0-cp311-cp311-win32.whl", hash = "sha256:3f51d35521f86e767d3e640d0ab42908d01c3e05cf54ac1f0b547f3f602800f1"}, + {file = "rapidfuzz-3.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:4ef3a6aa07b996c789c8d5ab99ed0563d551d32fa9330fd0f52ba28d20fcb662"}, + {file = "rapidfuzz-3.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:7eea0ca53da78040a6b7bb041af8051c52efa7facc6f18dce33e679f2decaf62"}, + {file = "rapidfuzz-3.0.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6dfd138dcc0920b71c1d1bc017413b032286a1f33488613dce9e254c454abaf2"}, + {file = "rapidfuzz-3.0.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b81d15da16e97c288c645eb642d8a08d0ab98b827efb2682cab282a45893efe"}, + {file = "rapidfuzz-3.0.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ff8835a3ba17f3baf3838f2612e3758d7b1ca09eb16c9a382df3bec5bb9bda3"}, + {file = "rapidfuzz-3.0.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:82a4ea0742b9e375d4856714ef59241007765edbce34fd2f7d76c552ed93a7d2"}, + {file = "rapidfuzz-3.0.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f5767b0e8220b6f8afcc1fe77529e5678470f9e94a1cfc9e29f5b0721dc1496c"}, + {file = "rapidfuzz-3.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a8c372dc278d1d5ced7cdc99ad8cc1d3de0b245e769a6b327c462b98873e5d4"}, + {file = "rapidfuzz-3.0.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:5d8664d6f844ea9018b4866e8a8dbf49c87f703668b1b3265de83aa3c9941272"}, + {file = "rapidfuzz-3.0.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:fa098429af4e17fb5bacb0c39f1f8349891356ba7ca540521515b5708fec4a76"}, + {file = "rapidfuzz-3.0.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:738ae2d59ab254c4f173b40b00a9c1f092697949284c59e0879e6e3beb337a69"}, + {file = "rapidfuzz-3.0.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:1a5eb2d1844f375f34e3c83b1a03094293d894472fdd1a095cf35e4dfa2ecf01"}, + {file = "rapidfuzz-3.0.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:24d77723bb20030a91b096326d14b673d2ff1f0c7bbc64ed519992ed8eb5b869"}, + {file = "rapidfuzz-3.0.0-cp37-cp37m-win32.whl", hash = "sha256:b85dfb6f0c353c4b37499529f9831620a7bdc61c375e07f8c38b595f93e906e5"}, + {file = "rapidfuzz-3.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:54fb70b667b882f9939bc6f581957fcb47fec2e7ad652259835c80e9e30230c9"}, + {file = "rapidfuzz-3.0.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:4e1da3dce34d742567da0722b9c8dc2b51554ab5a22fdaf763b60209445a7b37"}, + {file = "rapidfuzz-3.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c50825de43442c4625a2ca1d948c911d116cf9007ad7f29cd27561c99b16947c"}, + {file = "rapidfuzz-3.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:69270e0cd850984f562b2239d07cde2213e5c3642cd8d550d5ac9a0fcd0882df"}, + {file = "rapidfuzz-3.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf5ddf48f63895f949355a1c4d643e0a531c9317d52901f80d5a6299d967b766"}, + {file = "rapidfuzz-3.0.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd2ad4160d8ad9a2abdad1c765fd29e4d9b6b8ce6a707ee48eb2869e7dff0f89"}, + {file = "rapidfuzz-3.0.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc39af05cdf89be426d96fce579c812948a324b022fb11dfea1e99e180d4f68b"}, + {file = "rapidfuzz-3.0.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d25555297466ab5ded3875913fc0bfa78b89b0a32d79bd65ffbd32ae71f07c2d"}, + {file = "rapidfuzz-3.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76da6c8972acd58c31efdd09c4c85263ba3b4394d2c2929be4c171a22293bab3"}, + {file = "rapidfuzz-3.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2b50f2d429d81a65910f5ee9b14e172e300a09b8b2ecb91d3e4efc5d2583915c"}, + {file = "rapidfuzz-3.0.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f00a8b3d0b21884ea972d5430797b1a25b9d2c715b3eaf03366903aac5d8398c"}, + {file = "rapidfuzz-3.0.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:e058ecfd8edb04b221d1b2d005f17be932075a16f75b100b275de1d3d220da5f"}, + {file = "rapidfuzz-3.0.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:35e21f0718fd1c1853f8f433f2f84f618f6d4a6d9d96bb7c42e39797be600b58"}, + {file = "rapidfuzz-3.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d128f615da9a198cd9b33be658a0c26fabe06a6d28fa4652953853e8d174c2c6"}, + {file = "rapidfuzz-3.0.0-cp38-cp38-win32.whl", hash = "sha256:bc593306faa6c73e50cb31b81efbb580957272b14c5cf6bcf0233adf8a7e118d"}, + {file = "rapidfuzz-3.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:0f7041c550b69d35675e04dc3f0690d0c26499039e942a0b1604c6547951e6fc"}, + {file = "rapidfuzz-3.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:351df02889ac3da9f3f7b10e6812740927cfab9def453079da94f83697b03f2f"}, + {file = "rapidfuzz-3.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:35506d04429440333224c3711dfdb4195d34eff733cb48648d0c89a9b99faf14"}, + {file = "rapidfuzz-3.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d24054843f4cfbb86df608ec1209e6a29b0d2635230577a94e38a9cfa3880d18"}, + {file = "rapidfuzz-3.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a94fe0a42da816e4a6279ac4c23e4ba6de86a529b61b08d5e8e2633b29c781b"}, + {file = "rapidfuzz-3.0.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:41e98b3cebfa3e720186eeab37e6c0565895edf848fd958c34ab94c39e743311"}, + {file = "rapidfuzz-3.0.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ea5e25378591a698ae5076c582a0135db2cb43270fb2866737ab4cb6fcc34474"}, + {file = "rapidfuzz-3.0.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6bf090b9b4ec4df5f0899bbc4055b8b173b33169186d4de1dd3d9c609bd330a2"}, + {file = "rapidfuzz-3.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f241ca0bcbfcbf90bb48bb1c8dbc1fddc205bee5520f898b994adda3d3f150a"}, + {file = "rapidfuzz-3.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f80986d3c8d55b848d679084231a35273320f658e64f0d86d725bb360e6cd2c4"}, + {file = "rapidfuzz-3.0.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:62c760748b1253e08ab5138855e8f8d2c25a7cb5a0bfad74bb66db63c27d8a50"}, + {file = "rapidfuzz-3.0.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:8b5d78052e840191b9c7556eb3bd4fe52435e58bd979c75298b65262368dd1fa"}, + {file = "rapidfuzz-3.0.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:fc764665ba19b923696eae6912a2f0fc52bdd7db6c53be178d1dd70eb72f2f68"}, + {file = "rapidfuzz-3.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:62aac81ef17bab9f664828b9087d0afe5a94ed48396b0456a2503b68e3d567f2"}, + {file = "rapidfuzz-3.0.0-cp39-cp39-win32.whl", hash = "sha256:aeb855b62bc351884a672b8f87875c552492d9199c78f33cc8650c283fd7504d"}, + {file = "rapidfuzz-3.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:a0e0d8798b7048c9db4e139bafb21792013fb043df07bfaf0d3dc9e1df2be5e6"}, + {file = "rapidfuzz-3.0.0-cp39-cp39-win_arm64.whl", hash = "sha256:ebf96d236a52058c010f354256e8de4274621a7f8b5a15dffa54d9b6a1c7e6e8"}, + {file = "rapidfuzz-3.0.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fbe4b8305cb427b49d70c182a01c91fd85112e0573193a1f9e4fbcec35ea3eff"}, + {file = "rapidfuzz-3.0.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db57085c9dbd0b1005d6ad905c610920c49d0752f522d2f34477b13cba24e1d1"}, + {file = "rapidfuzz-3.0.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e334225a97824d9f75f5cf8e949e129bc183f0762f4c9b7a127d1809461bdc55"}, + {file = "rapidfuzz-3.0.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0c22a36b611a2d53fada2cb03b276135d08c2703039078ce985d7cc42734fd7"}, + {file = "rapidfuzz-3.0.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:05130d9d33c4770116037de9f131e488825165105588cc7143f77733c5b25a6f"}, + {file = "rapidfuzz-3.0.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9c263840bda0f532714ecd66f1f82ed3d3460f45e79e8a907f4df8eaafd93d31"}, + {file = "rapidfuzz-3.0.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6dbaa605c0f81208efbf166afb23f73b0f3847a1a966bec828f4167f61d0ca4b"}, + {file = "rapidfuzz-3.0.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ba129c3c8202e8bef0d9964b8798913905ad1dc6293e94d7a02d87cdbef2544"}, + {file = "rapidfuzz-3.0.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e85b4f4aeb994c841478e98a9e05bcb7ed8ead084d93bd2ca0683dc5e93b1c36"}, + {file = "rapidfuzz-3.0.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:284f216f0500cd977830f107da5c3f96e91356dc7993512efc414dbd55679d51"}, + {file = "rapidfuzz-3.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:494b613a3e730e08df1c7c14e45c303a0f5c8a701162bfc8ac9079585837de43"}, + {file = "rapidfuzz-3.0.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a5670d5475777450fbc70ed8de8d4e3f7c69230a8b539f45bda358a6f9699f2"}, + {file = "rapidfuzz-3.0.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14e9924108a26f2f58aa8cb90f1a106398fa43e359fa5a96b0f328c7bb7f76da"}, + {file = "rapidfuzz-3.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:832d953b5f1462eba5a0830ea7df11b784f090ba5409fc92bccb856d2539b618"}, + {file = "rapidfuzz-3.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5fdcc1ce830bf46fbc098c8b6eb3201a8299476153bae7a5d5e86576f7228d0a"}, + {file = "rapidfuzz-3.0.0.tar.gz", hash = "sha256:4c1d895d16f62e9ac88d303eb918d90a390bd712055c849e01c558b7ae0fa908"}, ] [package.extras] @@ -2234,18 +2107,17 @@ full = ["numpy"] [[package]] name = "redis" -version = "4.5.3" +version = "4.5.5" description = "Python client for Redis database and key-value store" -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "redis-4.5.3-py3-none-any.whl", hash = "sha256:7df17a0a2b72a4c8895b462dd07616c51b1dcb48fdd7ecb7b6f4bf39ecb2e94e"}, - {file = "redis-4.5.3.tar.gz", hash = "sha256:56732e156fe31801c4f43396bd3ca0c2a7f6f83d7936798531b9848d103381aa"}, + {file = "redis-4.5.5-py3-none-any.whl", hash = "sha256:77929bc7f5dab9adf3acba2d3bb7d7658f1e0c2f1cafe7eb36434e751c471119"}, + {file = "redis-4.5.5.tar.gz", hash = "sha256:dc87a0bdef6c8bfe1ef1e1c40be7034390c2ae02d92dcd0c7ca1729443899880"}, ] [package.dependencies] -async-timeout = {version = ">=4.0.2", markers = "python_version < \"3.11\""} +async-timeout = {version = ">=4.0.2", markers = "python_full_version <= \"3.11.2\""} [package.extras] hiredis = ["hiredis (>=1.0.0)"] @@ -2253,91 +2125,117 @@ ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)" [[package]] name = "regex" -version = "2023.3.23" +version = "2023.5.5" description = "Alternative regular expression module, to replace re." -category = "main" optional = false -python-versions = ">=3.8" +python-versions = ">=3.6" files = [ - {file = "regex-2023.3.23-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:845a5e2d84389c4ddada1a9b95c055320070f18bb76512608374aca00d22eca8"}, - {file = "regex-2023.3.23-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:87d9951f5a538dd1d016bdc0dcae59241d15fa94860964833a54d18197fcd134"}, - {file = "regex-2023.3.23-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37ae17d3be44c0b3f782c28ae9edd8b47c1f1776d4cabe87edc0b98e1f12b021"}, - {file = "regex-2023.3.23-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0b8eb1e3bca6b48dc721818a60ae83b8264d4089a4a41d62be6d05316ec38e15"}, - {file = "regex-2023.3.23-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df45fac182ebc3c494460c644e853515cc24f5ad9da05f8ffb91da891bfee879"}, - {file = "regex-2023.3.23-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7006105b10b59971d3b248ad75acc3651c7e4cf54d81694df5a5130a3c3f7ea"}, - {file = "regex-2023.3.23-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93f3f1aa608380fe294aa4cb82e2afda07a7598e828d0341e124b8fd9327c715"}, - {file = "regex-2023.3.23-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:787954f541ab95d8195d97b0b8cf1dc304424adb1e07365967e656b92b38a699"}, - {file = "regex-2023.3.23-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:20abe0bdf03630fe92ccafc45a599bca8b3501f48d1de4f7d121153350a2f77d"}, - {file = "regex-2023.3.23-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:11d00c31aeab9a6e0503bc77e73ed9f4527b3984279d997eb145d7c7be6268fd"}, - {file = "regex-2023.3.23-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:d5bbe0e1511b844794a3be43d6c145001626ba9a6c1db8f84bdc724e91131d9d"}, - {file = "regex-2023.3.23-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ea3c0cb56eadbf4ab2277e7a095676370b3e46dbfc74d5c383bd87b0d6317910"}, - {file = "regex-2023.3.23-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d895b4c863059a4934d3e874b90998df774644a41b349ebb330f85f11b4ef2c0"}, - {file = "regex-2023.3.23-cp310-cp310-win32.whl", hash = "sha256:9d764514d19b4edcc75fd8cb1423448ef393e8b6cbd94f38cab983ab1b75855d"}, - {file = "regex-2023.3.23-cp310-cp310-win_amd64.whl", hash = "sha256:11d1f2b7a0696dc0310de0efb51b1f4d813ad4401fe368e83c0c62f344429f98"}, - {file = "regex-2023.3.23-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8a9c63cde0eaa345795c0fdeb19dc62d22e378c50b0bc67bf4667cd5b482d98b"}, - {file = "regex-2023.3.23-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dd7200b4c27b68cf9c9646da01647141c6db09f48cc5b51bc588deaf8e98a797"}, - {file = "regex-2023.3.23-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22720024b90a6ba673a725dcc62e10fb1111b889305d7c6b887ac7466b74bedb"}, - {file = "regex-2023.3.23-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b190a339090e6af25f4a5fd9e77591f6d911cc7b96ecbb2114890b061be0ac1"}, - {file = "regex-2023.3.23-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e76b6fc0d8e9efa39100369a9b3379ce35e20f6c75365653cf58d282ad290f6f"}, - {file = "regex-2023.3.23-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7868b8f218bf69a2a15402fde08b08712213a1f4b85a156d90473a6fb6b12b09"}, - {file = "regex-2023.3.23-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2472428efc4127374f494e570e36b30bb5e6b37d9a754f7667f7073e43b0abdd"}, - {file = "regex-2023.3.23-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c37df2a060cb476d94c047b18572ee2b37c31f831df126c0da3cd9227b39253d"}, - {file = "regex-2023.3.23-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4479f9e2abc03362df4045b1332d4a2b7885b245a30d4f4b051c4083b97d95d8"}, - {file = "regex-2023.3.23-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e2396e0678167f2d0c197da942b0b3fb48fee2f0b5915a0feb84d11b6686afe6"}, - {file = "regex-2023.3.23-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:75f288c60232a5339e0ff2fa05779a5e9c74e9fc085c81e931d4a264501e745b"}, - {file = "regex-2023.3.23-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c869260aa62cee21c5eb171a466c0572b5e809213612ef8d495268cd2e34f20d"}, - {file = "regex-2023.3.23-cp311-cp311-win32.whl", hash = "sha256:25f0532fd0c53e96bad84664171969de9673b4131f2297f1db850d3918d58858"}, - {file = "regex-2023.3.23-cp311-cp311-win_amd64.whl", hash = "sha256:5ccfafd98473e007cebf7da10c1411035b7844f0f204015efd050601906dbb53"}, - {file = "regex-2023.3.23-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6572ff287176c0fb96568adb292674b421fa762153ed074d94b1d939ed92c253"}, - {file = "regex-2023.3.23-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a610e0adfcb0fc84ea25f6ea685e39e74cbcd9245a72a9a7aab85ff755a5ed27"}, - {file = "regex-2023.3.23-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086afe222d58b88b62847bdbd92079b4699350b4acab892f88a935db5707c790"}, - {file = "regex-2023.3.23-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79e29fd62fa2f597a6754b247356bda14b866131a22444d67f907d6d341e10f3"}, - {file = "regex-2023.3.23-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c07ce8e9eee878a48ebeb32ee661b49504b85e164b05bebf25420705709fdd31"}, - {file = "regex-2023.3.23-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86b036f401895e854de9fefe061518e78d506d8a919cc250dc3416bca03f6f9a"}, - {file = "regex-2023.3.23-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78ac8dd8e18800bb1f97aad0d73f68916592dddf233b99d2b5cabc562088503a"}, - {file = "regex-2023.3.23-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:539dd010dc35af935b32f248099e38447bbffc10b59c2b542bceead2bed5c325"}, - {file = "regex-2023.3.23-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9bf4a5626f2a0ea006bf81e8963f498a57a47d58907eaa58f4b3e13be68759d8"}, - {file = "regex-2023.3.23-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cf86b4328c204c3f315074a61bc1c06f8a75a8e102359f18ce99fbcbbf1951f0"}, - {file = "regex-2023.3.23-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:2848bf76673c83314068241c8d5b7fa9ad9bed866c979875a0e84039349e8fa7"}, - {file = "regex-2023.3.23-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:c125a02d22c555e68f7433bac8449992fa1cead525399f14e47c2d98f2f0e467"}, - {file = "regex-2023.3.23-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cd1671e9d5ac05ce6aa86874dd8dfa048824d1dbe73060851b310c6c1a201a96"}, - {file = "regex-2023.3.23-cp38-cp38-win32.whl", hash = "sha256:fffe57312a358be6ec6baeb43d253c36e5790e436b7bf5b7a38df360363e88e9"}, - {file = "regex-2023.3.23-cp38-cp38-win_amd64.whl", hash = "sha256:dbb3f87e15d3dd76996d604af8678316ad2d7d20faa394e92d9394dfd621fd0c"}, - {file = "regex-2023.3.23-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c88e8c226473b5549fe9616980ea7ca09289246cfbdf469241edf4741a620004"}, - {file = "regex-2023.3.23-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6560776ec19c83f3645bbc5db64a7a5816c9d8fb7ed7201c5bcd269323d88072"}, - {file = "regex-2023.3.23-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b1fc2632c01f42e06173d8dd9bb2e74ab9b0afa1d698058c867288d2c7a31f3"}, - {file = "regex-2023.3.23-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fdf7ad455f1916b8ea5cdbc482d379f6daf93f3867b4232d14699867a5a13af7"}, - {file = "regex-2023.3.23-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5fc33b27b1d800fc5b78d7f7d0f287e35079ecabe68e83d46930cf45690e1c8c"}, - {file = "regex-2023.3.23-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c49552dc938e3588f63f8a78c86f3c9c75301e813bca0bef13bdb4b87ccf364"}, - {file = "regex-2023.3.23-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e152461e9a0aedec7d37fc66ec0fa635eca984777d3d3c3e36f53bf3d3ceb16e"}, - {file = "regex-2023.3.23-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:db034255e72d2995cf581b14bb3fc9c00bdbe6822b49fcd4eef79e1d5f232618"}, - {file = "regex-2023.3.23-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:55ae114da21b7a790b90255ea52d2aa3a0d121a646deb2d3c6a3194e722fc762"}, - {file = "regex-2023.3.23-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ef3f528fe1cc3d139508fe1b22523745aa77b9d6cb5b0bf277f48788ee0b993f"}, - {file = "regex-2023.3.23-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:a81c9ec59ca2303acd1ccd7b9ac409f1e478e40e96f8f79b943be476c5fdb8bb"}, - {file = "regex-2023.3.23-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:cde09c4fdd070772aa2596d97e942eb775a478b32459e042e1be71b739d08b77"}, - {file = "regex-2023.3.23-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3cd9f5dd7b821f141d3a6ca0d5d9359b9221e4f051ca3139320adea9f1679691"}, - {file = "regex-2023.3.23-cp39-cp39-win32.whl", hash = "sha256:7304863f3a652dab5e68e6fb1725d05ebab36ec0390676d1736e0571ebb713ef"}, - {file = "regex-2023.3.23-cp39-cp39-win_amd64.whl", hash = "sha256:54c3fa855a3f7438149de3211738dd9b5f0c733f48b54ae05aa7fce83d48d858"}, - {file = "regex-2023.3.23.tar.gz", hash = "sha256:dc80df325b43ffea5cdea2e3eaa97a44f3dd298262b1c7fe9dbb2a9522b956a7"}, + {file = "regex-2023.5.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:48c9ec56579d4ba1c88f42302194b8ae2350265cb60c64b7b9a88dcb7fbde309"}, + {file = "regex-2023.5.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02f4541550459c08fdd6f97aa4e24c6f1932eec780d58a2faa2068253df7d6ff"}, + {file = "regex-2023.5.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53e22e4460f0245b468ee645156a4f84d0fc35a12d9ba79bd7d79bdcd2f9629d"}, + {file = "regex-2023.5.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4b870b6f632fc74941cadc2a0f3064ed8409e6f8ee226cdfd2a85ae50473aa94"}, + {file = "regex-2023.5.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:171c52e320fe29260da550d81c6b99f6f8402450dc7777ef5ced2e848f3b6f8f"}, + {file = "regex-2023.5.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aad5524c2aedaf9aa14ef1bc9327f8abd915699dea457d339bebbe2f0d218f86"}, + {file = "regex-2023.5.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a0f874ee8c0bc820e649c900243c6d1e6dc435b81da1492046716f14f1a2a96"}, + {file = "regex-2023.5.5-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e645c757183ee0e13f0bbe56508598e2d9cd42b8abc6c0599d53b0d0b8dd1479"}, + {file = "regex-2023.5.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a4c5da39bca4f7979eefcbb36efea04471cd68db2d38fcbb4ee2c6d440699833"}, + {file = "regex-2023.5.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5e3f4468b8c6fd2fd33c218bbd0a1559e6a6fcf185af8bb0cc43f3b5bfb7d636"}, + {file = "regex-2023.5.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:59e4b729eae1a0919f9e4c0fc635fbcc9db59c74ad98d684f4877be3d2607dd6"}, + {file = "regex-2023.5.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ba73a14e9c8f9ac409863543cde3290dba39098fc261f717dc337ea72d3ebad2"}, + {file = "regex-2023.5.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0bbd5dcb19603ab8d2781fac60114fb89aee8494f4505ae7ad141a3314abb1f9"}, + {file = "regex-2023.5.5-cp310-cp310-win32.whl", hash = "sha256:40005cbd383438aecf715a7b47fe1e3dcbc889a36461ed416bdec07e0ef1db66"}, + {file = "regex-2023.5.5-cp310-cp310-win_amd64.whl", hash = "sha256:59597cd6315d3439ed4b074febe84a439c33928dd34396941b4d377692eca810"}, + {file = "regex-2023.5.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8f08276466fedb9e36e5193a96cb944928301152879ec20c2d723d1031cd4ddd"}, + {file = "regex-2023.5.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cd46f30e758629c3ee91713529cfbe107ac50d27110fdcc326a42ce2acf4dafc"}, + {file = "regex-2023.5.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2910502f718828cecc8beff004917dcf577fc5f8f5dd40ffb1ea7612124547b"}, + {file = "regex-2023.5.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:445d6f4fc3bd9fc2bf0416164454f90acab8858cd5a041403d7a11e3356980e8"}, + {file = "regex-2023.5.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18196c16a584619c7c1d843497c069955d7629ad4a3fdee240eb347f4a2c9dbe"}, + {file = "regex-2023.5.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33d430a23b661629661f1fe8395be2004006bc792bb9fc7c53911d661b69dd7e"}, + {file = "regex-2023.5.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72a28979cc667e5f82ef433db009184e7ac277844eea0f7f4d254b789517941d"}, + {file = "regex-2023.5.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f764e4dfafa288e2eba21231f455d209f4709436baeebb05bdecfb5d8ddc3d35"}, + {file = "regex-2023.5.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:23d86ad2121b3c4fc78c58f95e19173790e22ac05996df69b84e12da5816cb17"}, + {file = "regex-2023.5.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:690a17db524ee6ac4a27efc5406530dd90e7a7a69d8360235323d0e5dafb8f5b"}, + {file = "regex-2023.5.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:1ecf3dcff71f0c0fe3e555201cbe749fa66aae8d18f80d2cc4de8e66df37390a"}, + {file = "regex-2023.5.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:811040d7f3dd9c55eb0d8b00b5dcb7fd9ae1761c454f444fd9f37fe5ec57143a"}, + {file = "regex-2023.5.5-cp311-cp311-win32.whl", hash = "sha256:c8c143a65ce3ca42e54d8e6fcaf465b6b672ed1c6c90022794a802fb93105d22"}, + {file = "regex-2023.5.5-cp311-cp311-win_amd64.whl", hash = "sha256:586a011f77f8a2da4b888774174cd266e69e917a67ba072c7fc0e91878178a80"}, + {file = "regex-2023.5.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b6365703e8cf1644b82104cdd05270d1a9f043119a168d66c55684b1b557d008"}, + {file = "regex-2023.5.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a56c18f21ac98209da9c54ae3ebb3b6f6e772038681d6cb43b8d53da3b09ee81"}, + {file = "regex-2023.5.5-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8b942d8b3ce765dbc3b1dad0a944712a89b5de290ce8f72681e22b3c55f3cc8"}, + {file = "regex-2023.5.5-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:844671c9c1150fcdac46d43198364034b961bd520f2c4fdaabfc7c7d7138a2dd"}, + {file = "regex-2023.5.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2ce65bdeaf0a386bb3b533a28de3994e8e13b464ac15e1e67e4603dd88787fa"}, + {file = "regex-2023.5.5-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fee0016cc35a8a91e8cc9312ab26a6fe638d484131a7afa79e1ce6165328a135"}, + {file = "regex-2023.5.5-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:18f05d14f14a812fe9723f13afafefe6b74ca042d99f8884e62dbd34dcccf3e2"}, + {file = "regex-2023.5.5-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:941b3f1b2392f0bcd6abf1bc7a322787d6db4e7457be6d1ffd3a693426a755f2"}, + {file = "regex-2023.5.5-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:921473a93bcea4d00295799ab929522fc650e85c6b9f27ae1e6bb32a790ea7d3"}, + {file = "regex-2023.5.5-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:e2205a81f815b5bb17e46e74cc946c575b484e5f0acfcb805fb252d67e22938d"}, + {file = "regex-2023.5.5-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:385992d5ecf1a93cb85adff2f73e0402dd9ac29b71b7006d342cc920816e6f32"}, + {file = "regex-2023.5.5-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:890a09cb0a62198bff92eda98b2b507305dd3abf974778bae3287f98b48907d3"}, + {file = "regex-2023.5.5-cp36-cp36m-win32.whl", hash = "sha256:821a88b878b6589c5068f4cc2cfeb2c64e343a196bc9d7ac68ea8c2a776acd46"}, + {file = "regex-2023.5.5-cp36-cp36m-win_amd64.whl", hash = "sha256:7918a1b83dd70dc04ab5ed24c78ae833ae8ea228cef84e08597c408286edc926"}, + {file = "regex-2023.5.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:338994d3d4ca4cf12f09822e025731a5bdd3a37aaa571fa52659e85ca793fb67"}, + {file = "regex-2023.5.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a69cf0c00c4d4a929c6c7717fd918414cab0d6132a49a6d8fc3ded1988ed2ea"}, + {file = "regex-2023.5.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f5e06df94fff8c4c85f98c6487f6636848e1dc85ce17ab7d1931df4a081f657"}, + {file = "regex-2023.5.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8906669b03c63266b6a7693d1f487b02647beb12adea20f8840c1a087e2dfb5"}, + {file = "regex-2023.5.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fda3e50abad8d0f48df621cf75adc73c63f7243cbe0e3b2171392b445401550"}, + {file = "regex-2023.5.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ac2b7d341dc1bd102be849d6dd33b09701223a851105b2754339e390be0627a"}, + {file = "regex-2023.5.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fb2b495dd94b02de8215625948132cc2ea360ae84fe6634cd19b6567709c8ae2"}, + {file = "regex-2023.5.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:aa7d032c1d84726aa9edeb6accf079b4caa87151ca9fabacef31fa028186c66d"}, + {file = "regex-2023.5.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:3d45864693351c15531f7e76f545ec35000d50848daa833cead96edae1665559"}, + {file = "regex-2023.5.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:21e90a288e6ba4bf44c25c6a946cb9b0f00b73044d74308b5e0afd190338297c"}, + {file = "regex-2023.5.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:10250a093741ec7bf74bcd2039e697f519b028518f605ff2aa7ac1e9c9f97423"}, + {file = "regex-2023.5.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6b8d0c153f07a953636b9cdb3011b733cadd4178123ef728ccc4d5969e67f3c2"}, + {file = "regex-2023.5.5-cp37-cp37m-win32.whl", hash = "sha256:10374c84ee58c44575b667310d5bbfa89fb2e64e52349720a0182c0017512f6c"}, + {file = "regex-2023.5.5-cp37-cp37m-win_amd64.whl", hash = "sha256:9b320677521aabf666cdd6e99baee4fb5ac3996349c3b7f8e7c4eee1c00dfe3a"}, + {file = "regex-2023.5.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:afb1c70ec1e594a547f38ad6bf5e3d60304ce7539e677c1429eebab115bce56e"}, + {file = "regex-2023.5.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cf123225945aa58b3057d0fba67e8061c62d14cc8a4202630f8057df70189051"}, + {file = "regex-2023.5.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a99757ad7fe5c8a2bb44829fc57ced11253e10f462233c1255fe03888e06bc19"}, + {file = "regex-2023.5.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a623564d810e7a953ff1357f7799c14bc9beeab699aacc8b7ab7822da1e952b8"}, + {file = "regex-2023.5.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ced02e3bd55e16e89c08bbc8128cff0884d96e7f7a5633d3dc366b6d95fcd1d6"}, + {file = "regex-2023.5.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1cbe6b5be3b9b698d8cc4ee4dee7e017ad655e83361cd0ea8e653d65e469468"}, + {file = "regex-2023.5.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a6e4b0e0531223f53bad07ddf733af490ba2b8367f62342b92b39b29f72735a"}, + {file = "regex-2023.5.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2e9c4f778514a560a9c9aa8e5538bee759b55f6c1dcd35613ad72523fd9175b8"}, + {file = "regex-2023.5.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:256f7f4c6ba145f62f7a441a003c94b8b1af78cee2cccacfc1e835f93bc09426"}, + {file = "regex-2023.5.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:bd7b68fd2e79d59d86dcbc1ccd6e2ca09c505343445daaa4e07f43c8a9cc34da"}, + {file = "regex-2023.5.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4a5059bd585e9e9504ef9c07e4bc15b0a621ba20504388875d66b8b30a5c4d18"}, + {file = "regex-2023.5.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:6893544e06bae009916a5658ce7207e26ed17385149f35a3125f5259951f1bbe"}, + {file = "regex-2023.5.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c64d5abe91a3dfe5ff250c6bb267ef00dbc01501518225b45a5f9def458f31fb"}, + {file = "regex-2023.5.5-cp38-cp38-win32.whl", hash = "sha256:7923470d6056a9590247ff729c05e8e0f06bbd4efa6569c916943cb2d9b68b91"}, + {file = "regex-2023.5.5-cp38-cp38-win_amd64.whl", hash = "sha256:4035d6945cb961c90c3e1c1ca2feb526175bcfed44dfb1cc77db4fdced060d3e"}, + {file = "regex-2023.5.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:50fd2d9b36938d4dcecbd684777dd12a407add4f9f934f235c66372e630772b0"}, + {file = "regex-2023.5.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d19e57f888b00cd04fc38f5e18d0efbd91ccba2d45039453ab2236e6eec48d4d"}, + {file = "regex-2023.5.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd966475e963122ee0a7118ec9024388c602d12ac72860f6eea119a3928be053"}, + {file = "regex-2023.5.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db09e6c18977a33fea26fe67b7a842f706c67cf8bda1450974d0ae0dd63570df"}, + {file = "regex-2023.5.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6164d4e2a82f9ebd7752a06bd6c504791bedc6418c0196cd0a23afb7f3e12b2d"}, + {file = "regex-2023.5.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84397d3f750d153ebd7f958efaa92b45fea170200e2df5e0e1fd4d85b7e3f58a"}, + {file = "regex-2023.5.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9c3efee9bb53cbe7b285760c81f28ac80dc15fa48b5fe7e58b52752e642553f1"}, + {file = "regex-2023.5.5-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:144b5b017646b5a9392a5554a1e5db0000ae637be4971c9747566775fc96e1b2"}, + {file = "regex-2023.5.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1189fbbb21e2c117fda5303653b61905aeeeea23de4a94d400b0487eb16d2d60"}, + {file = "regex-2023.5.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f83fe9e10f9d0b6cf580564d4d23845b9d692e4c91bd8be57733958e4c602956"}, + {file = "regex-2023.5.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:72aa4746993a28c841e05889f3f1b1e5d14df8d3daa157d6001a34c98102b393"}, + {file = "regex-2023.5.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:de2f780c3242ea114dd01f84848655356af4dd561501896c751d7b885ea6d3a1"}, + {file = "regex-2023.5.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:290fd35219486dfbc00b0de72f455ecdd63e59b528991a6aec9fdfc0ce85672e"}, + {file = "regex-2023.5.5-cp39-cp39-win32.whl", hash = "sha256:732176f5427e72fa2325b05c58ad0b45af341c459910d766f814b0584ac1f9ac"}, + {file = "regex-2023.5.5-cp39-cp39-win_amd64.whl", hash = "sha256:1307aa4daa1cbb23823d8238e1f61292fd07e4e5d8d38a6efff00b67a7cdb764"}, + {file = "regex-2023.5.5.tar.gz", hash = "sha256:7d76a8a1fc9da08296462a18f16620ba73bcbf5909e42383b253ef34d9d5141e"}, ] [[package]] name = "requests" -version = "2.28.2" +version = "2.31.0" description = "Python HTTP for Humans." -category = "main" optional = false -python-versions = ">=3.7, <4" +python-versions = ">=3.7" files = [ - {file = "requests-2.28.2-py3-none-any.whl", hash = "sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa"}, - {file = "requests-2.28.2.tar.gz", hash = "sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf"}, + {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,<1.27" +urllib3 = ">=1.21.1,<3" [package.extras] socks = ["PySocks (>=1.5.6,!=1.5.7)"] @@ -2347,7 +2245,6 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] name = "requests-oauthlib" version = "1.3.1" description = "OAuthlib authentication support for Requests." -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -2364,14 +2261,13 @@ rsa = ["oauthlib[signedtoken] (>=3.0.0)"] [[package]] name = "requests-toolbelt" -version = "0.10.1" +version = "1.0.0" description = "A utility belt for advanced users of python-requests" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ - {file = "requests-toolbelt-0.10.1.tar.gz", hash = "sha256:62e09f7ff5ccbda92772a29f394a49c3ad6cb181d568b1337626b2abb628a63d"}, - {file = "requests_toolbelt-0.10.1-py2.py3-none-any.whl", hash = "sha256:18565aa58116d9951ac39baa288d3adb5b3ff975c4f25eee78555d89e8f247f7"}, + {file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"}, + {file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"}, ] [package.dependencies] @@ -2381,7 +2277,6 @@ requests = ">=2.0.1,<3.0.0" name = "rich" version = "12.6.0" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" -category = "main" optional = false python-versions = ">=3.6.3,<4.0.0" files = [ @@ -2398,14 +2293,13 @@ jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"] [[package]] name = "setuptools" -version = "67.6.0" +version = "67.7.2" description = "Easily download, build, install, upgrade, and uninstall Python packages" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "setuptools-67.6.0-py3-none-any.whl", hash = "sha256:b78aaa36f6b90a074c1fa651168723acbf45d14cb1196b6f02c0fd07f17623b2"}, - {file = "setuptools-67.6.0.tar.gz", hash = "sha256:2ee892cd5f29f3373097f5a814697e397cf3ce313616df0af11231e2ad118077"}, + {file = "setuptools-67.7.2-py3-none-any.whl", hash = "sha256:23aaf86b85ca52ceb801d32703f12d77517b2556af839621c641fca11287952b"}, + {file = "setuptools-67.7.2.tar.gz", hash = "sha256:f104fa03692a2602fa0fec6c6a9e63b6c8a968de13e17c026957dd1f53d80990"}, ] [package.extras] @@ -2417,7 +2311,6 @@ testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs ( name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -2429,7 +2322,6 @@ files = [ name = "smmap" version = "5.0.0" description = "A pure Python implementation of a sliding window memory map manager" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -2439,21 +2331,19 @@ files = [ [[package]] name = "soupsieve" -version = "2.4" +version = "2.4.1" description = "A modern CSS selector implementation for Beautiful Soup." -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "soupsieve-2.4-py3-none-any.whl", hash = "sha256:49e5368c2cda80ee7e84da9dbe3e110b70a4575f196efb74e51b94549d921955"}, - {file = "soupsieve-2.4.tar.gz", hash = "sha256:e28dba9ca6c7c00173e34e4ba57448f0688bb681b7c5e8bf4971daafc093d69a"}, + {file = "soupsieve-2.4.1-py3-none-any.whl", hash = "sha256:1c1bfee6819544a3447586c889157365a27e10d88cde3ad3da0cf0ddf646feb8"}, + {file = "soupsieve-2.4.1.tar.gz", hash = "sha256:89d12b2d5dfcd2c9e8c22326da9d9aa9cb3dfab0a83a024f05704076ee8d35ea"}, ] [[package]] name = "statipy" version = "0.1.0" description = "" -category = "main" optional = false python-versions = ">=3.10,<4" files = [] @@ -2461,19 +2351,18 @@ develop = false [package.dependencies] beanie = "^1.17.0" -interactions = {git = "https://github.com/interactions-py/interactions.py", rev = "5.x"} +interactions-py = ">=5.3,<6" [package.source] type = "git" url = "https://github.com/zevaryx/statipy" reference = "main" -resolved_reference = "9bc2f910dafd7702d275185a8b96187c6ab1f8fb" +resolved_reference = "d91a9151e6e22045bd4f1cc097824f742fed28b0" [[package]] name = "thefuzz" version = "0.19.0" description = "Fuzzy string matching in python" -category = "main" optional = false python-versions = "*" files = [] @@ -2495,7 +2384,6 @@ resolved_reference = "e4ab69d3d44cc3dd67221cba53e6a614786b0d7c" name = "toml" version = "0.10.2" description = "Python Library for Tom's Obvious, Minimal Language" -category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -2507,7 +2395,6 @@ files = [ name = "tomli" version = "2.0.1" description = "A lil' TOML parser" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2519,7 +2406,6 @@ files = [ name = "tqdm" version = "4.65.0" description = "Fast, Extensible Progress Meter" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2538,14 +2424,13 @@ telegram = ["requests"] [[package]] name = "tweepy" -version = "4.13.0" +version = "4.14.0" description = "Twitter library for Python" -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "tweepy-4.13.0-py3-none-any.whl", hash = "sha256:95207c41023b75a066b0b442a0a907acada610a3cfa09c4ccb5f2d9e522c33b5"}, - {file = "tweepy-4.13.0.tar.gz", hash = "sha256:097425335f9f6674826ba7e72b2247bbca39c9ca0a0bd82f30a38a5bef8c6c88"}, + {file = "tweepy-4.14.0-py3-none-any.whl", hash = "sha256:db6d3844ccc0c6d27f339f12ba8acc89912a961da513c1ae50fa2be502a56afb"}, + {file = "tweepy-4.14.0.tar.gz", hash = "sha256:1f9f1707d6972de6cff6c5fd90dfe6a449cd2e0d70bd40043ffab01e07a06c8c"}, ] [package.dependencies] @@ -2564,7 +2449,6 @@ test = ["vcrpy (>=1.10.3)"] name = "typing-extensions" version = "4.5.0" description = "Backported and Experimental Type Hints for Python 3.7+" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2574,21 +2458,19 @@ files = [ [[package]] name = "tzdata" -version = "2023.2" +version = "2023.3" description = "Provider of IANA time zone data" -category = "main" optional = false python-versions = ">=2" files = [ - {file = "tzdata-2023.2-py2.py3-none-any.whl", hash = "sha256:905ae9e6744dd9ef5ce94d2aaa2dd00282fee38b670b2133407f23c388f110a1"}, - {file = "tzdata-2023.2.tar.gz", hash = "sha256:c3b51b235b07f9f1889089c2264bcbeaaba260a63f89bea09e350ea4205eb95f"}, + {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"}, + {file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"}, ] [[package]] name = "tzlocal" version = "4.3" description = "tzinfo object for the local timezone" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2607,7 +2489,6 @@ devenv = ["black", "check-manifest", "flake8", "pyroma", "pytest (>=4.3)", "pyte name = "ulid-py" version = "1.1.0" description = "Universally Unique Lexicographically Sortable Identifier" -category = "main" optional = false python-versions = "*" files = [ @@ -2615,32 +2496,10 @@ files = [ {file = "ulid_py-1.1.0-py2.py3-none-any.whl", hash = "sha256:b56a0f809ef90d6020b21b89a87a48edc7c03aea80e5ed5174172e82d76e3987"}, ] -[[package]] -name = "umongo" -version = "3.1.0" -description = "sync/async MongoDB ODM, yes." -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "umongo-3.1.0-py2.py3-none-any.whl", hash = "sha256:f6913027651ae673d71aaf54285f9ebf1e49a3f57662e526d029ba72e1a3fcd5"}, - {file = "umongo-3.1.0.tar.gz", hash = "sha256:20c72f09edae931285c22c1928862af35b90ec639a4dac2dbf015aaaac00e931"}, -] - -[package.dependencies] -marshmallow = ">=3.10.0" -pymongo = ">=3.7.0" - -[package.extras] -mongomock = ["mongomock"] -motor = ["motor (>=2.0,<3.0)"] -txmongo = ["txmongo (>=19.2.0)"] - [[package]] name = "update-checker" version = "0.18.0" description = "A python module that will check for package updates." -category = "main" optional = false python-versions = "*" files = [ @@ -2660,7 +2519,6 @@ test = ["pytest (>=2.7.3)"] name = "urllib3" version = "1.26.15" description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ @@ -2675,30 +2533,28 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "virtualenv" -version = "20.21.0" +version = "20.23.0" description = "Virtual Python Environment builder" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.21.0-py3-none-any.whl", hash = "sha256:31712f8f2a17bd06234fa97fdf19609e789dd4e3e4bf108c3da71d710651adbc"}, - {file = "virtualenv-20.21.0.tar.gz", hash = "sha256:f50e3e60f990a0757c9b68333c9fdaa72d7188caa417f96af9e52407831a3b68"}, + {file = "virtualenv-20.23.0-py3-none-any.whl", hash = "sha256:6abec7670e5802a528357fdc75b26b9f57d5d92f29c5462ba0fbe45feacc685e"}, + {file = "virtualenv-20.23.0.tar.gz", hash = "sha256:a85caa554ced0c0afbd0d638e7e2d7b5f92d23478d05d17a76daeac8f279f924"}, ] [package.dependencies] distlib = ">=0.3.6,<1" -filelock = ">=3.4.1,<4" -platformdirs = ">=2.4,<4" +filelock = ">=3.11,<4" +platformdirs = ">=3.2,<4" [package.extras] -docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=22.12)"] -test = ["covdefaults (>=2.2.2)", "coverage (>=7.1)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23)", "pytest (>=7.2.1)", "pytest-env (>=0.8.1)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=22.12)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.3.1)", "pytest-env (>=0.8.1)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=67.7.1)", "time-machine (>=2.9)"] [[package]] name = "watchdog" version = "3.0.0" description = "Filesystem events monitoring" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2738,7 +2594,6 @@ watchmedo = ["PyYAML (>=3.10)"] name = "wcwidth" version = "0.2.6" description = "Measures the displayed width of unicode strings in a terminal" -category = "main" optional = false python-versions = "*" files = [ @@ -2750,7 +2605,6 @@ files = [ name = "websockets" version = "10.4" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2827,86 +2681,85 @@ files = [ [[package]] name = "yarl" -version = "1.8.2" +version = "1.9.2" description = "Yet another URL library" -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "yarl-1.8.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:bb81f753c815f6b8e2ddd2eef3c855cf7da193b82396ac013c661aaa6cc6b0a5"}, - {file = "yarl-1.8.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:47d49ac96156f0928f002e2424299b2c91d9db73e08c4cd6742923a086f1c863"}, - {file = "yarl-1.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3fc056e35fa6fba63248d93ff6e672c096f95f7836938241ebc8260e062832fe"}, - {file = "yarl-1.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58a3c13d1c3005dbbac5c9f0d3210b60220a65a999b1833aa46bd6677c69b08e"}, - {file = "yarl-1.8.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:10b08293cda921157f1e7c2790999d903b3fd28cd5c208cf8826b3b508026996"}, - {file = "yarl-1.8.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:de986979bbd87272fe557e0a8fcb66fd40ae2ddfe28a8b1ce4eae22681728fef"}, - {file = "yarl-1.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c4fcfa71e2c6a3cb568cf81aadc12768b9995323186a10827beccf5fa23d4f8"}, - {file = "yarl-1.8.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae4d7ff1049f36accde9e1ef7301912a751e5bae0a9d142459646114c70ecba6"}, - {file = "yarl-1.8.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bf071f797aec5b96abfc735ab97da9fd8f8768b43ce2abd85356a3127909d146"}, - {file = "yarl-1.8.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:74dece2bfc60f0f70907c34b857ee98f2c6dd0f75185db133770cd67300d505f"}, - {file = "yarl-1.8.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:df60a94d332158b444301c7f569659c926168e4d4aad2cfbf4bce0e8fb8be826"}, - {file = "yarl-1.8.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:63243b21c6e28ec2375f932a10ce7eda65139b5b854c0f6b82ed945ba526bff3"}, - {file = "yarl-1.8.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cfa2bbca929aa742b5084fd4663dd4b87c191c844326fcb21c3afd2d11497f80"}, - {file = "yarl-1.8.2-cp310-cp310-win32.whl", hash = "sha256:b05df9ea7496df11b710081bd90ecc3a3db6adb4fee36f6a411e7bc91a18aa42"}, - {file = "yarl-1.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:24ad1d10c9db1953291f56b5fe76203977f1ed05f82d09ec97acb623a7976574"}, - {file = "yarl-1.8.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2a1fca9588f360036242f379bfea2b8b44cae2721859b1c56d033adfd5893634"}, - {file = "yarl-1.8.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f37db05c6051eff17bc832914fe46869f8849de5b92dc4a3466cd63095d23dfd"}, - {file = "yarl-1.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:77e913b846a6b9c5f767b14dc1e759e5aff05502fe73079f6f4176359d832581"}, - {file = "yarl-1.8.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0978f29222e649c351b173da2b9b4665ad1feb8d1daa9d971eb90df08702668a"}, - {file = "yarl-1.8.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:388a45dc77198b2460eac0aca1efd6a7c09e976ee768b0d5109173e521a19daf"}, - {file = "yarl-1.8.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2305517e332a862ef75be8fad3606ea10108662bc6fe08509d5ca99503ac2aee"}, - {file = "yarl-1.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42430ff511571940d51e75cf42f1e4dbdded477e71c1b7a17f4da76c1da8ea76"}, - {file = "yarl-1.8.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3150078118f62371375e1e69b13b48288e44f6691c1069340081c3fd12c94d5b"}, - {file = "yarl-1.8.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c15163b6125db87c8f53c98baa5e785782078fbd2dbeaa04c6141935eb6dab7a"}, - {file = "yarl-1.8.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4d04acba75c72e6eb90745447d69f84e6c9056390f7a9724605ca9c56b4afcc6"}, - {file = "yarl-1.8.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e7fd20d6576c10306dea2d6a5765f46f0ac5d6f53436217913e952d19237efc4"}, - {file = "yarl-1.8.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:75c16b2a900b3536dfc7014905a128a2bea8fb01f9ee26d2d7d8db0a08e7cb2c"}, - {file = "yarl-1.8.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6d88056a04860a98341a0cf53e950e3ac9f4e51d1b6f61a53b0609df342cc8b2"}, - {file = "yarl-1.8.2-cp311-cp311-win32.whl", hash = "sha256:fb742dcdd5eec9f26b61224c23baea46c9055cf16f62475e11b9b15dfd5c117b"}, - {file = "yarl-1.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:8c46d3d89902c393a1d1e243ac847e0442d0196bbd81aecc94fcebbc2fd5857c"}, - {file = "yarl-1.8.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:ceff9722e0df2e0a9e8a79c610842004fa54e5b309fe6d218e47cd52f791d7ef"}, - {file = "yarl-1.8.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f6b4aca43b602ba0f1459de647af954769919c4714706be36af670a5f44c9c1"}, - {file = "yarl-1.8.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1684a9bd9077e922300ecd48003ddae7a7474e0412bea38d4631443a91d61077"}, - {file = "yarl-1.8.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ebb78745273e51b9832ef90c0898501006670d6e059f2cdb0e999494eb1450c2"}, - {file = "yarl-1.8.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3adeef150d528ded2a8e734ebf9ae2e658f4c49bf413f5f157a470e17a4a2e89"}, - {file = "yarl-1.8.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57a7c87927a468e5a1dc60c17caf9597161d66457a34273ab1760219953f7f4c"}, - {file = "yarl-1.8.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:efff27bd8cbe1f9bd127e7894942ccc20c857aa8b5a0327874f30201e5ce83d0"}, - {file = "yarl-1.8.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a783cd344113cb88c5ff7ca32f1f16532a6f2142185147822187913eb989f739"}, - {file = "yarl-1.8.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:705227dccbe96ab02c7cb2c43e1228e2826e7ead880bb19ec94ef279e9555b5b"}, - {file = "yarl-1.8.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:34c09b43bd538bf6c4b891ecce94b6fa4f1f10663a8d4ca589a079a5018f6ed7"}, - {file = "yarl-1.8.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a48f4f7fea9a51098b02209d90297ac324241bf37ff6be6d2b0149ab2bd51b37"}, - {file = "yarl-1.8.2-cp37-cp37m-win32.whl", hash = "sha256:0414fd91ce0b763d4eadb4456795b307a71524dbacd015c657bb2a39db2eab89"}, - {file = "yarl-1.8.2-cp37-cp37m-win_amd64.whl", hash = "sha256:d881d152ae0007809c2c02e22aa534e702f12071e6b285e90945aa3c376463c5"}, - {file = "yarl-1.8.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5df5e3d04101c1e5c3b1d69710b0574171cc02fddc4b23d1b2813e75f35a30b1"}, - {file = "yarl-1.8.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7a66c506ec67eb3159eea5096acd05f5e788ceec7b96087d30c7d2865a243918"}, - {file = "yarl-1.8.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2b4fa2606adf392051d990c3b3877d768771adc3faf2e117b9de7eb977741229"}, - {file = "yarl-1.8.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e21fb44e1eff06dd6ef971d4bdc611807d6bd3691223d9c01a18cec3677939e"}, - {file = "yarl-1.8.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:93202666046d9edadfe9f2e7bf5e0782ea0d497b6d63da322e541665d65a044e"}, - {file = "yarl-1.8.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fc77086ce244453e074e445104f0ecb27530d6fd3a46698e33f6c38951d5a0f1"}, - {file = "yarl-1.8.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dd68a92cab699a233641f5929a40f02a4ede8c009068ca8aa1fe87b8c20ae3"}, - {file = "yarl-1.8.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1b372aad2b5f81db66ee7ec085cbad72c4da660d994e8e590c997e9b01e44901"}, - {file = "yarl-1.8.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e6f3515aafe0209dd17fb9bdd3b4e892963370b3de781f53e1746a521fb39fc0"}, - {file = "yarl-1.8.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:dfef7350ee369197106805e193d420b75467b6cceac646ea5ed3049fcc950a05"}, - {file = "yarl-1.8.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:728be34f70a190566d20aa13dc1f01dc44b6aa74580e10a3fb159691bc76909d"}, - {file = "yarl-1.8.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:ff205b58dc2929191f68162633d5e10e8044398d7a45265f90a0f1d51f85f72c"}, - {file = "yarl-1.8.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:baf211dcad448a87a0d9047dc8282d7de59473ade7d7fdf22150b1d23859f946"}, - {file = "yarl-1.8.2-cp38-cp38-win32.whl", hash = "sha256:272b4f1599f1b621bf2aabe4e5b54f39a933971f4e7c9aa311d6d7dc06965165"}, - {file = "yarl-1.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:326dd1d3caf910cd26a26ccbfb84c03b608ba32499b5d6eeb09252c920bcbe4f"}, - {file = "yarl-1.8.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f8ca8ad414c85bbc50f49c0a106f951613dfa5f948ab69c10ce9b128d368baf8"}, - {file = "yarl-1.8.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:418857f837347e8aaef682679f41e36c24250097f9e2f315d39bae3a99a34cbf"}, - {file = "yarl-1.8.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ae0eec05ab49e91a78700761777f284c2df119376e391db42c38ab46fd662b77"}, - {file = "yarl-1.8.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:009a028127e0a1755c38b03244c0bea9d5565630db9c4cf9572496e947137a87"}, - {file = "yarl-1.8.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3edac5d74bb3209c418805bda77f973117836e1de7c000e9755e572c1f7850d0"}, - {file = "yarl-1.8.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da65c3f263729e47351261351b8679c6429151ef9649bba08ef2528ff2c423b2"}, - {file = "yarl-1.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ef8fb25e52663a1c85d608f6dd72e19bd390e2ecaf29c17fb08f730226e3a08"}, - {file = "yarl-1.8.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bcd7bb1e5c45274af9a1dd7494d3c52b2be5e6bd8d7e49c612705fd45420b12d"}, - {file = "yarl-1.8.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:44ceac0450e648de86da8e42674f9b7077d763ea80c8ceb9d1c3e41f0f0a9951"}, - {file = "yarl-1.8.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:97209cc91189b48e7cfe777237c04af8e7cc51eb369004e061809bcdf4e55220"}, - {file = "yarl-1.8.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:48dd18adcf98ea9cd721a25313aef49d70d413a999d7d89df44f469edfb38a06"}, - {file = "yarl-1.8.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e59399dda559688461762800d7fb34d9e8a6a7444fd76ec33220a926c8be1516"}, - {file = "yarl-1.8.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d617c241c8c3ad5c4e78a08429fa49e4b04bedfc507b34b4d8dceb83b4af3588"}, - {file = "yarl-1.8.2-cp39-cp39-win32.whl", hash = "sha256:cb6d48d80a41f68de41212f3dfd1a9d9898d7841c8f7ce6696cf2fd9cb57ef83"}, - {file = "yarl-1.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:6604711362f2dbf7160df21c416f81fac0de6dbcf0b5445a2ef25478ecc4c778"}, - {file = "yarl-1.8.2.tar.gz", hash = "sha256:49d43402c6e3013ad0978602bf6bf5328535c48d192304b91b97a3c6790b1562"}, + {file = "yarl-1.9.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8c2ad583743d16ddbdf6bb14b5cd76bf43b0d0006e918809d5d4ddf7bde8dd82"}, + {file = "yarl-1.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:82aa6264b36c50acfb2424ad5ca537a2060ab6de158a5bd2a72a032cc75b9eb8"}, + {file = "yarl-1.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c0c77533b5ed4bcc38e943178ccae29b9bcf48ffd1063f5821192f23a1bd27b9"}, + {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee4afac41415d52d53a9833ebae7e32b344be72835bbb589018c9e938045a560"}, + {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9bf345c3a4f5ba7f766430f97f9cc1320786f19584acc7086491f45524a551ac"}, + {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a96c19c52ff442a808c105901d0bdfd2e28575b3d5f82e2f5fd67e20dc5f4ea"}, + {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:891c0e3ec5ec881541f6c5113d8df0315ce5440e244a716b95f2525b7b9f3608"}, + {file = "yarl-1.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c3a53ba34a636a256d767c086ceb111358876e1fb6b50dfc4d3f4951d40133d5"}, + {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:566185e8ebc0898b11f8026447eacd02e46226716229cea8db37496c8cdd26e0"}, + {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2b0738fb871812722a0ac2154be1f049c6223b9f6f22eec352996b69775b36d4"}, + {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:32f1d071b3f362c80f1a7d322bfd7b2d11e33d2adf395cc1dd4df36c9c243095"}, + {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:e9fdc7ac0d42bc3ea78818557fab03af6181e076a2944f43c38684b4b6bed8e3"}, + {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:56ff08ab5df8429901ebdc5d15941b59f6253393cb5da07b4170beefcf1b2528"}, + {file = "yarl-1.9.2-cp310-cp310-win32.whl", hash = "sha256:8ea48e0a2f931064469bdabca50c2f578b565fc446f302a79ba6cc0ee7f384d3"}, + {file = "yarl-1.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:50f33040f3836e912ed16d212f6cc1efb3231a8a60526a407aeb66c1c1956dde"}, + {file = "yarl-1.9.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:646d663eb2232d7909e6601f1a9107e66f9791f290a1b3dc7057818fe44fc2b6"}, + {file = "yarl-1.9.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aff634b15beff8902d1f918012fc2a42e0dbae6f469fce134c8a0dc51ca423bb"}, + {file = "yarl-1.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a83503934c6273806aed765035716216cc9ab4e0364f7f066227e1aaea90b8d0"}, + {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b25322201585c69abc7b0e89e72790469f7dad90d26754717f3310bfe30331c2"}, + {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22a94666751778629f1ec4280b08eb11815783c63f52092a5953faf73be24191"}, + {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ec53a0ea2a80c5cd1ab397925f94bff59222aa3cf9c6da938ce05c9ec20428d"}, + {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:159d81f22d7a43e6eabc36d7194cb53f2f15f498dbbfa8edc8a3239350f59fe7"}, + {file = "yarl-1.9.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:832b7e711027c114d79dffb92576acd1bd2decc467dec60e1cac96912602d0e6"}, + {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:95d2ecefbcf4e744ea952d073c6922e72ee650ffc79028eb1e320e732898d7e8"}, + {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d4e2c6d555e77b37288eaf45b8f60f0737c9efa3452c6c44626a5455aeb250b9"}, + {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:783185c75c12a017cc345015ea359cc801c3b29a2966c2655cd12b233bf5a2be"}, + {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:b8cc1863402472f16c600e3e93d542b7e7542a540f95c30afd472e8e549fc3f7"}, + {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:822b30a0f22e588b32d3120f6d41e4ed021806418b4c9f0bc3048b8c8cb3f92a"}, + {file = "yarl-1.9.2-cp311-cp311-win32.whl", hash = "sha256:a60347f234c2212a9f0361955007fcf4033a75bf600a33c88a0a8e91af77c0e8"}, + {file = "yarl-1.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:be6b3fdec5c62f2a67cb3f8c6dbf56bbf3f61c0f046f84645cd1ca73532ea051"}, + {file = "yarl-1.9.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:38a3928ae37558bc1b559f67410df446d1fbfa87318b124bf5032c31e3447b74"}, + {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac9bb4c5ce3975aeac288cfcb5061ce60e0d14d92209e780c93954076c7c4367"}, + {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3da8a678ca8b96c8606bbb8bfacd99a12ad5dd288bc6f7979baddd62f71c63ef"}, + {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:13414591ff516e04fcdee8dc051c13fd3db13b673c7a4cb1350e6b2ad9639ad3"}, + {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf74d08542c3a9ea97bb8f343d4fcbd4d8f91bba5ec9d5d7f792dbe727f88938"}, + {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e7221580dc1db478464cfeef9b03b95c5852cc22894e418562997df0d074ccc"}, + {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:494053246b119b041960ddcd20fd76224149cfea8ed8777b687358727911dd33"}, + {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:52a25809fcbecfc63ac9ba0c0fb586f90837f5425edfd1ec9f3372b119585e45"}, + {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:e65610c5792870d45d7b68c677681376fcf9cc1c289f23e8e8b39c1485384185"}, + {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:1b1bba902cba32cdec51fca038fd53f8beee88b77efc373968d1ed021024cc04"}, + {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:662e6016409828ee910f5d9602a2729a8a57d74b163c89a837de3fea050c7582"}, + {file = "yarl-1.9.2-cp37-cp37m-win32.whl", hash = "sha256:f364d3480bffd3aa566e886587eaca7c8c04d74f6e8933f3f2c996b7f09bee1b"}, + {file = "yarl-1.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6a5883464143ab3ae9ba68daae8e7c5c95b969462bbe42e2464d60e7e2698368"}, + {file = "yarl-1.9.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5610f80cf43b6202e2c33ba3ec2ee0a2884f8f423c8f4f62906731d876ef4fac"}, + {file = "yarl-1.9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b9a4e67ad7b646cd6f0938c7ebfd60e481b7410f574c560e455e938d2da8e0f4"}, + {file = "yarl-1.9.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:83fcc480d7549ccebe9415d96d9263e2d4226798c37ebd18c930fce43dfb9574"}, + {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fcd436ea16fee7d4207c045b1e340020e58a2597301cfbcfdbe5abd2356c2fb"}, + {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84e0b1599334b1e1478db01b756e55937d4614f8654311eb26012091be109d59"}, + {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3458a24e4ea3fd8930e934c129b676c27452e4ebda80fbe47b56d8c6c7a63a9e"}, + {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:838162460b3a08987546e881a2bfa573960bb559dfa739e7800ceeec92e64417"}, + {file = "yarl-1.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f4e2d08f07a3d7d3e12549052eb5ad3eab1c349c53ac51c209a0e5991bbada78"}, + {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:de119f56f3c5f0e2fb4dee508531a32b069a5f2c6e827b272d1e0ff5ac040333"}, + {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:149ddea5abf329752ea5051b61bd6c1d979e13fbf122d3a1f9f0c8be6cb6f63c"}, + {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:674ca19cbee4a82c9f54e0d1eee28116e63bc6fd1e96c43031d11cbab8b2afd5"}, + {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:9b3152f2f5677b997ae6c804b73da05a39daa6a9e85a512e0e6823d81cdad7cc"}, + {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5415d5a4b080dc9612b1b63cba008db84e908b95848369aa1da3686ae27b6d2b"}, + {file = "yarl-1.9.2-cp38-cp38-win32.whl", hash = "sha256:f7a3d8146575e08c29ed1cd287068e6d02f1c7bdff8970db96683b9591b86ee7"}, + {file = "yarl-1.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:63c48f6cef34e6319a74c727376e95626f84ea091f92c0250a98e53e62c77c72"}, + {file = "yarl-1.9.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:75df5ef94c3fdc393c6b19d80e6ef1ecc9ae2f4263c09cacb178d871c02a5ba9"}, + {file = "yarl-1.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c027a6e96ef77d401d8d5a5c8d6bc478e8042f1e448272e8d9752cb0aff8b5c8"}, + {file = "yarl-1.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3b078dbe227f79be488ffcfc7a9edb3409d018e0952cf13f15fd6512847f3f7"}, + {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59723a029760079b7d991a401386390c4be5bfec1e7dd83e25a6a0881859e716"}, + {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b03917871bf859a81ccb180c9a2e6c1e04d2f6a51d953e6a5cdd70c93d4e5a2a"}, + {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c1012fa63eb6c032f3ce5d2171c267992ae0c00b9e164efe4d73db818465fac3"}, + {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a74dcbfe780e62f4b5a062714576f16c2f3493a0394e555ab141bf0d746bb955"}, + {file = "yarl-1.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8c56986609b057b4839968ba901944af91b8e92f1725d1a2d77cbac6972b9ed1"}, + {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2c315df3293cd521033533d242d15eab26583360b58f7ee5d9565f15fee1bef4"}, + {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:b7232f8dfbd225d57340e441d8caf8652a6acd06b389ea2d3222b8bc89cbfca6"}, + {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:53338749febd28935d55b41bf0bcc79d634881195a39f6b2f767870b72514caf"}, + {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:066c163aec9d3d073dc9ffe5dd3ad05069bcb03fcaab8d221290ba99f9f69ee3"}, + {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8288d7cd28f8119b07dd49b7230d6b4562f9b61ee9a4ab02221060d21136be80"}, + {file = "yarl-1.9.2-cp39-cp39-win32.whl", hash = "sha256:b124e2a6d223b65ba8768d5706d103280914d61f5cae3afbc50fc3dfcc016623"}, + {file = "yarl-1.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:61016e7d582bc46a5378ffdd02cd0314fb8ba52f40f9cf4d9a5e7dbef88dee18"}, + {file = "yarl-1.9.2.tar.gz", hash = "sha256:04ab9d4b9f587c06d801c2abfe9317b77cdf996c65a90d5e84ecc45010823571"}, ] [package.dependencies] @@ -2917,7 +2770,6 @@ multidict = ">=4.0" name = "zipp" version = "3.15.0" description = "Backport of pathlib-compatible object wrapper for zip files" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2931,5 +2783,5 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" -python-versions = ">=3.10,<4" -content-hash = "7d444e8d9981e9afc498cdc5d3847de847a8bbfc4de2b1cd73940f0ac7319060" +python-versions = ">=3.11,<4" +content-hash = "a98a0513e04d91f34a3dd9749f3ce939c9044d9953a5d38eec340c4c503df67f" diff --git a/pyproject.toml b/pyproject.toml index fd86351..d72e86e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ description = "JARVIS admin bot" authors = ["Zevaryx "] [tool.poetry.dependencies] -python = ">=3.10,<4" +python = ">=3.11,<4" PyYAML = "^6.0" GitPython = "^3.1.26" opencv-python = "^4.5.5" @@ -14,7 +14,7 @@ psutil = "^5.9.0" python-gitlab = "^3.1.1" ulid-py = "^1.1.0" tweepy = "^4.5.0" -jarvis-core = {git = "https://git.zevaryx.com/stark-industries/jarvis/jarvis-core.git", rev = "main"} # Mine +jarvis-core = { git = "https://git.zevaryx.com/stark-industries/jarvis/jarvis-core.git", rev = "beanie" } # Mine aiohttp = "^3.8.3" pastypy = "^1.0.3.post1" # Mine dateparser = "^1.1.1" @@ -24,15 +24,19 @@ rich = "^12.3.0" jurigged = "^0.5.3" # Contributed ansitoimg = "^2022.1" nest-asyncio = "^1.5.5" -thefuzz = {extras = ["speedup"], git = "https://github.com/zevaryx/thefuzz.git", rev = "master"} # Forked +thefuzz = { extras = [ + "speedup", +], git = "https://github.com/zevaryx/thefuzz.git", rev = "master" } # Forked beautifulsoup4 = "^4.11.1" -calculator = {git = "https://git.zevaryx.com/zevaryx/calculator.git"} # Mine +calculator = { git = "https://git.zevaryx.com/zevaryx/calculator.git" } # Mine redis = "^4.4.0" -interactions = {git = "https://github.com/interactions-py/interactions.py", rev = "5.x"} -statipy = {git = "https://github.com/zevaryx/statipy", rev = "main"} +interactions-py = ">=5.3,<6" +statipy = { git = "https://github.com/zevaryx/statipy", rev = "main" } beanie = "^1.17.0" -pydantic = "^1.10.7" +pydantic = ">=2.3.0,<3" orjson = "^3.8.8" +croniter = "^1.4.1" +erapi = { git = "https://git.zevaryx.com/zevaryx-technologies/erapi.git" } [tool.poetry.group.dev.dependencies] pre-commit = "^2.21.0" diff --git a/sample.env b/sample.env new file mode 100644 index 0000000..a35e88a --- /dev/null +++ b/sample.env @@ -0,0 +1,38 @@ +# Base Config, required +TOKEN= + +# Base Config, optional +ENVIRONMENT=develop +SYNC=false +LOG_LEVEL=INFO +JURIGGED=false + +# MongoDB, required +MONGO_HOST=localhost +MONGO_USERNAME= +MONGO_PASSWORD= +MONGO_PORT=27017 + +# Redis, required +REDIS_HOST=localhost +REDIS_USERNAME= +REDIS_PASSWORD= + +# Mastodon, optional +MASTODON_TOKEN= +MASTODON_URL= + +# Reddit, optional +REDDIT_USER_AGENT= +REDDIT_CLIENT_SECRET= +REDDIT_CLIENT_ID= + +# Twitter, optional +TWITTER_CONSUMER_KEY= +TWITTER_CONSUMER_SECRET= +TWITTER_ACCESS_TOKEN= +TWITTER_ACCESS_SECRET= +TWITTER_BEARER_TOKEN= + +# URLs, optional +URL_DBRAND= \ No newline at end of file