aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Xithrius <[email protected]>2022-11-02 02:07:29 -0700
committerGravatar GitHub <[email protected]>2022-11-02 02:07:29 -0700
commit43a2acf5ee4eb354ce3dfaeef9504eee9b9b46b4 (patch)
treecbdfeb08f8d582aa98acec6a529f0fa3dcd7933c
parentAppeased the formatter (diff)
parentMerge pull request #1137 from DivyanshuBist/bug-issue1122-message-of-type-None (diff)
Merge branch 'main' into main
-rw-r--r--.github/dependabot.yml6
-rw-r--r--.github/workflows/build.yaml1
-rw-r--r--.github/workflows/lint.yaml64
-rw-r--r--Dockerfile20
-rw-r--r--bot/__init__.py24
-rw-r--r--bot/__main__.py90
-rw-r--r--bot/bot.py198
-rw-r--r--bot/exts/avatar_modification/avatar_modify.py7
-rw-r--r--bot/exts/core/error_handler.py7
-rw-r--r--bot/exts/core/extensions.py44
-rw-r--r--bot/exts/core/help.py6
-rw-r--r--bot/exts/core/internal_eval/__init__.py4
-rw-r--r--bot/exts/core/internal_eval/_internal_eval.py3
-rw-r--r--bot/exts/core/ping.py4
-rw-r--r--bot/exts/core/source.py4
-rw-r--r--bot/exts/events/advent_of_code/__init__.py4
-rw-r--r--bot/exts/events/advent_of_code/_cog.py6
-rw-r--r--bot/exts/events/advent_of_code/_helpers.py10
-rw-r--r--bot/exts/events/advent_of_code/views/dayandstarview.py6
-rw-r--r--bot/exts/events/hacktoberfest/hacktober-issue-finder.py9
-rw-r--r--bot/exts/events/hacktoberfest/hacktoberstats.py4
-rw-r--r--bot/exts/events/hacktoberfest/timeleft.py4
-rw-r--r--bot/exts/events/trivianight/_questions.py2
-rw-r--r--bot/exts/events/trivianight/_scoreboard.py8
-rw-r--r--bot/exts/events/trivianight/trivianight.py4
-rw-r--r--bot/exts/fun/anagram.py4
-rw-r--r--bot/exts/fun/battleship.py4
-rw-r--r--bot/exts/fun/catify.py4
-rw-r--r--bot/exts/fun/coinflip.py4
-rw-r--r--bot/exts/fun/connect_four.py4
-rw-r--r--bot/exts/fun/duck_game.py4
-rw-r--r--bot/exts/fun/fun.py12
-rw-r--r--bot/exts/fun/game.py86
-rw-r--r--bot/exts/fun/hangman.py6
-rw-r--r--bot/exts/fun/latex.py4
-rw-r--r--bot/exts/fun/madlibs.py6
-rw-r--r--bot/exts/fun/magic_8ball.py4
-rw-r--r--bot/exts/fun/minesweeper.py10
-rw-r--r--bot/exts/fun/movie.py52
-rw-r--r--bot/exts/fun/quack.py11
-rw-r--r--bot/exts/fun/recommend_game.py4
-rw-r--r--bot/exts/fun/rps.py4
-rw-r--r--bot/exts/fun/snakes/__init__.py4
-rw-r--r--bot/exts/fun/snakes/_snakes_cog.py3
-rw-r--r--bot/exts/fun/space.py8
-rw-r--r--bot/exts/fun/speedrun.py4
-rw-r--r--bot/exts/fun/status_codes.py4
-rw-r--r--bot/exts/fun/tic_tac_toe.py4
-rw-r--r--bot/exts/fun/trivia_quiz.py6
-rw-r--r--bot/exts/fun/uwu.py4
-rw-r--r--bot/exts/fun/wonder_twins.py4
-rw-r--r--bot/exts/fun/xkcd.py4
-rw-r--r--bot/exts/holidays/earth_day/save_the_planet.py4
-rw-r--r--bot/exts/holidays/easter/april_fools_vids.py4
-rw-r--r--bot/exts/holidays/easter/bunny_name_generator.py4
-rw-r--r--bot/exts/holidays/easter/earth_photos.py4
-rw-r--r--bot/exts/holidays/easter/easter_riddle.py4
-rw-r--r--bot/exts/holidays/easter/egg_decorating.py4
-rw-r--r--bot/exts/holidays/easter/egg_facts.py6
-rw-r--r--bot/exts/holidays/easter/egghead_quiz.py52
-rw-r--r--bot/exts/holidays/easter/traditions.py4
-rw-r--r--bot/exts/holidays/halloween/8ball.py4
-rw-r--r--bot/exts/holidays/halloween/candy_collection.py9
-rw-r--r--bot/exts/holidays/halloween/halloween_facts.py4
-rw-r--r--bot/exts/holidays/halloween/halloweenify.py4
-rw-r--r--bot/exts/holidays/halloween/monsterbio.py4
-rw-r--r--bot/exts/holidays/halloween/monstersurvey.py4
-rw-r--r--bot/exts/holidays/halloween/scarymovie.py4
-rw-r--r--bot/exts/holidays/halloween/spookygif.py6
-rw-r--r--bot/exts/holidays/halloween/spookynamerate.py9
-rw-r--r--bot/exts/holidays/halloween/spookyrating.py4
-rw-r--r--bot/exts/holidays/halloween/spookyreact.py7
-rw-r--r--bot/exts/holidays/hanukkah/hanukkah_embed.py4
-rw-r--r--bot/exts/holidays/pride/drag_queen_name.py4
-rw-r--r--bot/exts/holidays/pride/pride_anthem.py4
-rw-r--r--bot/exts/holidays/pride/pride_facts.py6
-rw-r--r--bot/exts/holidays/pride/pride_leader.py4
-rw-r--r--bot/exts/holidays/valentines/be_my_valentine.py4
-rw-r--r--bot/exts/holidays/valentines/lovecalculator.py4
-rw-r--r--bot/exts/holidays/valentines/movie_generator.py4
-rw-r--r--bot/exts/holidays/valentines/myvalenstate.py4
-rw-r--r--bot/exts/holidays/valentines/pickuplines.py4
-rw-r--r--bot/exts/holidays/valentines/savethedate.py4
-rw-r--r--bot/exts/holidays/valentines/valentine_zodiac.py4
-rw-r--r--bot/exts/holidays/valentines/whoisvalentine.py4
-rw-r--r--bot/exts/utilities/bookmark.py4
-rw-r--r--bot/exts/utilities/challenges.py4
-rw-r--r--bot/exts/utilities/cheatsheet.py4
-rw-r--r--bot/exts/utilities/colour.py7
-rw-r--r--bot/exts/utilities/conversationstarters.py4
-rw-r--r--bot/exts/utilities/emoji.py10
-rw-r--r--bot/exts/utilities/epoch.py12
-rw-r--r--bot/exts/utilities/githubinfo.py7
-rw-r--r--bot/exts/utilities/logging.py40
-rw-r--r--bot/exts/utilities/pythonfacts.py4
-rw-r--r--bot/exts/utilities/realpython.py4
-rw-r--r--bot/exts/utilities/reddit.py17
-rw-r--r--bot/exts/utilities/stackoverflow.py4
-rw-r--r--bot/exts/utilities/timed.py4
-rw-r--r--bot/exts/utilities/twemoji.py11
-rw-r--r--bot/exts/utilities/wikipedia.py4
-rw-r--r--bot/exts/utilities/wolfram.py17
-rw-r--r--bot/exts/utilities/wtf_python.py6
-rw-r--r--bot/monkey_patches.py91
-rw-r--r--bot/resources/utilities/ryanzec_colours.json2
-rw-r--r--bot/utils/commands.py6
-rw-r--r--bot/utils/decorators.py27
-rw-r--r--bot/utils/extensions.py45
-rw-r--r--bot/utils/pagination.py3
-rw-r--r--poetry.lock1556
-rw-r--r--pyproject.toml60
-rw-r--r--tox.ini2
112 files changed, 1896 insertions, 1065 deletions
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 00000000..b38df29f
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,6 @@
+version: 2
+updates:
+ - package-ecosystem: "pip"
+ directory: "/"
+ schedule:
+ interval: "daily"
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 854243e6..62c83b0a 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -79,7 +79,6 @@ jobs:
uses: actions/checkout@v2
with:
repository: python-discord/kubernetes
- token: ${{ secrets.REPO_TOKEN }}
path: kubernetes
- name: Authenticate with Kubernetes
diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml
index 2cbfc2f5..fd41e972 100644
--- a/.github/workflows/lint.yaml
+++ b/.github/workflows/lint.yaml
@@ -26,56 +26,16 @@ jobs:
Mozilla Public License 2.0 (MPL 2.0);
Public Domain;
Python Software Foundation License
- # See https://github.com/pre-commit/pre-commit/issues/2178#issuecomment-1002163763
- # for why we set this.
- SETUPTOOLS_USE_DISTUTILS: stdlib
-
-# Configure pip to cache dependencies and do a user install
- PIP_NO_CACHE_DIR: false
- PIP_USER: 1
-
- # Disable Poetry virtualenv creation
- POETRY_VIRTUALENVS_CREATE: false
-
- # Specify explicit paths for python dependencies and the pre-commit
- # environment so we know which directories to cache
- PYTHONUSERBASE: ${{ github.workspace }}/.cache/py-user-base
- PRE_COMMIT_HOME: ${{ github.workspace }}/.cache/pre-commit-cache
steps:
- - name: Add custom PYTHONUSERBASE to PATH
- run: echo '${{ env.PYTHONUSERBASE }}/bin/' >> $GITHUB_PATH
-
- name: Checkout repository
uses: actions/checkout@v2
- - name: Setup python
- id: python
- uses: actions/setup-python@v2
+ - name: Install Python Dependencies
+ uses: HassanAbouelela/actions/setup-python@setup-python_v1.3.1
with:
- python-version: '3.9'
-
- # This step caches our Python dependencies. To make sure we
- # only restore a cache when the dependencies, the python version,
- # the runner operating system, and the dependency location haven't
- # changed, we create a cache key that is a composite of those states.
- #
- # Only when the context is exactly the same, we will restore the cache.
- - name: Python Dependency Caching
- uses: actions/cache@v2
- id: python_cache
- with:
- path: ${{ env.PYTHONUSERBASE }}
- key: "python-0-${{ runner.os }}-${{ env.PYTHONUSERBASE }}-\
- ${{ steps.python.outputs.python-version }}-\
- ${{ hashFiles('./pyproject.toml', './poetry.lock') }}"
-
- # Install our dependencies if we did not restore a dependency cache
- - name: Install dependencies using poetry
- if: steps.python_cache.outputs.cache-hit != 'true'
- run: |
- pip install poetry
- poetry install --no-interaction --no-ansi
+ dev: true
+ python_version: "3.10"
# Check all of our dev dependencies are compatible with the MIT license.
# If you added a new dependencies that is being rejected,
@@ -94,22 +54,10 @@ jobs:
USE_FAKEREDIS: true
IN_CI: true
- # This step caches our pre-commit environment. To make sure we
- # do create a new environment when our pre-commit setup changes,
- # we create a cache key based on relevant factors.
- - name: Pre-commit Environment Caching
- uses: actions/cache@v2
- with:
- path: ${{ env.PRE_COMMIT_HOME }}
- key: "precommit-0-${{ runner.os }}-${{ env.PRE_COMMIT_HOME }}-\
- ${{ steps.python.outputs.python-version }}-\
- ${{ hashFiles('./.pre-commit-config.yaml') }}"
-
# We will not run `flake8` here, as we will use a separate flake8
- # action. As pre-commit does not support user installs, we set
- # PIP_USER=0 to not do a user install.
+ # action.
- name: Run pre-commit hooks
- run: export PIP_USER=0; SKIP=flake8 pre-commit run --all-files
+ run: SKIP=flake8 pre-commit run --all-files
# Run flake8 and have it format the linting errors in the format of
# the GitHub Workflow command to register error annotations. This
diff --git a/Dockerfile b/Dockerfile
index 44ef0574..43fcdf5a 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,20 +1,9 @@
-FROM --platform=linux/amd64 python:3.9-slim
-
-# Set pip to have cleaner logs and no saved cache
-ENV PIP_NO_CACHE_DIR=false \
- POETRY_VIRTUALENVS_CREATE=false
-
-# Install Poetry
-RUN pip install --upgrade poetry
+FROM --platform=linux/amd64 ghcr.io/chrislovering/python-poetry-base:3.10-slim
+# Install dependencies
WORKDIR /bot
-
-# Copy dependencies and lockfile
-COPY pyproject.toml poetry.lock /bot/
-
-# Install dependencies and lockfile, excluding development
-# dependencies,
-RUN poetry install --no-dev --no-interaction --no-ansi
+COPY pyproject.toml poetry.lock ./
+RUN poetry install --without dev
# Set SHA build argument
ARG git_sha="development"
@@ -24,4 +13,5 @@ ENV GIT_SHA=$git_sha
COPY . .
# Start the bot
+ENTRYPOINT ["poetry", "run"]
CMD ["python", "-m", "bot"]
diff --git a/bot/__init__.py b/bot/__init__.py
index 3136c863..33fd4e1c 100644
--- a/bot/__init__.py
+++ b/bot/__init__.py
@@ -8,15 +8,18 @@ except ModuleNotFoundError:
import asyncio
import logging
import os
-from functools import partial, partialmethod
+from typing import TYPE_CHECKING
import arrow
import sentry_sdk
-from discord.ext import commands
+from botcore.utils import apply_monkey_patches
from sentry_sdk.integrations.logging import LoggingIntegration
from sentry_sdk.integrations.redis import RedisIntegration
-from bot import log, monkey_patches
+from bot import log
+
+if TYPE_CHECKING:
+ from bot.bot import Bot
sentry_logging = LoggingIntegration(
level=logging.DEBUG,
@@ -41,17 +44,6 @@ start_time = arrow.utcnow()
if os.name == "nt":
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
-monkey_patches.patch_typing()
-
-# This patches any convertors that use PartialMessage, but not the PartialMessageConverter itself
-# as library objects are made by this mapping.
-# https://github.com/Rapptz/discord.py/blob/1a4e73d59932cdbe7bf2c281f25e32529fc7ae1f/discord/ext/commands/converter.py#L984-L1004
-commands.converter.PartialMessageConverter = monkey_patches.FixedPartialMessageConverter
-
-# Monkey-patch discord.py decorators to use the both the Command and Group subclasses which supports root aliases.
-# Must be patched before any cogs are added.
-commands.command = partial(commands.command, cls=monkey_patches.Command)
-commands.GroupMixin.command = partialmethod(commands.GroupMixin.command, cls=monkey_patches.Command)
+apply_monkey_patches()
-commands.group = partial(commands.group, cls=monkey_patches.Group)
-commands.GroupMixin.group = partialmethod(commands.GroupMixin.group, cls=monkey_patches.Group)
+instance: "Bot" = None # Global Bot instance.
diff --git a/bot/__main__.py b/bot/__main__.py
index bd6c70ee..9cf63dc5 100644
--- a/bot/__main__.py
+++ b/bot/__main__.py
@@ -1,19 +1,87 @@
+import asyncio
import logging
-from bot.bot import bot
-from bot.constants import Client, STAFF_ROLES, WHITELISTED_CHANNELS
+import aiohttp
+import discord
+from async_rediscache import RedisSession
+from botcore import StartupError
+from discord.ext import commands
+from redis import RedisError
+
+import bot
+from bot import constants
+from bot.bot import Bot
from bot.utils.decorators import whitelist_check
-from bot.utils.extensions import walk_extensions
log = logging.getLogger(__name__)
-bot.add_check(whitelist_check(channels=WHITELISTED_CHANNELS, roles=STAFF_ROLES))
-for ext in walk_extensions():
- bot.load_extension(ext)
+async def _create_redis_session() -> RedisSession:
+ """Create and connect to a redis session."""
+ redis_session = RedisSession(
+ host=constants.RedisConfig.host,
+ port=constants.RedisConfig.port,
+ password=constants.RedisConfig.password,
+ max_connections=20,
+ use_fakeredis=constants.RedisConfig.use_fakeredis,
+ global_namespace="bot",
+ decode_responses=True,
+ )
+ try:
+ return await redis_session.connect()
+ except RedisError as e:
+ raise StartupError(e)
+
+
+async def test_bot_in_ci(bot: Bot) -> None:
+ """
+ Attempt to import all extensions and then return.
+
+ This is to ensure that all extensions can at least be
+ imported and have a setup function within our CI.
+ """
+ from botcore.utils._extensions import walk_extensions
+
+ from bot import exts
+
+ for _ in walk_extensions(exts):
+ # walk_extensions does all the heavy lifting within the generator.
+ pass
+
+
+async def main() -> None:
+ """Entry async method for starting the bot."""
+ allowed_roles = list({discord.Object(id_) for id_ in constants.MODERATION_ROLES})
+ intents = discord.Intents.default()
+ intents.bans = False
+ intents.integrations = False
+ intents.invites = False
+ intents.message_content = True
+ intents.typing = False
+ intents.webhooks = False
+
+ async with aiohttp.ClientSession() as session:
+ bot.instance = Bot(
+ guild_id=constants.Client.guild,
+ http_session=session,
+ redis_session=await _create_redis_session(),
+ command_prefix=commands.when_mentioned_or(constants.Client.prefix),
+ activity=discord.Game(name=f"Commands: {constants.Client.prefix}help"),
+ case_insensitive=True,
+ allowed_mentions=discord.AllowedMentions(everyone=False, roles=allowed_roles),
+ intents=intents,
+ allowed_roles=allowed_roles,
+ )
+
+ async with bot.instance as _bot:
+ _bot.add_check(whitelist_check(
+ channels=constants.WHITELISTED_CHANNELS,
+ roles=constants.STAFF_ROLES,
+ ))
+ if constants.Client.in_ci:
+ await test_bot_in_ci(_bot)
+ else:
+ await _bot.start(constants.Client.token)
+
-if not Client.in_ci:
- # Manually enable the message content intent. This is required until the below PR is merged
- # https://github.com/python-discord/sir-lancebot/pull/1092
- bot._connection._intents.value += 1 << 15
- bot.run(Client.token)
+asyncio.run(main())
diff --git a/bot/bot.py b/bot/bot.py
index c7b87a65..636946f1 100644
--- a/bot/bot.py
+++ b/bot/bot.py
@@ -1,24 +1,20 @@
-import asyncio
import logging
-import socket
-from contextlib import suppress
from typing import Optional
import discord
-from aiohttp import AsyncResolver, ClientSession, TCPConnector
-from async_rediscache import RedisSession
-from discord import DiscordException, Embed, Forbidden, Thread
+from botcore import BotBase
+from botcore.utils import scheduling
+from discord import DiscordException, Embed
from discord.ext import commands
-from discord.ext.commands import Cog, when_mentioned_or
-from bot import constants
+from bot import constants, exts
log = logging.getLogger(__name__)
-__all__ = ("Bot", "bot")
+__all__ = ("Bot", )
-class Bot(commands.Bot):
+class Bot(BotBase):
"""
Base bot instance.
@@ -29,16 +25,6 @@ class Bot(commands.Bot):
name = constants.Client.name
- def __init__(self, redis_session: RedisSession, **kwargs):
- super().__init__(**kwargs)
- self.http_session = ClientSession(
- connector=TCPConnector(resolver=AsyncResolver(), family=socket.AF_INET)
- )
- self._guild_available = asyncio.Event()
- self.redis_session = redis_session
- self.loop.create_task(self.check_channels())
- self.loop.create_task(self.send_log(self.name, "Connected!"))
-
@property
def member(self) -> Optional[discord.Member]:
"""Retrieves the guild member object for the bot."""
@@ -47,60 +33,6 @@ class Bot(commands.Bot):
return None
return guild.me
- @Cog.listener()
- async def on_thread_join(self, thread: Thread) -> None:
- """
- Try to join newly created threads.
-
- Despite the event name being misleading, this is dispatched when new threads are created.
- We want our bots to automatically join threads in order to answer commands using their prefixes.
- """
- if thread.me:
- # Already in this thread, return early
- return
-
- with suppress(Forbidden):
- await thread.join()
-
- async def close(self) -> None:
- """Close Redis session when bot is shutting down."""
- await super().close()
-
- if self.http_session:
- await self.http_session.close()
-
- if self.redis_session:
- await self.redis_session.close()
-
- def add_cog(self, cog: commands.Cog) -> None:
- """
- Delegate to super to register `cog`.
-
- This only serves to make the info log, so that extensions don't have to.
- """
- super().add_cog(cog)
- log.info(f"Cog loaded: {cog.qualified_name}")
-
- def add_command(self, command: commands.Command) -> None:
- """Add `command` as normal and then add its root aliases to the bot."""
- super().add_command(command)
- self._add_root_aliases(command)
-
- def remove_command(self, name: str) -> Optional[commands.Command]:
- """
- Remove a command/alias as normal and then remove its root aliases from the bot.
-
- Individual root aliases cannot be removed by this function.
- To remove them, either remove the entire command or manually edit `bot.all_commands`.
- """
- command = super().remove_command(name)
- if command is None:
- # Even if it's a root alias, there's no way to get the Bot instance to remove the alias.
- return
-
- self._remove_root_aliases(command)
- return command
-
async def on_command_error(self, context: commands.Context, exception: DiscordException) -> None:
"""Check command errors for UserInputError and reset the cooldown if thrown."""
if isinstance(exception, commands.UserInputError):
@@ -108,34 +40,10 @@ class Bot(commands.Bot):
else:
await super().on_command_error(context, exception)
- async def check_channels(self) -> None:
- """Verifies that all channel constants refer to channels which exist."""
- await self.wait_until_guild_available()
-
- if constants.Client.debug:
- log.info("Skipping Channels Check.")
- return
-
- all_channels_ids = [channel.id for channel in self.get_all_channels()]
- for name, channel_id in vars(constants.Channels).items():
- if name.startswith("_"):
- continue
- if channel_id not in all_channels_ids:
- log.error(f'Channel "{name}" with ID {channel_id} missing')
-
- async def send_log(self, title: str, details: str = None, *, icon: str = None) -> None:
- """Send an embed message to the devlog channel."""
- await self.wait_until_guild_available()
+ async def log_to_dev_log(self, title: str, details: str = None, *, icon: str = None) -> None:
+ """Send an embed message to the dev-log channel."""
devlog = self.get_channel(constants.Channels.devlog)
- if not devlog:
- log.info(f"Fetching devlog channel as it wasn't found in the cache (ID: {constants.Channels.devlog})")
- try:
- devlog = await self.fetch_channel(constants.Channels.devlog)
- except discord.HTTPException as discord_exc:
- log.exception("Fetch failed", exc_info=discord_exc)
- return
-
if not icon:
icon = self.user.display_avatar.url
@@ -144,84 +52,18 @@ class Bot(commands.Bot):
await devlog.send(embed=embed)
- async def on_guild_available(self, guild: discord.Guild) -> None:
- """
- Set the internal `_guild_available` event when PyDis guild becomes available.
-
- If the cache appears to still be empty (no members, no channels, or no roles), the event
- will not be set.
- """
- if guild.id != constants.Client.guild:
- return
-
- if not guild.roles or not guild.members or not guild.channels:
- log.warning("Guild available event was dispatched but the cache appears to still be empty!")
- return
+ async def setup_hook(self) -> None:
+ """Default async initialisation method for discord.py."""
+ await super().setup_hook()
- self._guild_available.set()
+ # This is not awaited to avoid a deadlock with any cogs that have
+ # wait_until_guild_available in their cog_load method.
+ scheduling.create_task(self.load_extensions(exts))
- async def on_guild_unavailable(self, guild: discord.Guild) -> None:
- """Clear the internal `_guild_available` event when PyDis guild becomes unavailable."""
- if guild.id != constants.Client.guild:
+ async def invoke_help_command(self, ctx: commands.Context) -> None:
+ """Invoke the help command or default help command if help extensions is not loaded."""
+ if "bot.exts.core.help" in ctx.bot.extensions:
+ help_command = ctx.bot.get_command("help")
+ await ctx.invoke(help_command, ctx.command.qualified_name)
return
-
- self._guild_available.clear()
-
- async def wait_until_guild_available(self) -> None:
- """
- Wait until the PyDis guild becomes available (and the cache is ready).
-
- The on_ready event is inadequate because it only waits 2 seconds for a GUILD_CREATE
- gateway event before giving up and thus not populating the cache for unavailable guilds.
- """
- await self._guild_available.wait()
-
- def _add_root_aliases(self, command: commands.Command) -> None:
- """Recursively add root aliases for `command` and any of its subcommands."""
- if isinstance(command, commands.Group):
- for subcommand in command.commands:
- self._add_root_aliases(subcommand)
-
- for alias in getattr(command, "root_aliases", ()):
- if alias in self.all_commands:
- raise commands.CommandRegistrationError(alias, alias_conflict=True)
-
- self.all_commands[alias] = command
-
- def _remove_root_aliases(self, command: commands.Command) -> None:
- """Recursively remove root aliases for `command` and any of its subcommands."""
- if isinstance(command, commands.Group):
- for subcommand in command.commands:
- self._remove_root_aliases(subcommand)
-
- for alias in getattr(command, "root_aliases", ()):
- self.all_commands.pop(alias, None)
-
-
-_allowed_roles = [discord.Object(id_) for id_ in constants.MODERATION_ROLES]
-
-_intents = discord.Intents.default() # Default is all intents except for privileged ones (Members, Presences, ...)
-_intents.bans = False
-_intents.integrations = False
-_intents.invites = False
-_intents.typing = False
-_intents.webhooks = False
-
-redis_session = RedisSession(
- address=(constants.RedisConfig.host, constants.RedisConfig.port),
- password=constants.RedisConfig.password,
- minsize=1,
- maxsize=20,
- use_fakeredis=constants.RedisConfig.use_fakeredis,
- global_namespace="sir-lancebot"
-)
-loop = asyncio.get_event_loop()
-loop.run_until_complete(redis_session.connect())
-
-bot = Bot(
- redis_session=redis_session,
- command_prefix=when_mentioned_or(constants.Client.prefix),
- activity=discord.Game(name=f"Commands: {constants.Client.prefix}help"),
- allowed_mentions=discord.AllowedMentions(everyone=False, roles=_allowed_roles),
- intents=_intents,
-)
+ await ctx.send_help(ctx.command)
diff --git a/bot/exts/avatar_modification/avatar_modify.py b/bot/exts/avatar_modification/avatar_modify.py
index 3ee70cfd..6d1f26f6 100644
--- a/bot/exts/avatar_modification/avatar_modify.py
+++ b/bot/exts/avatar_modification/avatar_modify.py
@@ -14,7 +14,6 @@ from discord.ext import commands
from bot.bot import Bot
from bot.constants import Colours, Emojis
from bot.exts.avatar_modification._effects import PfpEffects
-from bot.utils.extensions import invoke_help_command
from bot.utils.halloween import spookifications
log = logging.getLogger(__name__)
@@ -89,7 +88,7 @@ class AvatarModify(commands.Cog):
async def avatar_modify(self, ctx: commands.Context) -> None:
"""Groups all of the pfp modifying commands to allow a single concurrency limit."""
if not ctx.invoked_subcommand:
- await invoke_help_command(ctx)
+ await self.bot.invoke_help_command(ctx)
@avatar_modify.command(name="8bitify", root_aliases=("8bitify",))
async def eightbit_command(self, ctx: commands.Context) -> None:
@@ -367,6 +366,6 @@ class AvatarModify(commands.Cog):
await ctx.send(file=file, embed=embed)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the AvatarModify cog."""
- bot.add_cog(AvatarModify(bot))
+ await bot.add_cog(AvatarModify(bot))
diff --git a/bot/exts/core/error_handler.py b/bot/exts/core/error_handler.py
index 4578f734..f62b3d4e 100644
--- a/bot/exts/core/error_handler.py
+++ b/bot/exts/core/error_handler.py
@@ -171,9 +171,8 @@ class CommandErrorHandler(commands.Cog):
if not await similar_command.can_run(ctx):
log.debug(log_msg)
continue
- except commands.errors.CommandError as cmd_error:
+ except commands.errors.CommandError:
log.debug(log_msg)
- await self.on_command_error(ctx, cmd_error)
continue
command_suggestions.append(similar_command_name)
@@ -187,6 +186,6 @@ class CommandErrorHandler(commands.Cog):
await ctx.send(embed=e, delete_after=RedirectOutput.delete_delay)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the ErrorHandler cog."""
- bot.add_cog(CommandErrorHandler(bot))
+ await bot.add_cog(CommandErrorHandler(bot))
diff --git a/bot/exts/core/extensions.py b/bot/exts/core/extensions.py
index d809d2b9..5b958c02 100644
--- a/bot/exts/core/extensions.py
+++ b/bot/exts/core/extensions.py
@@ -4,6 +4,7 @@ from collections.abc import Mapping
from enum import Enum
from typing import Optional
+from botcore.utils._extensions import unqualify
from discord import Colour, Embed
from discord.ext import commands
from discord.ext.commands import Context, group
@@ -12,7 +13,6 @@ from bot import exts
from bot.bot import Bot
from bot.constants import Client, Emojis, MODERATION_ROLES, Roles
from bot.utils.checks import with_role_check
-from bot.utils.extensions import EXTENSIONS, invoke_help_command, unqualify
from bot.utils.pagination import LinePaginator
log = logging.getLogger(__name__)
@@ -46,13 +46,13 @@ class Extension(commands.Converter):
argument = argument.lower()
- if argument in EXTENSIONS:
+ if argument in ctx.bot.all_extensions:
return argument
- elif (qualified_arg := f"{exts.__name__}.{argument}") in EXTENSIONS:
+ elif (qualified_arg := f"{exts.__name__}.{argument}") in ctx.bot.all_extensions:
return qualified_arg
matches = []
- for ext in EXTENSIONS:
+ for ext in ctx.bot.all_extensions:
if argument == unqualify(ext):
matches.append(ext)
@@ -78,7 +78,7 @@ class Extensions(commands.Cog):
@group(name="extensions", aliases=("ext", "exts", "c", "cogs"), invoke_without_command=True)
async def extensions_group(self, ctx: Context) -> None:
"""Load, unload, reload, and list loaded extensions."""
- await invoke_help_command(ctx)
+ await self.bot.invoke_help_command(ctx)
@extensions_group.command(name="load", aliases=("l",))
async def load_command(self, ctx: Context, *extensions: Extension) -> None:
@@ -88,13 +88,13 @@ class Extensions(commands.Cog):
If '\*' or '\*\*' is given as the name, all unloaded extensions will be loaded.
""" # noqa: W605
if not extensions:
- await invoke_help_command(ctx)
+ await self.bot.invoke_help_command(ctx)
return
if "*" in extensions or "**" in extensions:
- extensions = set(EXTENSIONS) - set(self.bot.extensions.keys())
+ extensions = set(self.bot.all_extensions) - set(self.bot.extensions.keys())
- msg = self.batch_manage(Action.LOAD, *extensions)
+ msg = await self.batch_manage(Action.LOAD, *extensions)
await ctx.send(msg)
@extensions_group.command(name="unload", aliases=("ul",))
@@ -105,7 +105,7 @@ class Extensions(commands.Cog):
If '\*' or '\*\*' is given as the name, all loaded extensions will be unloaded.
""" # noqa: W605
if not extensions:
- await invoke_help_command(ctx)
+ await self.bot.invoke_help_command(ctx)
return
blacklisted = "\n".join(UNLOAD_BLACKLIST & set(extensions))
@@ -116,7 +116,7 @@ class Extensions(commands.Cog):
if "*" in extensions or "**" in extensions:
extensions = set(self.bot.extensions.keys()) - UNLOAD_BLACKLIST
- msg = self.batch_manage(Action.UNLOAD, *extensions)
+ msg = await self.batch_manage(Action.UNLOAD, *extensions)
await ctx.send(msg)
@@ -131,16 +131,16 @@ class Extensions(commands.Cog):
If '\*\*' is given as the name, all extensions, including unloaded ones, will be reloaded.
""" # noqa: W605
if not extensions:
- await invoke_help_command(ctx)
+ await self.bot.invoke_help_command(ctx)
return
if "**" in extensions:
- extensions = EXTENSIONS
+ extensions = self.bot.all_extensions
elif "*" in extensions:
extensions = set(self.bot.extensions.keys()) | set(extensions)
extensions.remove("*")
- msg = self.batch_manage(Action.RELOAD, *extensions)
+ msg = await self.batch_manage(Action.RELOAD, *extensions)
await ctx.send(msg)
@@ -175,7 +175,7 @@ class Extensions(commands.Cog):
"""Return a mapping of extension names and statuses to their categories."""
categories = {}
- for ext in EXTENSIONS:
+ for ext in self.bot.all_extensions:
if ext in self.bot.extensions:
status = Emojis.status_online
else:
@@ -191,21 +191,21 @@ class Extensions(commands.Cog):
return categories
- def batch_manage(self, action: Action, *extensions: str) -> str:
+ async def batch_manage(self, action: Action, *extensions: str) -> str:
"""
Apply an action to multiple extensions and return a message with the results.
If only one extension is given, it is deferred to `manage()`.
"""
if len(extensions) == 1:
- msg, _ = self.manage(action, extensions[0])
+ msg, _ = await self.manage(action, extensions[0])
return msg
verb = action.name.lower()
failures = {}
for extension in extensions:
- _, error = self.manage(action, extension)
+ _, error = await self.manage(action, extension)
if error:
failures[extension] = error
@@ -220,17 +220,17 @@ class Extensions(commands.Cog):
return msg
- def manage(self, action: Action, ext: str) -> tuple[str, Optional[str]]:
+ async def manage(self, action: Action, ext: str) -> tuple[str, Optional[str]]:
"""Apply an action to an extension and return the status message and any error message."""
verb = action.name.lower()
error_msg = None
try:
- action.value(self.bot, ext)
+ await action.value(self.bot, ext)
except (commands.ExtensionAlreadyLoaded, commands.ExtensionNotLoaded):
if action is Action.RELOAD:
# When reloading, just load the extension if it was not loaded.
- return self.manage(Action.LOAD, ext)
+ return await self.manage(Action.LOAD, ext)
msg = f":x: Extension `{ext}` is already {verb}ed."
log.debug(msg[4:])
@@ -261,6 +261,6 @@ class Extensions(commands.Cog):
error.handled = True
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Extensions cog."""
- bot.add_cog(Extensions(bot))
+ await bot.add_cog(Extensions(bot))
diff --git a/bot/exts/core/help.py b/bot/exts/core/help.py
index eb7a9762..30deaff4 100644
--- a/bot/exts/core/help.py
+++ b/bot/exts/core/help.py
@@ -220,11 +220,11 @@ class HelpSession:
async def prepare(self) -> None:
"""Sets up the help session pages, events, message and reactions."""
await self.build_pages()
+ await self.update_page()
self._bot.add_listener(self.on_reaction_add)
self._bot.add_listener(self.on_message_delete)
- await self.update_page()
self.add_reactions()
def add_reactions(self) -> None:
@@ -547,7 +547,7 @@ def unload(bot: Bot) -> None:
bot.add_command(bot._old_help)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""
The setup for the help extension.
@@ -562,7 +562,7 @@ def setup(bot: Bot) -> None:
bot.remove_command("help")
try:
- bot.add_cog(Help())
+ await bot.add_cog(Help())
except Exception:
unload(bot)
raise
diff --git a/bot/exts/core/internal_eval/__init__.py b/bot/exts/core/internal_eval/__init__.py
index 695fa74d..258f7fd8 100644
--- a/bot/exts/core/internal_eval/__init__.py
+++ b/bot/exts/core/internal_eval/__init__.py
@@ -1,10 +1,10 @@
from bot.bot import Bot
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Set up the Internal Eval extension."""
# Import the Cog at runtime to prevent side effects like defining
# RedisCache instances too early.
from ._internal_eval import InternalEval
- bot.add_cog(InternalEval(bot))
+ await bot.add_cog(InternalEval(bot))
diff --git a/bot/exts/core/internal_eval/_internal_eval.py b/bot/exts/core/internal_eval/_internal_eval.py
index 190a15ec..2daf8ef9 100644
--- a/bot/exts/core/internal_eval/_internal_eval.py
+++ b/bot/exts/core/internal_eval/_internal_eval.py
@@ -9,7 +9,6 @@ from discord.ext import commands
from bot.bot import Bot
from bot.constants import Client, Roles
from bot.utils.decorators import with_role
-from bot.utils.extensions import invoke_help_command
from ._helpers import EvalContext
@@ -154,7 +153,7 @@ class InternalEval(commands.Cog):
async def internal_group(self, ctx: commands.Context) -> None:
"""Internal commands. Top secret!"""
if not ctx.invoked_subcommand:
- await invoke_help_command(ctx)
+ await self.bot.invoke_help_command(ctx)
@internal_group.command(name="eval", aliases=("e",))
@with_role(Roles.admins)
diff --git a/bot/exts/core/ping.py b/bot/exts/core/ping.py
index 6be78117..cb32398e 100644
--- a/bot/exts/core/ping.py
+++ b/bot/exts/core/ping.py
@@ -40,6 +40,6 @@ class Ping(commands.Cog):
await ctx.send(f"I started up {uptime_string}.")
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Ping cog."""
- bot.add_cog(Ping(bot))
+ await bot.add_cog(Ping(bot))
diff --git a/bot/exts/core/source.py b/bot/exts/core/source.py
index 2801be0f..f771eaca 100644
--- a/bot/exts/core/source.py
+++ b/bot/exts/core/source.py
@@ -82,6 +82,6 @@ class BotSource(commands.Cog):
return embed
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the BotSource cog."""
- bot.add_cog(BotSource())
+ await bot.add_cog(BotSource())
diff --git a/bot/exts/events/advent_of_code/__init__.py b/bot/exts/events/advent_of_code/__init__.py
index 3c521168..33c3971a 100644
--- a/bot/exts/events/advent_of_code/__init__.py
+++ b/bot/exts/events/advent_of_code/__init__.py
@@ -1,10 +1,10 @@
from bot.bot import Bot
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Set up the Advent of Code extension."""
# Import the Cog at runtime to prevent side effects like defining
# RedisCache instances too early.
from ._cog import AdventOfCode
- bot.add_cog(AdventOfCode(bot))
+ await bot.add_cog(AdventOfCode(bot))
diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py
index 518841d4..49140a3f 100644
--- a/bot/exts/events/advent_of_code/_cog.py
+++ b/bot/exts/events/advent_of_code/_cog.py
@@ -18,7 +18,6 @@ from bot.exts.events.advent_of_code.views.dayandstarview import AoCDropdownView
from bot.utils import members
from bot.utils.decorators import InChannelCheckFailure, in_month, whitelist_override, with_role
from bot.utils.exceptions import MovedCommandError
-from bot.utils.extensions import invoke_help_command
log = logging.getLogger(__name__)
@@ -71,7 +70,6 @@ class AdventOfCode(commands.Cog):
Runs on a schedule, as defined in the task.loop decorator.
"""
- await self.bot.wait_until_guild_available()
guild = self.bot.get_guild(Client.guild)
completionist_role = guild.get_role(Roles.aoc_completionist)
if completionist_role is None:
@@ -87,7 +85,7 @@ class AdventOfCode(commands.Cog):
try:
leaderboard = await _helpers.fetch_leaderboard()
except _helpers.FetchingLeaderboardFailedError:
- await self.bot.send_log("Unable to fetch AoC leaderboard during role sync.")
+ await self.bot.log_to_dev_log("Unable to fetch AoC leaderboard during role sync.")
return
placement_leaderboard = json.loads(leaderboard["placement_leaderboard"])
@@ -122,7 +120,7 @@ class AdventOfCode(commands.Cog):
async def adventofcode_group(self, ctx: commands.Context) -> None:
"""All of the Advent of Code commands."""
if not ctx.invoked_subcommand:
- await invoke_help_command(ctx)
+ await self.bot.invoke_help_command(ctx)
@with_role(Roles.admins)
@adventofcode_group.command(
diff --git a/bot/exts/events/advent_of_code/_helpers.py b/bot/exts/events/advent_of_code/_helpers.py
index 6c004901..abd80b77 100644
--- a/bot/exts/events/advent_of_code/_helpers.py
+++ b/bot/exts/events/advent_of_code/_helpers.py
@@ -523,13 +523,6 @@ async def countdown_status(bot: Bot) -> None:
# Log that we're going to start with the countdown status.
log.info("The Advent of Code has started or will start soon, starting countdown status.")
- # Trying to change status too early in the bot's startup sequence will fail
- # the task because the websocket instance has not yet been created. Waiting
- # for this event means that both the websocket instance has been initialized
- # and that the connection to Discord is mature enough to change the presence
- # of the bot.
- await bot.wait_until_guild_available()
-
# Calculate when the task needs to stop running. To prevent the task from
# sleeping for the entire year, it will only wait in the currently
# configured year. This means that the task will only start hibernating once
@@ -578,9 +571,6 @@ async def new_puzzle_notification(bot: Bot) -> None:
log.info("The Advent of Code has started or will start soon, waking up notification task.")
- # Ensure that the guild cache is loaded so we can get the Advent of Code
- # channel and role.
- await bot.wait_until_guild_available()
aoc_channel = bot.get_channel(Channels.advent_of_code)
aoc_role = aoc_channel.guild.get_role(AdventOfCode.role_id)
diff --git a/bot/exts/events/advent_of_code/views/dayandstarview.py b/bot/exts/events/advent_of_code/views/dayandstarview.py
index 5529c12b..f0ebc803 100644
--- a/bot/exts/events/advent_of_code/views/dayandstarview.py
+++ b/bot/exts/events/advent_of_code/views/dayandstarview.py
@@ -55,7 +55,7 @@ class AoCDropdownView(discord.ui.View):
options=[discord.SelectOption(label=str(i)) for i in range(1, 26)],
custom_id="day_select"
)
- async def day_select(self, select: discord.ui.Select, interaction: discord.Interaction) -> None:
+ async def day_select(self, _: discord.Interaction, select: discord.ui.Select) -> None:
"""Dropdown to choose a Day of the AoC."""
self.day = select.values[0]
@@ -64,12 +64,12 @@ class AoCDropdownView(discord.ui.View):
options=[discord.SelectOption(label=str(i)) for i in range(1, 3)],
custom_id="star_select"
)
- async def star_select(self, select: discord.ui.Select, interaction: discord.Interaction) -> None:
+ async def star_select(self, _: discord.Interaction, select: discord.ui.Select) -> None:
"""Dropdown to choose either the first or the second star."""
self.star = select.values[0]
@discord.ui.button(label="Fetch", style=discord.ButtonStyle.blurple)
- async def fetch(self, button: discord.ui.Button, interaction: discord.Interaction) -> None:
+ async def fetch(self, interaction: discord.Interaction, _: discord.ui.Button) -> None:
"""Button that fetches the statistics based on the dropdown values."""
if self.day == 0 or self.star == 0:
await interaction.response.send_message(
diff --git a/bot/exts/events/hacktoberfest/hacktober-issue-finder.py b/bot/exts/events/hacktoberfest/hacktober-issue-finder.py
index 1774564b..aeffc8d7 100644
--- a/bot/exts/events/hacktoberfest/hacktober-issue-finder.py
+++ b/bot/exts/events/hacktoberfest/hacktober-issue-finder.py
@@ -100,8 +100,9 @@ class HacktoberIssues(commands.Cog):
"""Format the issue data into a embed."""
title = issue["title"]
issue_url = issue["url"].replace("api.", "").replace("/repos/", "/")
- # issues can have empty bodies, which in that case GitHub doesn't include the key in the API response
- body = issue.get("body", "")
+ # Issues can have empty bodies, resulting in the value being a literal `null` (parsed as `None`).
+ # For this reason, we can't use the default arg of `dict.get`, and so instead use `or` logic.
+ body = issue.get("body") or ""
labels = [label["name"] for label in issue["labels"]]
embed = discord.Embed(title=title)
@@ -113,6 +114,6 @@ class HacktoberIssues(commands.Cog):
return embed
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the HacktoberIssue finder."""
- bot.add_cog(HacktoberIssues(bot))
+ await bot.add_cog(HacktoberIssues(bot))
diff --git a/bot/exts/events/hacktoberfest/hacktoberstats.py b/bot/exts/events/hacktoberfest/hacktoberstats.py
index 72067dbe..c29e24b0 100644
--- a/bot/exts/events/hacktoberfest/hacktoberstats.py
+++ b/bot/exts/events/hacktoberfest/hacktoberstats.py
@@ -432,6 +432,6 @@ class HacktoberStats(commands.Cog):
return author_id, author_mention
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Hacktober Stats Cog."""
- bot.add_cog(HacktoberStats(bot))
+ await bot.add_cog(HacktoberStats(bot))
diff --git a/bot/exts/events/hacktoberfest/timeleft.py b/bot/exts/events/hacktoberfest/timeleft.py
index 55109599..f470e932 100644
--- a/bot/exts/events/hacktoberfest/timeleft.py
+++ b/bot/exts/events/hacktoberfest/timeleft.py
@@ -62,6 +62,6 @@ class TimeLeft(commands.Cog):
)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Time Left Cog."""
- bot.add_cog(TimeLeft())
+ await bot.add_cog(TimeLeft())
diff --git a/bot/exts/events/trivianight/_questions.py b/bot/exts/events/trivianight/_questions.py
index d6beced9..5f1046dc 100644
--- a/bot/exts/events/trivianight/_questions.py
+++ b/bot/exts/events/trivianight/_questions.py
@@ -127,7 +127,7 @@ class QuestionView(View):
if len(guesses) != 0:
answers_chosen = {
answer_choice: len(
- tuple(filter(lambda x: x[0] == answer_choice, guesses.values()))
+ tuple(filter(lambda x: x[0] == answer_choice, guesses.values())) # noqa: B023
)
for answer_choice in labels
}
diff --git a/bot/exts/events/trivianight/_scoreboard.py b/bot/exts/events/trivianight/_scoreboard.py
index a5a5fcac..bd61be3d 100644
--- a/bot/exts/events/trivianight/_scoreboard.py
+++ b/bot/exts/events/trivianight/_scoreboard.py
@@ -123,26 +123,26 @@ class ScoreboardView(View):
return rank_embed
@discord.ui.button(label="Scoreboard for Speed", style=ButtonStyle.green)
- async def speed_leaderboard(self, button: Button, interaction: Interaction) -> None:
+ async def speed_leaderboard(self, interaction: Interaction, _: Button) -> None:
"""
Send an ephemeral message with the speed leaderboard embed.
Parameters:
- - button: The discord.ui.Button instance representing the `Speed Leaderboard` button.
- interaction: The discord.Interaction instance containing information on the interaction between the user
and the button.
+ - button: The discord.ui.Button instance representing the `Speed Leaderboard` button.
"""
await interaction.response.send_message(embed=await self._create_speed_embed(), ephemeral=True)
@discord.ui.button(label="What's my rank?", style=ButtonStyle.blurple)
- async def rank_button(self, button: Button, interaction: Interaction) -> None:
+ async def rank_button(self, interaction: Interaction, _: Button) -> None:
"""
Send an ephemeral message with the user's rank for the overall points/average speed.
Parameters:
- - button: The discord.ui.Button instance representing the `What's my rank?` button.
- interaction: The discord.Interaction instance containing information on the interaction between the user
and the button.
+ - button: The discord.ui.Button instance representing the `What's my rank?` button.
"""
await interaction.response.send_message(embed=self._get_rank(interaction.user), ephemeral=True)
diff --git a/bot/exts/events/trivianight/trivianight.py b/bot/exts/events/trivianight/trivianight.py
index 18d8327a..10435551 100644
--- a/bot/exts/events/trivianight/trivianight.py
+++ b/bot/exts/events/trivianight/trivianight.py
@@ -323,6 +323,6 @@ class TriviaNightCog(commands.Cog):
))
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the TriviaNight cog."""
- bot.add_cog(TriviaNightCog(bot))
+ await bot.add_cog(TriviaNightCog(bot))
diff --git a/bot/exts/fun/anagram.py b/bot/exts/fun/anagram.py
index 79280fa9..d8ea6a55 100644
--- a/bot/exts/fun/anagram.py
+++ b/bot/exts/fun/anagram.py
@@ -104,6 +104,6 @@ class Anagram(commands.Cog):
await game.message_creation(message)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Anagram cog."""
- bot.add_cog(Anagram(bot))
+ await bot.add_cog(Anagram(bot))
diff --git a/bot/exts/fun/battleship.py b/bot/exts/fun/battleship.py
index 77e38427..a8039cf2 100644
--- a/bot/exts/fun/battleship.py
+++ b/bot/exts/fun/battleship.py
@@ -442,6 +442,6 @@ class Battleship(commands.Cog):
await ctx.send(embed=embed)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Battleship Cog."""
- bot.add_cog(Battleship(bot))
+ await bot.add_cog(Battleship(bot))
diff --git a/bot/exts/fun/catify.py b/bot/exts/fun/catify.py
index 32dfae09..6e8c75ba 100644
--- a/bot/exts/fun/catify.py
+++ b/bot/exts/fun/catify.py
@@ -81,6 +81,6 @@ class Catify(commands.Cog):
)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Loads the catify cog."""
- bot.add_cog(Catify())
+ await bot.add_cog(Catify())
diff --git a/bot/exts/fun/coinflip.py b/bot/exts/fun/coinflip.py
index 804306bd..b7dee44d 100644
--- a/bot/exts/fun/coinflip.py
+++ b/bot/exts/fun/coinflip.py
@@ -48,6 +48,6 @@ class CoinFlip(commands.Cog):
await ctx.send(message)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Loads the coinflip cog."""
- bot.add_cog(CoinFlip())
+ await bot.add_cog(CoinFlip())
diff --git a/bot/exts/fun/connect_four.py b/bot/exts/fun/connect_four.py
index 1b88d065..0d870a6e 100644
--- a/bot/exts/fun/connect_four.py
+++ b/bot/exts/fun/connect_four.py
@@ -447,6 +447,6 @@ class ConnectFour(commands.Cog):
await self._play_game(ctx, None, board_size, str(emoji1), str(emoji2))
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load ConnectFour Cog."""
- bot.add_cog(ConnectFour(bot))
+ await bot.add_cog(ConnectFour(bot))
diff --git a/bot/exts/fun/duck_game.py b/bot/exts/fun/duck_game.py
index 10b03a49..a2612e51 100644
--- a/bot/exts/fun/duck_game.py
+++ b/bot/exts/fun/duck_game.py
@@ -341,6 +341,6 @@ class DuckGamesDirector(commands.Cog):
return await ctx.send(file=file, embed=embed)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the DuckGamesDirector cog."""
- bot.add_cog(DuckGamesDirector(bot))
+ await bot.add_cog(DuckGamesDirector(bot))
diff --git a/bot/exts/fun/fun.py b/bot/exts/fun/fun.py
index e7337cb6..8056b033 100644
--- a/bot/exts/fun/fun.py
+++ b/bot/exts/fun/fun.py
@@ -6,9 +6,10 @@ from pathlib import Path
from typing import Literal
import pyjokes
+from botcore.utils.commands import clean_text_or_reply
from discord import Embed
from discord.ext import commands
-from discord.ext.commands import BadArgument, Cog, Context, clean_content
+from discord.ext.commands import BadArgument, Cog, Context
from bot.bot import Bot
from bot.constants import Client, Colours, Emojis
@@ -60,13 +61,14 @@ class Fun(Cog):
raise BadArgument(f"`{Client.prefix}roll` only supports between 1 and 6 rolls.")
@commands.command(name="randomcase", aliases=("rcase", "randomcaps", "rcaps",))
- async def randomcase_command(self, ctx: Context, *, text: clean_content(fix_channel_mentions=True)) -> None:
- """Randomly converts the casing of a given `text`."""
+ async def randomcase_command(self, ctx: Context, *, text: str | None) -> None:
+ """Randomly converts the casing of a given `text`, or the replied message."""
def conversion_func(text: str) -> str:
"""Randomly converts the casing of a given string."""
return "".join(
char.upper() if round(random.random()) else char.lower() for char in text
)
+ text = await clean_text_or_reply(ctx, text)
text, embed = await messages.get_text_and_embed(ctx, text)
# Convert embed if it exists
if embed is not None:
@@ -157,6 +159,6 @@ class Fun(Cog):
await ctx.send(joke)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Fun cog."""
- bot.add_cog(Fun(bot))
+ await bot.add_cog(Fun(bot))
diff --git a/bot/exts/fun/game.py b/bot/exts/fun/game.py
index 5f56bef7..4e01444e 100644
--- a/bot/exts/fun/game.py
+++ b/bot/exts/fun/game.py
@@ -2,12 +2,12 @@ import difflib
import logging
import random
import re
-from asyncio import sleep
from datetime import datetime as dt, timedelta
from enum import IntEnum
from typing import Any, Optional
from aiohttp import ClientSession
+from botcore.utils import scheduling
from discord import Embed
from discord.ext import tasks
from discord.ext.commands import Cog, Context, group
@@ -15,7 +15,6 @@ from discord.ext.commands import Cog, Context, group
from bot.bot import Bot
from bot.constants import STAFF_ROLES, Tokens
from bot.utils.decorators import with_role
-from bot.utils.extensions import invoke_help_command
from bot.utils.pagination import ImagePaginator, LinePaginator
# Base URL of IGDB API
@@ -185,46 +184,45 @@ class Games(Cog):
self.genres: dict[str, int] = {}
self.headers = BASE_HEADERS
+ self.token_refresh_scheduler = scheduling.Scheduler(__name__)
- self.bot.loop.create_task(self.renew_access_token())
-
- async def renew_access_token(self) -> None:
- """Refeshes V4 access token a number of seconds before expiry. See `ACCESS_TOKEN_RENEWAL_WINDOW`."""
- while True:
- async with self.http_session.post(OAUTH_URL, params=OAUTH_PARAMS) as resp:
- result = await resp.json()
- if resp.status != 200:
- # If there is a valid access token continue to use that,
- # otherwise unload cog.
- if "Authorization" in self.headers:
- time_delta = timedelta(seconds=ACCESS_TOKEN_RENEWAL_WINDOW)
- logger.error(
- "Failed to renew IGDB access token. "
- f"Current token will last for {time_delta} "
- f"OAuth response message: {result['message']}"
- )
- else:
- logger.warning(
- "Invalid OAuth credentials. Unloading Games cog. "
- f"OAuth response message: {result['message']}"
- )
- self.bot.remove_cog("Games")
-
- return
-
- self.headers["Authorization"] = f"Bearer {result['access_token']}"
-
- # Attempt to renew before the token expires
- next_renewal = result["expires_in"] - ACCESS_TOKEN_RENEWAL_WINDOW
-
- time_delta = timedelta(seconds=next_renewal)
- logger.info(f"Successfully renewed access token. Refreshing again in {time_delta}")
-
- # This will be true the first time this loop runs.
- # Since we now have an access token, its safe to start this task.
- if self.genres == {}:
- self.refresh_genres_task.start()
- await sleep(next_renewal)
+ async def cog_load(self) -> None:
+ """Get an auth token and start the refresh task on cog load."""
+ await self.refresh_token()
+ self.refresh_genres_task.start()
+
+ async def refresh_token(self) -> None:
+ """
+ Refresh the IGDB V4 access token.
+
+ Once a new token has been created, schedule another refresh `ACCESS_TOKEN_RENEWAL_WINDOW` seconds before expiry.
+ """
+ async with self.http_session.post(OAUTH_URL, params=OAUTH_PARAMS) as resp:
+ result = await resp.json()
+ if resp.status != 200:
+ # If there is a valid access token continue to use that,
+ # otherwise unload cog.
+ if "Authorization" in self.headers:
+ time_delta = timedelta(seconds=ACCESS_TOKEN_RENEWAL_WINDOW)
+ logger.error(
+ "Failed to renew IGDB access token. "
+ f"Current token will last for {time_delta} "
+ f"OAuth response message: {result['message']}"
+ )
+ else:
+ logger.warning(
+ "Invalid OAuth credentials. Unloading Games cog. "
+ f"OAuth response message: {result['message']}"
+ )
+ self.bot.remove_cog("Games")
+ return
+
+ self.headers["Authorization"] = f"Bearer {result['access_token']}"
+
+ # Attempt to renew before the token expires
+ seconds_until_next_renewal = result["expires_in"] - ACCESS_TOKEN_RENEWAL_WINDOW
+ logger.info(f"Successfully renewed access token. Refreshing again in {seconds_until_next_renewal} seconds")
+ self.token_refresh_scheduler.schedule_later(seconds_until_next_renewal, __name__, self.refresh_token())
@tasks.loop(hours=24.0)
async def refresh_genres_task(self) -> None:
@@ -267,7 +265,7 @@ class Games(Cog):
"""
# When user didn't specified genre, send help message
if genre is None:
- await invoke_help_command(ctx)
+ await self.bot.invoke_help_command(ctx)
return
# Capitalize genre for check
@@ -505,7 +503,7 @@ class Games(Cog):
return sorted((item for item in results if item[0] >= 0.60), reverse=True)[:4]
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Games cog."""
# Check does IGDB API key exist, if not, log warning and don't load cog
if not Tokens.igdb_client_id:
@@ -514,4 +512,4 @@ def setup(bot: Bot) -> None:
if not Tokens.igdb_client_secret:
logger.warning("No IGDB client secret. Not loading Games cog.")
return
- bot.add_cog(Games(bot))
+ await bot.add_cog(Games(bot))
diff --git a/bot/exts/fun/hangman.py b/bot/exts/fun/hangman.py
index a2c8c735..f385a955 100644
--- a/bot/exts/fun/hangman.py
+++ b/bot/exts/fun/hangman.py
@@ -110,7 +110,7 @@ class Hangman(commands.Cog):
try:
message = await self.bot.wait_for(
- event="message",
+ "message",
timeout=60.0,
check=check
)
@@ -177,6 +177,6 @@ class Hangman(commands.Cog):
await ctx.send(embed=win_embed)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Hangman cog."""
- bot.add_cog(Hangman(bot))
+ await bot.add_cog(Hangman(bot))
diff --git a/bot/exts/fun/latex.py b/bot/exts/fun/latex.py
index aeabcd20..b5dada1c 100644
--- a/bot/exts/fun/latex.py
+++ b/bot/exts/fun/latex.py
@@ -133,6 +133,6 @@ class Latex(commands.Cog):
await ctx.send(file=discord.File(image_path, "latex.png"))
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Latex Cog."""
- bot.add_cog(Latex(bot))
+ await bot.add_cog(Latex(bot))
diff --git a/bot/exts/fun/madlibs.py b/bot/exts/fun/madlibs.py
index 21708e53..075dde75 100644
--- a/bot/exts/fun/madlibs.py
+++ b/bot/exts/fun/madlibs.py
@@ -93,7 +93,7 @@ class Madlibs(commands.Cog):
await original_message.edit(embed=madlibs_embed)
try:
- message = await self.bot.wait_for(event="message", check=author_check, timeout=TIMEOUT)
+ message = await self.bot.wait_for("message", check=author_check, timeout=TIMEOUT)
except TimeoutError:
timeout_embed = discord.Embed(
title=choice(NEGATIVE_REPLIES),
@@ -143,6 +143,6 @@ class Madlibs(commands.Cog):
error.handled = True
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Madlibs cog."""
- bot.add_cog(Madlibs(bot))
+ await bot.add_cog(Madlibs(bot))
diff --git a/bot/exts/fun/magic_8ball.py b/bot/exts/fun/magic_8ball.py
index a7b682ca..95d711c4 100644
--- a/bot/exts/fun/magic_8ball.py
+++ b/bot/exts/fun/magic_8ball.py
@@ -25,6 +25,6 @@ class Magic8ball(commands.Cog):
await ctx.send("Usage: .8ball <question> (minimum length of 3 eg: `will I win?`)")
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Magic8Ball Cog."""
- bot.add_cog(Magic8ball())
+ await bot.add_cog(Magic8ball())
diff --git a/bot/exts/fun/minesweeper.py b/bot/exts/fun/minesweeper.py
index a48b5051..f16b1db2 100644
--- a/bot/exts/fun/minesweeper.py
+++ b/bot/exts/fun/minesweeper.py
@@ -11,7 +11,6 @@ from bot.bot import Bot
from bot.constants import Client
from bot.utils.converters import CoordinateConverter
from bot.utils.exceptions import UserNotPlayingError
-from bot.utils.extensions import invoke_help_command
MESSAGE_MAPPING = {
0: ":stop_button:",
@@ -51,13 +50,14 @@ class Game:
class Minesweeper(commands.Cog):
"""Play a game of Minesweeper."""
- def __init__(self):
+ def __init__(self, bot: Bot):
+ self.bot = bot
self.games: dict[int, Game] = {}
@commands.group(name="minesweeper", aliases=("ms",), invoke_without_command=True)
async def minesweeper_group(self, ctx: commands.Context) -> None:
"""Commands for Playing Minesweeper."""
- await invoke_help_command(ctx)
+ await self.bot.invoke_help_command(ctx)
@staticmethod
def get_neighbours(x: int, y: int) -> Iterator[tuple[int, int]]:
@@ -265,6 +265,6 @@ class Minesweeper(commands.Cog):
del self.games[ctx.author.id]
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Minesweeper cog."""
- bot.add_cog(Minesweeper())
+ await bot.add_cog(Minesweeper(bot))
diff --git a/bot/exts/fun/movie.py b/bot/exts/fun/movie.py
index a04eeb41..422a83ac 100644
--- a/bot/exts/fun/movie.py
+++ b/bot/exts/fun/movie.py
@@ -9,13 +9,16 @@ from discord.ext.commands import Cog, Context, group
from bot.bot import Bot
from bot.constants import Tokens
-from bot.utils.extensions import invoke_help_command
+from bot.utils.exceptions import APIError
from bot.utils.pagination import ImagePaginator
+logger = logging.getLogger(__name__)
+
# Define base URL of TMDB
BASE_URL = "https://api.themoviedb.org/3/"
-logger = logging.getLogger(__name__)
+# Logo of TMDB
+THUMBNAIL_URL = "https://i.imgur.com/LtFtC8H.png"
# Define movie params, that will be used for every movie request
MOVIE_PARAMS = {
@@ -23,6 +26,10 @@ MOVIE_PARAMS = {
"language": "en-US"
}
+# Maximum value for `pages` API parameter. The maximum is documented as 1000 but
+# anything over 500 returns an error.
+MAX_PAGES = 500
+
class MovieGenres(Enum):
"""Movies Genre names and IDs."""
@@ -50,12 +57,14 @@ class Movie(Cog):
"""Movie Cog contains movies command that grab random movies from TMDB."""
def __init__(self, bot: Bot):
+ self.bot = bot
self.http_session: ClientSession = bot.http_session
@group(name="movies", aliases=("movie",), invoke_without_command=True)
async def movies(self, ctx: Context, genre: str = "", amount: int = 5) -> None:
"""
- Get random movies by specifying genre. Also support amount parameter, that define how much movies will be shown.
+ Get random movies by specifying genre. Also support amount parameter,\
+ that define how much movies will be shown.
Default 5. Use .movies genres to get all available genres.
"""
@@ -73,28 +82,14 @@ class Movie(Cog):
try:
result = await self.get_movies_data(self.http_session, MovieGenres[genre].value, 1)
except KeyError:
- await invoke_help_command(ctx)
+ await self.bot.invoke_help_command(ctx)
return
- # Check if "results" is in result. If not, throw error.
- if "results" not in result:
- err_msg = (
- f"There is problem while making TMDB API request. Response Code: {result['status_code']}, "
- f"{result['status_message']}."
- )
- await ctx.send(err_msg)
- logger.warning(err_msg)
-
# Get random page. Max page is last page where is movies with this genre.
- page = random.randint(1, result["total_pages"])
+ page = random.randint(1, min(result["total_pages"], MAX_PAGES))
# Get movies list from TMDB, check if results key in result. When not, raise error.
movies = await self.get_movies_data(self.http_session, MovieGenres[genre].value, page)
- if "results" not in movies:
- err_msg = f"There is problem while making TMDB API request. Response Code: {result['status_code']}, " \
- f"{result['status_message']}."
- await ctx.send(err_msg)
- logger.warning(err_msg)
# Get all pages and embed
pages = await self.get_pages(self.http_session, movies, amount)
@@ -124,7 +119,18 @@ class Movie(Cog):
# Make discover request to TMDB, return result
async with client.get(url, params=params) as resp:
- return await resp.json()
+ result, status = await resp.json(), resp.status
+ # Check if "results" is in result. If not, throw error.
+ if "results" not in result:
+ err_msg = (
+ f"There was a problem making the TMDB API request. Response Code: {status}, "
+ f"TMDB: Status Code: {result.get('status_code', None)} "
+ f"TMDB: Status Message: {result.get('status_message', None)}, "
+ f"TMDB: Errors: {result.get('errors', None)}, "
+ )
+ logger.error(err_msg)
+ raise APIError("TMDB API", status, err_msg)
+ return result
async def get_pages(self, client: ClientSession, movies: dict[str, Any], amount: int) -> list[tuple[str, str]]:
"""Fetch all movie pages from movies dictionary. Return list of pages."""
@@ -196,10 +202,10 @@ class Movie(Cog):
"""Return embed of random movies. Uses name in title."""
embed = Embed(title=f"Random {name} Movies")
embed.set_footer(text="This product uses the TMDb API but is not endorsed or certified by TMDb.")
- embed.set_thumbnail(url="https://i.imgur.com/LtFtC8H.png")
+ embed.set_thumbnail(url=THUMBNAIL_URL)
return embed
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Movie Cog."""
- bot.add_cog(Movie(bot))
+ await bot.add_cog(Movie(bot))
diff --git a/bot/exts/fun/quack.py b/bot/exts/fun/quack.py
index 0c228aed..bb0cd731 100644
--- a/bot/exts/fun/quack.py
+++ b/bot/exts/fun/quack.py
@@ -50,13 +50,12 @@ class Quackstack(commands.Cog):
description="The request failed. Please try again later.",
color=Colours.soft_red,
)
- if response.status != 200:
+ if response.status != 201:
log.error(f"Response to Quackstack returned code {response.status}")
await ctx.send(embed=error_embed)
return
- data = await response.json()
- file = data["file"]
+ file = response.headers["Location"]
embed = discord.Embed(
title=f"Quack! Here's a {ducktype} for you.",
@@ -65,11 +64,11 @@ class Quackstack(commands.Cog):
url=f"{API_URL}/docs"
)
- embed.set_image(url=API_URL + file)
+ embed.set_image(url=file)
await ctx.send(embed=embed)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Loads the Quack cog."""
- bot.add_cog(Quackstack(bot))
+ await bot.add_cog(Quackstack(bot))
diff --git a/bot/exts/fun/recommend_game.py b/bot/exts/fun/recommend_game.py
index 42c9f7c2..e972b9a5 100644
--- a/bot/exts/fun/recommend_game.py
+++ b/bot/exts/fun/recommend_game.py
@@ -46,6 +46,6 @@ class RecommendGame(commands.Cog):
await ctx.send(embed=embed)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Loads the RecommendGame cog."""
- bot.add_cog(RecommendGame(bot))
+ await bot.add_cog(RecommendGame(bot))
diff --git a/bot/exts/fun/rps.py b/bot/exts/fun/rps.py
index c6bbff46..50129835 100644
--- a/bot/exts/fun/rps.py
+++ b/bot/exts/fun/rps.py
@@ -52,6 +52,6 @@ class RPS(commands.Cog):
await ctx.send(f"Sir Lancebot played {bot_move}! {player_mention} lost!")
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the RPS Cog."""
- bot.add_cog(RPS(bot))
+ await bot.add_cog(RPS(bot))
diff --git a/bot/exts/fun/snakes/__init__.py b/bot/exts/fun/snakes/__init__.py
index ba8333fd..8aa39fb5 100644
--- a/bot/exts/fun/snakes/__init__.py
+++ b/bot/exts/fun/snakes/__init__.py
@@ -6,6 +6,6 @@ from bot.exts.fun.snakes._snakes_cog import Snakes
log = logging.getLogger(__name__)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Snakes Cog."""
- bot.add_cog(Snakes(bot))
+ await bot.add_cog(Snakes(bot))
diff --git a/bot/exts/fun/snakes/_snakes_cog.py b/bot/exts/fun/snakes/_snakes_cog.py
index 59e57199..96718200 100644
--- a/bot/exts/fun/snakes/_snakes_cog.py
+++ b/bot/exts/fun/snakes/_snakes_cog.py
@@ -22,7 +22,6 @@ from bot.constants import ERROR_REPLIES, Tokens
from bot.exts.fun.snakes import _utils as utils
from bot.exts.fun.snakes._converter import Snake
from bot.utils.decorators import locked
-from bot.utils.extensions import invoke_help_command
log = logging.getLogger(__name__)
@@ -440,7 +439,7 @@ class Snakes(Cog):
@group(name="snakes", aliases=("snake",), invoke_without_command=True)
async def snakes_group(self, ctx: Context) -> None:
"""Commands from our first code jam."""
- await invoke_help_command(ctx)
+ await self.bot.invoke_help_command(ctx)
@bot_has_permissions(manage_messages=True)
@snakes_group.command(name="antidote")
diff --git a/bot/exts/fun/space.py b/bot/exts/fun/space.py
index 48ad0f96..22a89050 100644
--- a/bot/exts/fun/space.py
+++ b/bot/exts/fun/space.py
@@ -11,7 +11,6 @@ from discord.ext.commands import Cog, Context, group
from bot.bot import Bot
from bot.constants import Tokens
from bot.utils.converters import DateConverter
-from bot.utils.extensions import invoke_help_command
logger = logging.getLogger(__name__)
@@ -27,6 +26,7 @@ class Space(Cog):
def __init__(self, bot: Bot):
self.http_session = bot.http_session
+ self.bot = bot
self.rovers = {}
self.get_rovers.start()
@@ -50,7 +50,7 @@ class Space(Cog):
@group(name="space", invoke_without_command=True)
async def space(self, ctx: Context) -> None:
"""Head command that contains commands about space."""
- await invoke_help_command(ctx)
+ await self.bot.invoke_help_command(ctx)
@space.command(name="apod")
async def apod(self, ctx: Context, date: Optional[str]) -> None:
@@ -227,10 +227,10 @@ class Space(Cog):
).set_image(url=image).set_footer(text="Powered by NASA API" + footer)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Space cog."""
if not Tokens.nasa:
logger.warning("Can't find NASA API key. Not loading Space Cog.")
return
- bot.add_cog(Space(bot))
+ await bot.add_cog(Space(bot))
diff --git a/bot/exts/fun/speedrun.py b/bot/exts/fun/speedrun.py
index c2966ce1..43e570a2 100644
--- a/bot/exts/fun/speedrun.py
+++ b/bot/exts/fun/speedrun.py
@@ -21,6 +21,6 @@ class Speedrun(commands.Cog):
await ctx.send(choice(LINKS))
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Speedrun cog."""
- bot.add_cog(Speedrun())
+ await bot.add_cog(Speedrun())
diff --git a/bot/exts/fun/status_codes.py b/bot/exts/fun/status_codes.py
index 501cbe0a..cf544a19 100644
--- a/bot/exts/fun/status_codes.py
+++ b/bot/exts/fun/status_codes.py
@@ -82,6 +82,6 @@ class HTTPStatusCodes(commands.Cog):
)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the HTTPStatusCodes cog."""
- bot.add_cog(HTTPStatusCodes(bot))
+ await bot.add_cog(HTTPStatusCodes(bot))
diff --git a/bot/exts/fun/tic_tac_toe.py b/bot/exts/fun/tic_tac_toe.py
index 5dd38a81..fa2a7531 100644
--- a/bot/exts/fun/tic_tac_toe.py
+++ b/bot/exts/fun/tic_tac_toe.py
@@ -333,6 +333,6 @@ class TicTacToe(Cog):
await ctx.send(embed=embed)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the TicTacToe cog."""
- bot.add_cog(TicTacToe())
+ await bot.add_cog(TicTacToe())
diff --git a/bot/exts/fun/trivia_quiz.py b/bot/exts/fun/trivia_quiz.py
index 4a1cec5b..31652374 100644
--- a/bot/exts/fun/trivia_quiz.py
+++ b/bot/exts/fun/trivia_quiz.py
@@ -435,7 +435,7 @@ class TriviaQuiz(commands.Cog):
def contains_correct_answer(m: discord.Message) -> bool:
return m.channel == ctx.channel and any(
fuzz.ratio(answer.lower(), m.content.lower()) > variation_tolerance
- for answer in quiz_entry.answers
+ for answer in quiz_entry.answers # noqa: B023
)
return contains_correct_answer
@@ -670,6 +670,6 @@ class TriviaQuiz(commands.Cog):
await channel.send(embed=embed)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the TriviaQuiz cog."""
- bot.add_cog(TriviaQuiz(bot))
+ await bot.add_cog(TriviaQuiz(bot))
diff --git a/bot/exts/fun/uwu.py b/bot/exts/fun/uwu.py
index 83497893..7a9d55d0 100644
--- a/bot/exts/fun/uwu.py
+++ b/bot/exts/fun/uwu.py
@@ -199,6 +199,6 @@ class Uwu(Cog):
await ctx.send(content=converted_text, embed=embed)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the uwu cog."""
- bot.add_cog(Uwu(bot))
+ await bot.add_cog(Uwu(bot))
diff --git a/bot/exts/fun/wonder_twins.py b/bot/exts/fun/wonder_twins.py
index 79d6b6d9..0c5b0a76 100644
--- a/bot/exts/fun/wonder_twins.py
+++ b/bot/exts/fun/wonder_twins.py
@@ -44,6 +44,6 @@ class WonderTwins(Cog):
await ctx.send(f"Form of {self.format_phrase()}!")
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the WonderTwins cog."""
- bot.add_cog(WonderTwins())
+ await bot.add_cog(WonderTwins())
diff --git a/bot/exts/fun/xkcd.py b/bot/exts/fun/xkcd.py
index b56c53d9..380c3c80 100644
--- a/bot/exts/fun/xkcd.py
+++ b/bot/exts/fun/xkcd.py
@@ -86,6 +86,6 @@ class XKCD(Cog):
await ctx.send(embed=embed)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the XKCD cog."""
- bot.add_cog(XKCD(bot))
+ await bot.add_cog(XKCD(bot))
diff --git a/bot/exts/holidays/earth_day/save_the_planet.py b/bot/exts/holidays/earth_day/save_the_planet.py
index 13c84886..63836faf 100644
--- a/bot/exts/holidays/earth_day/save_the_planet.py
+++ b/bot/exts/holidays/earth_day/save_the_planet.py
@@ -20,6 +20,6 @@ class SaveThePlanet(commands.Cog):
await ctx.send(embed=return_embed)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Save the Planet Cog."""
- bot.add_cog(SaveThePlanet())
+ await bot.add_cog(SaveThePlanet())
diff --git a/bot/exts/holidays/easter/april_fools_vids.py b/bot/exts/holidays/easter/april_fools_vids.py
index ae22f751..7f46a569 100644
--- a/bot/exts/holidays/easter/april_fools_vids.py
+++ b/bot/exts/holidays/easter/april_fools_vids.py
@@ -25,6 +25,6 @@ class AprilFoolVideos(commands.Cog):
await ctx.send(f"Check out this April Fools' video by {channel}.\n\n{url}")
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the April Fools' Cog."""
- bot.add_cog(AprilFoolVideos())
+ await bot.add_cog(AprilFoolVideos())
diff --git a/bot/exts/holidays/easter/bunny_name_generator.py b/bot/exts/holidays/easter/bunny_name_generator.py
index f767f7c5..50872ebc 100644
--- a/bot/exts/holidays/easter/bunny_name_generator.py
+++ b/bot/exts/holidays/easter/bunny_name_generator.py
@@ -89,6 +89,6 @@ class BunnyNameGenerator(commands.Cog):
await ctx.send(bunnified_name)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Bunny Name Generator Cog."""
- bot.add_cog(BunnyNameGenerator())
+ await bot.add_cog(BunnyNameGenerator())
diff --git a/bot/exts/holidays/easter/earth_photos.py b/bot/exts/holidays/easter/earth_photos.py
index 27442f1c..e60e2626 100644
--- a/bot/exts/holidays/easter/earth_photos.py
+++ b/bot/exts/holidays/easter/earth_photos.py
@@ -57,9 +57,9 @@ class EarthPhotos(commands.Cog):
await ctx.send(embed=embed)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Earth Photos cog."""
if not Tokens.unsplash_access_key:
log.warning("No Unsplash access key found. Cog not loading.")
return
- bot.add_cog(EarthPhotos(bot))
+ await bot.add_cog(EarthPhotos(bot))
diff --git a/bot/exts/holidays/easter/easter_riddle.py b/bot/exts/holidays/easter/easter_riddle.py
index c9b7fc53..c5d7b164 100644
--- a/bot/exts/holidays/easter/easter_riddle.py
+++ b/bot/exts/holidays/easter/easter_riddle.py
@@ -107,6 +107,6 @@ class EasterRiddle(commands.Cog):
self.winners.add(message.author.mention)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Easter Riddle Cog load."""
- bot.add_cog(EasterRiddle(bot))
+ await bot.add_cog(EasterRiddle(bot))
diff --git a/bot/exts/holidays/easter/egg_decorating.py b/bot/exts/holidays/easter/egg_decorating.py
index 1db9b347..a9334820 100644
--- a/bot/exts/holidays/easter/egg_decorating.py
+++ b/bot/exts/holidays/easter/egg_decorating.py
@@ -114,6 +114,6 @@ class EggDecorating(commands.Cog):
return new_im
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Egg decorating Cog."""
- bot.add_cog(EggDecorating())
+ await bot.add_cog(EggDecorating())
diff --git a/bot/exts/holidays/easter/egg_facts.py b/bot/exts/holidays/easter/egg_facts.py
index 152af6a4..43b31c7b 100644
--- a/bot/exts/holidays/easter/egg_facts.py
+++ b/bot/exts/holidays/easter/egg_facts.py
@@ -29,8 +29,6 @@ class EasterFacts(commands.Cog):
@seasonal_task(Month.APRIL)
async def send_egg_fact_daily(self) -> None:
"""A background task that sends an easter egg fact in the event channel everyday."""
- await self.bot.wait_until_guild_available()
-
channel = self.bot.get_channel(Channels.sir_lancebot_playground)
await channel.send(embed=self.make_embed())
@@ -50,6 +48,6 @@ class EasterFacts(commands.Cog):
)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Easter Egg facts Cog."""
- bot.add_cog(EasterFacts(bot))
+ await bot.add_cog(EasterFacts(bot))
diff --git a/bot/exts/holidays/easter/egghead_quiz.py b/bot/exts/holidays/easter/egghead_quiz.py
index 06229537..2e4d1931 100644
--- a/bot/exts/holidays/easter/egghead_quiz.py
+++ b/bot/exts/holidays/easter/egghead_quiz.py
@@ -65,23 +65,47 @@ class EggheadQuiz(commands.Cog):
msg = await ctx.fetch_message(msg.id) # Refreshes message
- total_no = sum([len(await r.users().flatten()) for r in msg.reactions]) - len(valid_emojis) # - bot's reactions
+ users = []
+ for reaction in msg.reactions:
+ async for user in reaction.users():
+ users.append(user)
+
+ total_no = len(users) - len(valid_emojis) # - bot's reactions
if total_no == 0:
return await msg.delete() # To avoid ZeroDivisionError if nobody reacts
results = ["**VOTES:**"]
for emoji, _ in answers:
- num = [len(await r.users().flatten()) for r in msg.reactions if str(r.emoji) == emoji][0] - 1
+ users = []
+ for reaction in msg.reactions:
+ if str(reaction.emoji) != emoji:
+ continue
+
+ async for user in reaction.users():
+ users.append(user)
+ break
+
+ num = len(users) - 1
percent = round(100 * num / total_no)
s = "" if num == 1 else "s"
string = f"{emoji} - {num} vote{s} ({percent}%)"
results.append(string)
+ users = []
+ for reaction in msg.reactions:
+ if str(reaction.emoji) != correct:
+ continue
+
+ async for user in reaction.users():
+ users.append(user)
+
+ # At this point we've added everyone who reacted
+ # with the correct answer, so stop looping over reactions.
+ break
+
mentions = " ".join([
- u.mention for u in [
- await r.users().flatten() for r in msg.reactions if str(r.emoji) == correct
- ][0] if not u.bot
+ u.mention for u in users if not u.bot
])
content = f"Well done {mentions} for getting it correct!" if mentions else "Nobody got it right..."
@@ -95,10 +119,16 @@ class EggheadQuiz(commands.Cog):
await ctx.send(content, embed=a_embed)
@staticmethod
- async def already_reacted(message: discord.Message, user: Union[discord.Member, discord.User]) -> bool:
+ async def already_reacted(new_reaction: discord.Reaction, user: Union[discord.Member, discord.User]) -> bool:
"""Returns whether a given user has reacted more than once to a given message."""
- users = [u.id for reaction in [await r.users().flatten() for r in message.reactions] for u in reaction]
- return users.count(user.id) > 1 # Old reaction plus new reaction
+ message = new_reaction.message
+ for reaction in message.reactions:
+ if reaction.emoji == new_reaction.emoji:
+ continue # can't react with same emoji twice so skip 2nd reaction check
+ async for usr in reaction.users():
+ if usr.id == user.id: # user also reacted with the emoji, i.e. has already reacted
+ return True
+ return False
@commands.Cog.listener()
async def on_reaction_add(self, reaction: discord.Reaction, user: Union[discord.Member, discord.User]) -> None:
@@ -109,10 +139,10 @@ class EggheadQuiz(commands.Cog):
return
if str(reaction.emoji) not in self.quiz_messages[reaction.message.id]:
return await reaction.message.remove_reaction(reaction, user)
- if await self.already_reacted(reaction.message, user):
+ if await self.already_reacted(reaction, user):
return await reaction.message.remove_reaction(reaction, user)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Egghead Quiz Cog."""
- bot.add_cog(EggheadQuiz())
+ await bot.add_cog(EggheadQuiz())
diff --git a/bot/exts/holidays/easter/traditions.py b/bot/exts/holidays/easter/traditions.py
index f54ab5c4..3ac5617c 100644
--- a/bot/exts/holidays/easter/traditions.py
+++ b/bot/exts/holidays/easter/traditions.py
@@ -23,6 +23,6 @@ class Traditions(commands.Cog):
await ctx.send(f"{random_country}:\n{traditions[random_country]}")
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Traditions Cog."""
- bot.add_cog(Traditions())
+ await bot.add_cog(Traditions())
diff --git a/bot/exts/holidays/halloween/8ball.py b/bot/exts/holidays/halloween/8ball.py
index 4fec8463..21b55a01 100644
--- a/bot/exts/holidays/halloween/8ball.py
+++ b/bot/exts/holidays/halloween/8ball.py
@@ -26,6 +26,6 @@ class SpookyEightBall(commands.Cog):
await msg.edit(content=f"{choice[0]} \n{choice[1]}")
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Spooky Eight Ball Cog."""
- bot.add_cog(SpookyEightBall())
+ await bot.add_cog(SpookyEightBall())
diff --git a/bot/exts/holidays/halloween/candy_collection.py b/bot/exts/holidays/halloween/candy_collection.py
index 220ba8e5..683114f9 100644
--- a/bot/exts/holidays/halloween/candy_collection.py
+++ b/bot/exts/holidays/halloween/candy_collection.py
@@ -88,10 +88,7 @@ class CandyCollection(commands.Cog):
if message.author.bot:
return
- recent_message_ids = map(
- lambda m: m.id,
- await self.hacktober_channel.history(limit=10).flatten()
- )
+ recent_message_ids = [message.id async for message in self.hacktober_channel.history(limit=10)]
if message.id in recent_message_ids:
await self.reacted_msg_chance(message)
return
@@ -214,6 +211,6 @@ class CandyCollection(commands.Cog):
await ctx.send(embed=e)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Candy Collection Cog."""
- bot.add_cog(CandyCollection(bot))
+ await bot.add_cog(CandyCollection(bot))
diff --git a/bot/exts/holidays/halloween/halloween_facts.py b/bot/exts/holidays/halloween/halloween_facts.py
index adde2310..a0d63f64 100644
--- a/bot/exts/holidays/halloween/halloween_facts.py
+++ b/bot/exts/holidays/halloween/halloween_facts.py
@@ -50,6 +50,6 @@ class HalloweenFacts(commands.Cog):
return discord.Embed(title=title, description=fact, color=PUMPKIN_ORANGE)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Halloween Facts Cog."""
- bot.add_cog(HalloweenFacts())
+ await bot.add_cog(HalloweenFacts())
diff --git a/bot/exts/holidays/halloween/halloweenify.py b/bot/exts/holidays/halloween/halloweenify.py
index 03b52589..a16ea6cc 100644
--- a/bot/exts/holidays/halloween/halloweenify.py
+++ b/bot/exts/holidays/halloween/halloweenify.py
@@ -59,6 +59,6 @@ class Halloweenify(commands.Cog):
await ctx.send(embed=embed)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Halloweenify Cog."""
- bot.add_cog(Halloweenify())
+ await bot.add_cog(Halloweenify())
diff --git a/bot/exts/holidays/halloween/monsterbio.py b/bot/exts/holidays/halloween/monsterbio.py
index 0556a193..8e83e9d1 100644
--- a/bot/exts/holidays/halloween/monsterbio.py
+++ b/bot/exts/holidays/halloween/monsterbio.py
@@ -49,6 +49,6 @@ class MonsterBio(commands.Cog):
await ctx.send(embed=embed)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Monster Bio Cog."""
- bot.add_cog(MonsterBio())
+ await bot.add_cog(MonsterBio())
diff --git a/bot/exts/holidays/halloween/monstersurvey.py b/bot/exts/holidays/halloween/monstersurvey.py
index f3433886..517f1bcb 100644
--- a/bot/exts/holidays/halloween/monstersurvey.py
+++ b/bot/exts/holidays/halloween/monstersurvey.py
@@ -200,6 +200,6 @@ class MonsterSurvey(Cog):
await ctx.send(embed=embed)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Monster Survey Cog."""
- bot.add_cog(MonsterSurvey())
+ await bot.add_cog(MonsterSurvey())
diff --git a/bot/exts/holidays/halloween/scarymovie.py b/bot/exts/holidays/halloween/scarymovie.py
index 89310b97..74bcef90 100644
--- a/bot/exts/holidays/halloween/scarymovie.py
+++ b/bot/exts/holidays/halloween/scarymovie.py
@@ -120,6 +120,6 @@ class ScaryMovie(commands.Cog):
return embed
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Scary Movie Cog."""
- bot.add_cog(ScaryMovie(bot))
+ await bot.add_cog(ScaryMovie(bot))
diff --git a/bot/exts/holidays/halloween/spookygif.py b/bot/exts/holidays/halloween/spookygif.py
index 9511d407..750e86ca 100644
--- a/bot/exts/holidays/halloween/spookygif.py
+++ b/bot/exts/holidays/halloween/spookygif.py
@@ -25,7 +25,7 @@ class SpookyGif(commands.Cog):
# Make a GET request to the Giphy API to get a random halloween gif.
async with self.bot.http_session.get(API_URL, params=params) as resp:
data = await resp.json()
- url = data["data"]["image_url"]
+ url = data["data"]["images"]["downsized"]["url"]
embed = discord.Embed(title="A spooooky gif!", colour=Colours.purple)
embed.set_image(url=url)
@@ -33,6 +33,6 @@ class SpookyGif(commands.Cog):
await ctx.send(embed=embed)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Spooky GIF Cog load."""
- bot.add_cog(SpookyGif(bot))
+ await bot.add_cog(SpookyGif(bot))
diff --git a/bot/exts/holidays/halloween/spookynamerate.py b/bot/exts/holidays/halloween/spookynamerate.py
index 02fb71c3..a76e5e12 100644
--- a/bot/exts/holidays/halloween/spookynamerate.py
+++ b/bot/exts/holidays/halloween/spookynamerate.py
@@ -95,8 +95,6 @@ class SpookyNameRate(Cog):
self.bot = bot
self.name = None
- self.bot.loop.create_task(self.load_vars())
-
self.first_time = None
self.poll = False
self.announce_name.start()
@@ -104,7 +102,7 @@ class SpookyNameRate(Cog):
# Define an asyncio.Lock() to make sure the dictionary isn't changed
# when checking the messages for duplicate emojis'
- async def load_vars(self) -> None:
+ async def cog_load(self) -> None:
"""Loads the variables that couldn't be loaded in __init__."""
self.first_time = await self.data.get("first_time", True)
self.name = await self.data.get("name")
@@ -357,7 +355,6 @@ class SpookyNameRate(Cog):
async def get_channel(self) -> Optional[TextChannel]:
"""Gets the sir-lancebot-channel after waiting until ready."""
- await self.bot.wait_until_ready()
channel = self.bot.get_channel(
Channels.sir_lancebot_playground
) or await self.bot.fetch_channel(Channels.sir_lancebot_playground)
@@ -386,6 +383,6 @@ class SpookyNameRate(Cog):
self.announce_name.cancel()
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the SpookyNameRate Cog."""
- bot.add_cog(SpookyNameRate(bot))
+ await bot.add_cog(SpookyNameRate(bot))
diff --git a/bot/exts/holidays/halloween/spookyrating.py b/bot/exts/holidays/halloween/spookyrating.py
index ec6e8821..373b6583 100644
--- a/bot/exts/holidays/halloween/spookyrating.py
+++ b/bot/exts/holidays/halloween/spookyrating.py
@@ -62,6 +62,6 @@ class SpookyRating(commands.Cog):
await ctx.send(embed=embed)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Spooky Rating Cog."""
- bot.add_cog(SpookyRating())
+ await bot.add_cog(SpookyRating())
diff --git a/bot/exts/holidays/halloween/spookyreact.py b/bot/exts/holidays/halloween/spookyreact.py
index e228b91d..945bde33 100644
--- a/bot/exts/holidays/halloween/spookyreact.py
+++ b/bot/exts/holidays/halloween/spookyreact.py
@@ -17,7 +17,8 @@ SPOOKY_TRIGGERS = {
"pumpkin": (r"\bpumpkin\b", "\U0001F383"),
"halloween": (r"\bhalloween\b", "\U0001F383"),
"jack-o-lantern": (r"\bjack-o-lantern\b", "\U0001F383"),
- "danger": (r"\bdanger\b", "\U00002620")
+ "danger": (r"\bdanger\b", "\U00002620"),
+ "bat": (r"\bbat((wo)?m[ae]n|persons?|people|s)?\b", "\U0001F987"),
}
@@ -65,6 +66,6 @@ class SpookyReact(Cog):
return False
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Spooky Reaction Cog."""
- bot.add_cog(SpookyReact(bot))
+ await bot.add_cog(SpookyReact(bot))
diff --git a/bot/exts/holidays/hanukkah/hanukkah_embed.py b/bot/exts/holidays/hanukkah/hanukkah_embed.py
index 5767f91e..1ebc21e8 100644
--- a/bot/exts/holidays/hanukkah/hanukkah_embed.py
+++ b/bot/exts/holidays/hanukkah/hanukkah_embed.py
@@ -96,6 +96,6 @@ class HanukkahEmbed(commands.Cog):
await ctx.send(embed=embed)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Hanukkah Embed Cog."""
- bot.add_cog(HanukkahEmbed(bot))
+ await bot.add_cog(HanukkahEmbed(bot))
diff --git a/bot/exts/holidays/pride/drag_queen_name.py b/bot/exts/holidays/pride/drag_queen_name.py
index bd01a603..0c1ca6fb 100644
--- a/bot/exts/holidays/pride/drag_queen_name.py
+++ b/bot/exts/holidays/pride/drag_queen_name.py
@@ -21,6 +21,6 @@ class DragNames(commands.Cog):
await ctx.send(random.choice(NAMES))
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Drag Names Cog."""
- bot.add_cog(DragNames())
+ await bot.add_cog(DragNames())
diff --git a/bot/exts/holidays/pride/pride_anthem.py b/bot/exts/holidays/pride/pride_anthem.py
index e8a4563b..6b78cba1 100644
--- a/bot/exts/holidays/pride/pride_anthem.py
+++ b/bot/exts/holidays/pride/pride_anthem.py
@@ -46,6 +46,6 @@ class PrideAnthem(commands.Cog):
await ctx.send("I couldn't find a video, sorry!")
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Pride Anthem Cog."""
- bot.add_cog(PrideAnthem())
+ await bot.add_cog(PrideAnthem())
diff --git a/bot/exts/holidays/pride/pride_facts.py b/bot/exts/holidays/pride/pride_facts.py
index 340f0b43..36a9415e 100644
--- a/bot/exts/holidays/pride/pride_facts.py
+++ b/bot/exts/holidays/pride/pride_facts.py
@@ -28,8 +28,6 @@ class PrideFacts(commands.Cog):
@seasonal_task(Month.JUNE)
async def send_pride_fact_daily(self) -> None:
"""Background task to post the daily pride fact every day."""
- await self.bot.wait_until_guild_available()
-
channel = self.bot.get_channel(Channels.sir_lancebot_playground)
await self.send_select_fact(channel, datetime.utcnow())
@@ -94,6 +92,6 @@ class PrideFacts(commands.Cog):
)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Pride Facts Cog."""
- bot.add_cog(PrideFacts(bot))
+ await bot.add_cog(PrideFacts(bot))
diff --git a/bot/exts/holidays/pride/pride_leader.py b/bot/exts/holidays/pride/pride_leader.py
index adf01134..120e9e16 100644
--- a/bot/exts/holidays/pride/pride_leader.py
+++ b/bot/exts/holidays/pride/pride_leader.py
@@ -112,6 +112,6 @@ class PrideLeader(commands.Cog):
await ctx.send(embed=embed)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Pride Leader Cog."""
- bot.add_cog(PrideLeader(bot))
+ await bot.add_cog(PrideLeader(bot))
diff --git a/bot/exts/holidays/valentines/be_my_valentine.py b/bot/exts/holidays/valentines/be_my_valentine.py
index cbb95157..5ffd14e6 100644
--- a/bot/exts/holidays/valentines/be_my_valentine.py
+++ b/bot/exts/holidays/valentines/be_my_valentine.py
@@ -163,6 +163,6 @@ class BeMyValentine(commands.Cog):
return random.choice(self.valentines["valentine_compliments"])
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Be my Valentine Cog."""
- bot.add_cog(BeMyValentine(bot))
+ await bot.add_cog(BeMyValentine(bot))
diff --git a/bot/exts/holidays/valentines/lovecalculator.py b/bot/exts/holidays/valentines/lovecalculator.py
index 10dea9df..c212e833 100644
--- a/bot/exts/holidays/valentines/lovecalculator.py
+++ b/bot/exts/holidays/valentines/lovecalculator.py
@@ -95,6 +95,6 @@ class LoveCalculator(Cog):
await ctx.send(embed=embed)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Love calculator Cog."""
- bot.add_cog(LoveCalculator())
+ await bot.add_cog(LoveCalculator())
diff --git a/bot/exts/holidays/valentines/movie_generator.py b/bot/exts/holidays/valentines/movie_generator.py
index d2dc8213..64b86f1b 100644
--- a/bot/exts/holidays/valentines/movie_generator.py
+++ b/bot/exts/holidays/valentines/movie_generator.py
@@ -62,6 +62,6 @@ class RomanceMovieFinder(commands.Cog):
await ctx.send(embed=embed)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Romance movie Cog."""
- bot.add_cog(RomanceMovieFinder(bot))
+ await bot.add_cog(RomanceMovieFinder(bot))
diff --git a/bot/exts/holidays/valentines/myvalenstate.py b/bot/exts/holidays/valentines/myvalenstate.py
index 4b547d9b..8d8772d4 100644
--- a/bot/exts/holidays/valentines/myvalenstate.py
+++ b/bot/exts/holidays/valentines/myvalenstate.py
@@ -77,6 +77,6 @@ class MyValenstate(commands.Cog):
await ctx.send(embed=embed)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Valenstate Cog."""
- bot.add_cog(MyValenstate())
+ await bot.add_cog(MyValenstate())
diff --git a/bot/exts/holidays/valentines/pickuplines.py b/bot/exts/holidays/valentines/pickuplines.py
index bc4b88c6..8562a07d 100644
--- a/bot/exts/holidays/valentines/pickuplines.py
+++ b/bot/exts/holidays/valentines/pickuplines.py
@@ -36,6 +36,6 @@ class PickupLine(commands.Cog):
await ctx.send(embed=embed)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Pickup lines Cog."""
- bot.add_cog(PickupLine())
+ await bot.add_cog(PickupLine())
diff --git a/bot/exts/holidays/valentines/savethedate.py b/bot/exts/holidays/valentines/savethedate.py
index 3638c1ef..7fd644df 100644
--- a/bot/exts/holidays/valentines/savethedate.py
+++ b/bot/exts/holidays/valentines/savethedate.py
@@ -33,6 +33,6 @@ class SaveTheDate(commands.Cog):
await ctx.send(embed=embed)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Save the date Cog."""
- bot.add_cog(SaveTheDate())
+ await bot.add_cog(SaveTheDate())
diff --git a/bot/exts/holidays/valentines/valentine_zodiac.py b/bot/exts/holidays/valentines/valentine_zodiac.py
index d1b3a630..0a28a5c5 100644
--- a/bot/exts/holidays/valentines/valentine_zodiac.py
+++ b/bot/exts/holidays/valentines/valentine_zodiac.py
@@ -141,6 +141,6 @@ class ValentineZodiac(commands.Cog):
log.trace("Embed from date successfully sent.")
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Valentine zodiac Cog."""
- bot.add_cog(ValentineZodiac())
+ await bot.add_cog(ValentineZodiac())
diff --git a/bot/exts/holidays/valentines/whoisvalentine.py b/bot/exts/holidays/valentines/whoisvalentine.py
index 67e46aa4..c652e616 100644
--- a/bot/exts/holidays/valentines/whoisvalentine.py
+++ b/bot/exts/holidays/valentines/whoisvalentine.py
@@ -44,6 +44,6 @@ class ValentineFacts(commands.Cog):
await ctx.send(embed=embed)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Who is Valentine Cog."""
- bot.add_cog(ValentineFacts())
+ await bot.add_cog(ValentineFacts())
diff --git a/bot/exts/utilities/bookmark.py b/bot/exts/utilities/bookmark.py
index 9eb23988..50e3038f 100644
--- a/bot/exts/utilities/bookmark.py
+++ b/bot/exts/utilities/bookmark.py
@@ -189,6 +189,6 @@ class Bookmark(commands.Cog):
await target_message.delete()
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Bookmark cog."""
- bot.add_cog(Bookmark(bot))
+ await bot.add_cog(Bookmark(bot))
diff --git a/bot/exts/utilities/challenges.py b/bot/exts/utilities/challenges.py
index ab7ae442..1a5bf289 100644
--- a/bot/exts/utilities/challenges.py
+++ b/bot/exts/utilities/challenges.py
@@ -336,6 +336,6 @@ class Challenges(commands.Cog):
await original_message.edit(embed=kata_embed, view=None)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Challenges cog."""
- bot.add_cog(Challenges(bot))
+ await bot.add_cog(Challenges(bot))
diff --git a/bot/exts/utilities/cheatsheet.py b/bot/exts/utilities/cheatsheet.py
index 33d29f67..3141a050 100644
--- a/bot/exts/utilities/cheatsheet.py
+++ b/bot/exts/utilities/cheatsheet.py
@@ -107,6 +107,6 @@ class CheatSheet(commands.Cog):
await ctx.send(content=description)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the CheatSheet cog."""
- bot.add_cog(CheatSheet(bot))
+ await bot.add_cog(CheatSheet(bot))
diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py
index ee6bad93..20f97e4b 100644
--- a/bot/exts/utilities/colour.py
+++ b/bot/exts/utilities/colour.py
@@ -13,7 +13,6 @@ from discord.ext import commands
from bot import constants
from bot.bot import Bot
-from bot.exts.core.extensions import invoke_help_command
from bot.utils.decorators import whitelist_override
THUMBNAIL_SIZE = (80, 80)
@@ -99,7 +98,7 @@ class Colour(commands.Cog):
extra_colour = ImageColor.getrgb(colour_input)
await self.send_colour_response(ctx, extra_colour)
except ValueError:
- await invoke_help_command(ctx)
+ await self.bot.invoke_help_command(ctx)
@colour.command()
async def rgb(self, ctx: commands.Context, red: int, green: int, blue: int) -> None:
@@ -261,6 +260,6 @@ class Colour(commands.Cog):
return f"#{self.colour_mapping[match]}"
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Colour cog."""
- bot.add_cog(Colour(bot))
+ await bot.add_cog(Colour(bot))
diff --git a/bot/exts/utilities/conversationstarters.py b/bot/exts/utilities/conversationstarters.py
index 8bf2abfd..410ea884 100644
--- a/bot/exts/utilities/conversationstarters.py
+++ b/bot/exts/utilities/conversationstarters.py
@@ -121,6 +121,6 @@ class ConvoStarters(commands.Cog):
self.bot.loop.create_task(self._listen_for_refresh(ctx.author, message))
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the ConvoStarters cog."""
- bot.add_cog(ConvoStarters(bot))
+ await bot.add_cog(ConvoStarters(bot))
diff --git a/bot/exts/utilities/emoji.py b/bot/exts/utilities/emoji.py
index fa438d7f..ec40be01 100644
--- a/bot/exts/utilities/emoji.py
+++ b/bot/exts/utilities/emoji.py
@@ -10,7 +10,6 @@ from discord.ext import commands
from bot.bot import Bot
from bot.constants import Colours, ERROR_REPLIES
-from bot.utils.extensions import invoke_help_command
from bot.utils.pagination import LinePaginator
from bot.utils.time import time_since
@@ -20,6 +19,9 @@ log = logging.getLogger(__name__)
class Emojis(commands.Cog):
"""A collection of commands related to emojis in the server."""
+ def __init__(self, bot: Bot) -> None:
+ self.bot = bot
+
@staticmethod
def embed_builder(emoji: dict) -> tuple[Embed, list[str]]:
"""Generates an embed with the emoji names and count."""
@@ -74,7 +76,7 @@ class Emojis(commands.Cog):
if emoji is not None:
await ctx.invoke(self.info_command, emoji)
else:
- await invoke_help_command(ctx)
+ await self.bot.invoke_help_command(ctx)
@emoji_group.command(name="count", aliases=("c",))
async def count_command(self, ctx: commands.Context, *, category_query: str = None) -> None:
@@ -118,6 +120,6 @@ class Emojis(commands.Cog):
await ctx.send(embed=emoji_information)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Emojis cog."""
- bot.add_cog(Emojis())
+ await bot.add_cog(Emojis(bot))
diff --git a/bot/exts/utilities/epoch.py b/bot/exts/utilities/epoch.py
index 42312dd1..6f572640 100644
--- a/bot/exts/utilities/epoch.py
+++ b/bot/exts/utilities/epoch.py
@@ -6,7 +6,6 @@ from dateutil import parser
from discord.ext import commands
from bot.bot import Bot
-from bot.utils.extensions import invoke_help_command
# https://discord.com/developers/docs/reference#message-formatting-timestamp-styles
STYLES = {
@@ -48,6 +47,9 @@ class DateString(commands.Converter):
class Epoch(commands.Cog):
"""Convert an entered time and date to a unix timestamp."""
+ def __init__(self, bot: Bot) -> None:
+ self.bot = bot
+
@commands.command(name="epoch")
async def epoch(self, ctx: commands.Context, *, date_time: DateString = None) -> None:
"""
@@ -71,7 +73,7 @@ class Epoch(commands.Cog):
Times in the dropdown are shown in UTC
"""
if not date_time:
- await invoke_help_command(ctx)
+ await self.bot.invoke_help_command(ctx)
return
if isinstance(date_time, tuple):
@@ -117,7 +119,7 @@ class TimestampMenuView(discord.ui.View):
self.dropdown.add_option(label=label, description=date_time)
@discord.ui.select(placeholder="Select the format of your timestamp")
- async def select_format(self, _: discord.ui.Select, interaction: discord.Interaction) -> discord.Message:
+ async def select_format(self, interaction: discord.Interaction, _: discord.ui.Select) -> discord.Message:
"""Drop down menu which contains a list of formats which discord timestamps can take."""
selected = interaction.data["values"][0]
if selected == "Epoch":
@@ -133,6 +135,6 @@ class TimestampMenuView(discord.ui.View):
return True
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Epoch cog."""
- bot.add_cog(Epoch())
+ await bot.add_cog(Epoch(bot))
diff --git a/bot/exts/utilities/githubinfo.py b/bot/exts/utilities/githubinfo.py
index 046f67df..a7979718 100644
--- a/bot/exts/utilities/githubinfo.py
+++ b/bot/exts/utilities/githubinfo.py
@@ -12,7 +12,6 @@ from discord.ext import commands
from bot.bot import Bot
from bot.constants import Colours, ERROR_REPLIES, Emojis, NEGATIVE_REPLIES, Tokens
-from bot.exts.core.extensions import invoke_help_command
log = logging.getLogger(__name__)
@@ -168,7 +167,7 @@ class GithubInfo(commands.Cog):
async def github_group(self, ctx: commands.Context) -> None:
"""Commands for finding information related to GitHub."""
if ctx.invoked_subcommand is None:
- await invoke_help_command(ctx)
+ await self.bot.invoke_help_command(ctx)
@commands.Cog.listener()
async def on_message(self, message: discord.Message) -> None:
@@ -363,6 +362,6 @@ class GithubInfo(commands.Cog):
await ctx.send(embed=embed)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the GithubInfo cog."""
- bot.add_cog(GithubInfo(bot))
+ await bot.add_cog(GithubInfo(bot))
diff --git a/bot/exts/utilities/logging.py b/bot/exts/utilities/logging.py
new file mode 100644
index 00000000..83b7025f
--- /dev/null
+++ b/bot/exts/utilities/logging.py
@@ -0,0 +1,40 @@
+from botcore.utils.logging import get_logger
+from discord.ext.commands import Cog
+
+from bot import constants
+from bot.bot import Bot
+
+log = get_logger(__name__)
+
+
+class Logging(Cog):
+ """Debug logging module."""
+
+ def __init__(self, bot: Bot):
+ self.bot = bot
+
+ async def cog_load(self) -> None:
+ """Announce our presence to the configured dev-log channel after checking channel constants."""
+ await self.check_channels()
+ await self.bot.log_to_dev_log(
+ title=self.bot.name,
+ details="Connected!",
+ )
+
+ async def check_channels(self) -> None:
+ """Verifies that all channel constants refer to channels which exist."""
+ if constants.Client.debug:
+ log.info("Skipping Channels Check.")
+ return
+
+ all_channels_ids = [channel.id for channel in self.bot.get_all_channels()]
+ for name, channel_id in vars(constants.Channels).items():
+ if name.startswith("_"):
+ continue
+ if channel_id not in all_channels_ids:
+ log.error(f'Channel "{name}" with ID {channel_id} missing')
+
+
+async def setup(bot: Bot) -> None:
+ """Load the Logging cog."""
+ await bot.add_cog(Logging(bot))
diff --git a/bot/exts/utilities/pythonfacts.py b/bot/exts/utilities/pythonfacts.py
index ef190185..a5bfb612 100644
--- a/bot/exts/utilities/pythonfacts.py
+++ b/bot/exts/utilities/pythonfacts.py
@@ -31,6 +31,6 @@ class PythonFacts(commands.Cog):
await ctx.send(embed=embed)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the PythonFacts Cog."""
- bot.add_cog(PythonFacts())
+ await bot.add_cog(PythonFacts())
diff --git a/bot/exts/utilities/realpython.py b/bot/exts/utilities/realpython.py
index 5e9757d0..46b02866 100644
--- a/bot/exts/utilities/realpython.py
+++ b/bot/exts/utilities/realpython.py
@@ -94,6 +94,6 @@ class RealPython(commands.Cog):
await ctx.send(embed=article_embed)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Real Python Cog."""
- bot.add_cog(RealPython(bot))
+ await bot.add_cog(RealPython(bot))
diff --git a/bot/exts/utilities/reddit.py b/bot/exts/utilities/reddit.py
index 782583d2..028c16bc 100644
--- a/bot/exts/utilities/reddit.py
+++ b/bot/exts/utilities/reddit.py
@@ -15,7 +15,6 @@ from discord.utils import escape_markdown, sleep_until
from bot.bot import Bot
from bot.constants import Channels, ERROR_REPLIES, Emojis, Reddit as RedditConfig, STAFF_ROLES
from bot.utils.converters import Subreddit
-from bot.utils.extensions import invoke_help_command
from bot.utils.messages import sub_clyde
from bot.utils.pagination import ImagePaginator, LinePaginator
@@ -39,20 +38,17 @@ class Reddit(Cog):
self.access_token = None
self.client_auth = BasicAuth(RedditConfig.client_id, RedditConfig.secret)
- bot.loop.create_task(self.init_reddit_ready())
self.auto_poster_loop.start()
- def cog_unload(self) -> None:
+ async def cog_unload(self) -> None:
"""Stop the loop task and revoke the access token when the cog is unloaded."""
self.auto_poster_loop.cancel()
if self.access_token and self.access_token.expires_at > datetime.utcnow():
asyncio.create_task(self.revoke_access_token())
- async def init_reddit_ready(self) -> None:
+ async def cog_load(self) -> None:
"""Sets the reddit webhook when the cog is loaded."""
- await self.bot.wait_until_guild_available()
- if not self.webhook:
- self.webhook = await self.bot.fetch_webhook(RedditConfig.webhook)
+ self.webhook = await self.bot.fetch_webhook(RedditConfig.webhook)
@property
def channel(self) -> TextChannel:
@@ -258,7 +254,6 @@ class Reddit(Cog):
await sleep_until(midnight_tomorrow)
- await self.bot.wait_until_guild_available()
if not self.webhook:
await self.bot.fetch_webhook(RedditConfig.webhook)
@@ -302,7 +297,7 @@ class Reddit(Cog):
@group(name="reddit", invoke_without_command=True)
async def reddit_group(self, ctx: Context) -> None:
"""View the top posts from various subreddits."""
- await invoke_help_command(ctx)
+ await self.bot.invoke_help_command(ctx)
@reddit_group.command(name="top")
async def top_command(self, ctx: Context, subreddit: Subreddit = "r/Python") -> None:
@@ -360,9 +355,9 @@ class Reddit(Cog):
)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Reddit cog."""
if not RedditConfig.secret or not RedditConfig.client_id:
log.error("Credentials not provided, cog not loaded.")
return
- bot.add_cog(Reddit(bot))
+ await bot.add_cog(Reddit(bot))
diff --git a/bot/exts/utilities/stackoverflow.py b/bot/exts/utilities/stackoverflow.py
index 64455e33..b248e83f 100644
--- a/bot/exts/utilities/stackoverflow.py
+++ b/bot/exts/utilities/stackoverflow.py
@@ -83,6 +83,6 @@ class Stackoverflow(commands.Cog):
await ctx.send(embed=search_query_too_long)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Stackoverflow Cog."""
- bot.add_cog(Stackoverflow(bot))
+ await bot.add_cog(Stackoverflow(bot))
diff --git a/bot/exts/utilities/timed.py b/bot/exts/utilities/timed.py
index 2ea6b419..d419dd08 100644
--- a/bot/exts/utilities/timed.py
+++ b/bot/exts/utilities/timed.py
@@ -43,6 +43,6 @@ class TimedCommands(commands.Cog):
await ctx.send(f"Command execution for `{new_ctx.command}` finished in {(t_end - t_start):.4f} seconds.")
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Timed cog."""
- bot.add_cog(TimedCommands())
+ await bot.add_cog(TimedCommands())
diff --git a/bot/exts/utilities/twemoji.py b/bot/exts/utilities/twemoji.py
index c915f05b..25a03d25 100644
--- a/bot/exts/utilities/twemoji.py
+++ b/bot/exts/utilities/twemoji.py
@@ -4,12 +4,11 @@ from typing import Literal, Optional
import discord
from discord.ext import commands
-from emoji import UNICODE_EMOJI_ENGLISH, is_emoji
+from emoji import EMOJI_DATA, is_emoji
from bot.bot import Bot
from bot.constants import Colours, Roles
from bot.utils.decorators import whitelist_override
-from bot.utils.extensions import invoke_help_command
log = logging.getLogger(__name__)
BASE_URLS = {
@@ -50,7 +49,7 @@ class Twemoji(commands.Cog):
emoji = "".join(Twemoji.emoji(e) or "" for e in codepoint.split("-"))
embed = discord.Embed(
- title=Twemoji.alias_to_name(UNICODE_EMOJI_ENGLISH[emoji]),
+ title=Twemoji.alias_to_name(EMOJI_DATA[emoji]["en"]),
description=f"{codepoint.replace('-', ' ')}\n[Download svg]({Twemoji.get_url(codepoint, 'svg')})",
colour=Colours.twitter_blue,
)
@@ -133,7 +132,7 @@ class Twemoji(commands.Cog):
async def twemoji(self, ctx: commands.Context, *raw_emoji: str) -> None:
"""Sends a preview of a given Twemoji, specified by codepoint or emoji."""
if len(raw_emoji) == 0:
- await invoke_help_command(ctx)
+ await self.bot.invoke_help_command(ctx)
return
try:
codepoint = self.codepoint_from_input(raw_emoji)
@@ -145,6 +144,6 @@ class Twemoji(commands.Cog):
await ctx.send(embed=self.build_embed(codepoint))
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Twemoji cog."""
- bot.add_cog(Twemoji(bot))
+ await bot.add_cog(Twemoji(bot))
diff --git a/bot/exts/utilities/wikipedia.py b/bot/exts/utilities/wikipedia.py
index e5e8e289..d87982c9 100644
--- a/bot/exts/utilities/wikipedia.py
+++ b/bot/exts/utilities/wikipedia.py
@@ -93,6 +93,6 @@ class WikipediaSearch(commands.Cog):
)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the WikipediaSearch cog."""
- bot.add_cog(WikipediaSearch(bot))
+ await bot.add_cog(WikipediaSearch(bot))
diff --git a/bot/exts/utilities/wolfram.py b/bot/exts/utilities/wolfram.py
index 9a26e545..a2f1228a 100644
--- a/bot/exts/utilities/wolfram.py
+++ b/bot/exts/utilities/wolfram.py
@@ -202,6 +202,13 @@ class Wolfram(Cog):
message = "Wolfram API key is invalid or missing."
footer = ""
color = Colours.soft_red
+ elif status != 200:
+ # Handle all other possible status codes here
+ message = f"Unexpected status code from Wolfram API: {status}"
+ footer = ""
+ color = Colours.soft_red
+
+ log.warning(f"Unexpected status code from Wolfram API: {status}\nInput: {query}")
else:
message = ""
footer = "View original for a bigger picture."
@@ -281,6 +288,12 @@ class Wolfram(Cog):
elif response_text == "Error 1: Invalid appid.":
message = "Wolfram API key is invalid or missing."
color = Colours.soft_red
+ elif status != 200:
+ # Handle all other possible status codes here
+ message = f"Unexpected status code from Wolfram API: {status}"
+ color = Colours.soft_red
+
+ log.warning(f"Unexpected status code from Wolfram API: {status}\nInput: {query}")
else:
message = response_text
color = Colours.soft_orange
@@ -288,6 +301,6 @@ class Wolfram(Cog):
await send_embed(ctx, message, color)
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the Wolfram cog."""
- bot.add_cog(Wolfram(bot))
+ await bot.add_cog(Wolfram(bot))
diff --git a/bot/exts/utilities/wtf_python.py b/bot/exts/utilities/wtf_python.py
index 980b3dba..0c0375cb 100644
--- a/bot/exts/utilities/wtf_python.py
+++ b/bot/exts/utilities/wtf_python.py
@@ -78,7 +78,7 @@ class WTFPython(commands.Cog):
match, certainty, _ = rapidfuzz.process.extractOne(query, self.headers.keys())
return match if certainty > MINIMUM_CERTAINTY else None
- @commands.command(aliases=("wtf", "WTF"))
+ @commands.command(aliases=("wtf",))
async def wtf_python(self, ctx: commands.Context, *, query: Optional[str] = None) -> None:
"""
Search WTF Python repository.
@@ -133,6 +133,6 @@ class WTFPython(commands.Cog):
self.fetch_readme.cancel()
-def setup(bot: Bot) -> None:
+async def setup(bot: Bot) -> None:
"""Load the WTFPython Cog."""
- bot.add_cog(WTFPython(bot))
+ await bot.add_cog(WTFPython(bot))
diff --git a/bot/monkey_patches.py b/bot/monkey_patches.py
deleted file mode 100644
index 925d3206..00000000
--- a/bot/monkey_patches.py
+++ /dev/null
@@ -1,91 +0,0 @@
-import logging
-import re
-from datetime import datetime, timedelta
-
-from discord import Forbidden, http
-from discord.ext import commands
-
-log = logging.getLogger(__name__)
-MESSAGE_ID_RE = re.compile(r"(?P<message_id>[0-9]{15,20})$")
-
-
-class Command(commands.Command):
- """
- A `discord.ext.commands.Command` subclass which supports root aliases.
-
- A `root_aliases` keyword argument is added, which is a sequence of alias names that will act as
- top-level commands rather than being aliases of the command's group. It's stored as an attribute
- also named `root_aliases`.
- """
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
- self.root_aliases = kwargs.get("root_aliases", [])
-
- if not isinstance(self.root_aliases, (list, tuple)):
- raise TypeError("Root aliases of a command must be a list or a tuple of strings.")
-
-
-class Group(commands.Group):
- """
- A `discord.ext.commands.Group` subclass which supports root aliases.
-
- A `root_aliases` keyword argument is added, which is a sequence of alias names that will act as
- top-level groups rather than being aliases of the command's group. It's stored as an attribute
- also named `root_aliases`.
- """
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
- self.root_aliases = kwargs.get("root_aliases", [])
-
- if not isinstance(self.root_aliases, (list, tuple)):
- raise TypeError("Root aliases of a group must be a list or a tuple of strings.")
-
-
-def patch_typing() -> None:
- """
- Sometimes discord turns off typing events by throwing 403's.
-
- Handle those issues by patching the trigger_typing method so it ignores 403's in general.
- """
- log.debug("Patching send_typing, which should fix things breaking when discord disables typing events. Stay safe!")
-
- original = http.HTTPClient.send_typing
- last_403 = None
-
- async def honeybadger_type(self, channel_id: int) -> None: # noqa: ANN001
- nonlocal last_403
- if last_403 and (datetime.utcnow() - last_403) < timedelta(minutes=5):
- log.warning("Not sending typing event, we got a 403 less than 5 minutes ago.")
- return
- try:
- await original(self, channel_id)
- except Forbidden:
- last_403 = datetime.utcnow()
- log.warning("Got a 403 from typing event!")
- pass
-
- http.HTTPClient.send_typing = honeybadger_type
-
-
-class FixedPartialMessageConverter(commands.PartialMessageConverter):
- """
- Make the Message converter infer channelID from the given context if only a messageID is given.
-
- Discord.py's Message converter is supposed to infer channelID based
- on ctx.channel if only a messageID is given. A refactor commit, linked below,
- a few weeks before d.py's archival broke this defined behaviour of the converter.
- Currently, if only a messageID is given to the converter, it will only find that message
- if it's in the bot's cache.
-
- https://github.com/Rapptz/discord.py/commit/1a4e73d59932cdbe7bf2c281f25e32529fc7ae1f
- """
-
- @staticmethod
- def _get_id_matches(ctx: commands.Context, argument: str) -> tuple[int, int, int]:
- """Inserts ctx.channel.id before calling super method if argument is just a messageID."""
- match = MESSAGE_ID_RE.match(argument)
- if match:
- argument = f"{ctx.channel.id}-{match.group('message_id')}"
- return commands.PartialMessageConverter._get_id_matches(ctx, argument)
diff --git a/bot/resources/utilities/ryanzec_colours.json b/bot/resources/utilities/ryanzec_colours.json
index 552d5a3f..3eff93f2 100644
--- a/bot/resources/utilities/ryanzec_colours.json
+++ b/bot/resources/utilities/ryanzec_colours.json
@@ -147,6 +147,7 @@
"Blue Whale": "042E4C",
"Blue Zodiac": "13264D",
"Blumine": "18587A",
+ "Blurple": "5865F2",
"Blush": "B44668",
"Blush Pink": "FF6FFF",
"Bombay": "AFB1B8",
@@ -957,6 +958,7 @@
"Ochre": "CC7722",
"Off Green": "E6F8F3",
"Off Yellow": "FEF9E3",
+ "OG Blurple": "7289DA",
"Oil": "281E15",
"Old Brick": "901E1E",
"Old Copper": "724A2F",
diff --git a/bot/utils/commands.py b/bot/utils/commands.py
index 7c04a25a..2058507e 100644
--- a/bot/utils/commands.py
+++ b/bot/utils/commands.py
@@ -1,11 +1,7 @@
-from typing import Optional
-
from rapidfuzz import process
-def get_command_suggestions(
- all_commands: list[str], query: str, *, cutoff: int = 60, limit: int = 3
-) -> Optional[list]:
+def get_command_suggestions(all_commands: list[str], query: str, *, cutoff: int = 60, limit: int = 3) -> list[str]:
"""Get similar command names."""
results = process.extract(query, all_commands, score_cutoff=cutoff, limit=limit)
return [result[0] for result in results]
diff --git a/bot/utils/decorators.py b/bot/utils/decorators.py
index 8954e016..442eb841 100644
--- a/bot/utils/decorators.py
+++ b/bot/utils/decorators.py
@@ -199,13 +199,28 @@ def whitelist_check(**default_kwargs: Container[int]) -> Callable[[Context], boo
kwargs = default_kwargs.copy()
allow_dms = False
- # Update kwargs based on override
- if hasattr(ctx.command.callback, "override"):
+ # Determine which command's overrides we will use. Group commands will
+ # inherit from their parents if they don't define their own overrides
+ overridden_command: Optional[commands.Command] = None
+ for command in [ctx.command, *ctx.command.parents]:
+ if hasattr(command.callback, "override"):
+ overridden_command = command
+ break
+ if overridden_command is not None:
+ log.debug(f'Command {overridden_command} has overrides')
+ if overridden_command is not ctx.command:
+ log.debug(
+ f"Command '{ctx.command.qualified_name}' inherited overrides "
+ "from parent command '{overridden_command.qualified_name}'"
+ )
+
+ # Update kwargs based on override, if one exists
+ if overridden_command:
# Handle DM invocations
- allow_dms = ctx.command.callback.override_dm
+ allow_dms = overridden_command.callback.override_dm
# Remove default kwargs if reset is True
- if ctx.command.callback.override_reset:
+ if overridden_command.callback.override_reset:
kwargs = {}
log.debug(
f"{ctx.author} called the '{ctx.command.name}' command and "
@@ -213,9 +228,9 @@ def whitelist_check(**default_kwargs: Container[int]) -> Callable[[Context], boo
)
# Merge overwrites and defaults
- for arg in ctx.command.callback.override:
+ for arg in overridden_command.callback.override:
default_value = kwargs.get(arg)
- new_value = ctx.command.callback.override[arg]
+ new_value = overridden_command.callback.override[arg]
# Skip values that don't need merging, or can't be merged
if default_value is None or isinstance(arg, int):
diff --git a/bot/utils/extensions.py b/bot/utils/extensions.py
deleted file mode 100644
index 09192ae2..00000000
--- a/bot/utils/extensions.py
+++ /dev/null
@@ -1,45 +0,0 @@
-import importlib
-import inspect
-import pkgutil
-from collections.abc import Iterator
-from typing import NoReturn
-
-from discord.ext.commands import Context
-
-from bot import exts
-
-
-def unqualify(name: str) -> str:
- """Return an unqualified name given a qualified module/package `name`."""
- return name.rsplit(".", maxsplit=1)[-1]
-
-
-def walk_extensions() -> Iterator[str]:
- """Yield extension names from the bot.exts subpackage."""
-
- def on_error(name: str) -> NoReturn:
- raise ImportError(name=name) # pragma: no cover
-
- for module in pkgutil.walk_packages(exts.__path__, f"{exts.__name__}.", onerror=on_error):
- if unqualify(module.name).startswith("_"):
- # Ignore module/package names starting with an underscore.
- continue
-
- if module.ispkg:
- imported = importlib.import_module(module.name)
- if not inspect.isfunction(getattr(imported, "setup", None)):
- # If it lacks a setup function, it's not an extension.
- continue
-
- yield module.name
-
-
-async def invoke_help_command(ctx: Context) -> None:
- """Invoke the help command or default help command if help extensions is not loaded."""
- if "bot.exts.core.help" in ctx.bot.extensions:
- help_command = ctx.bot.get_command("help")
- await ctx.invoke(help_command, ctx.command.qualified_name)
- return
- await ctx.send_help(ctx.command)
-
-EXTENSIONS = frozenset(walk_extensions())
diff --git a/bot/utils/pagination.py b/bot/utils/pagination.py
index 188b279f..b291f7db 100644
--- a/bot/utils/pagination.py
+++ b/bot/utils/pagination.py
@@ -5,7 +5,6 @@ from typing import Optional
from discord import Embed, Member, Reaction
from discord.abc import User
-from discord.embeds import EmptyEmbed
from discord.ext.commands import Context, Paginator
from bot.constants import Emojis
@@ -422,7 +421,7 @@ class ImagePaginator(Paginator):
# Magic happens here, after page and reaction_type is set
embed.description = paginator.pages[current_page]
- image = paginator.images[current_page] or EmptyEmbed
+ image = paginator.images[current_page] or None
embed.set_image(url=image)
embed.set_footer(text=f"Page {current_page + 1}/{len(paginator.pages)}")
diff --git a/poetry.lock b/poetry.lock
index 08d0de7e..2ab9c7f8 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,48 +1,63 @@
[[package]]
name = "aiodns"
-version = "2.0.0"
+version = "3.0.0"
description = "Simple DNS resolver for asyncio"
category = "main"
optional = false
python-versions = "*"
[package.dependencies]
-pycares = ">=3.0.0"
+pycares = ">=4.0.0"
[[package]]
name = "aiohttp"
-version = "3.7.4.post0"
+version = "3.8.1"
description = "Async http client/server framework (asyncio)"
category = "main"
optional = false
python-versions = ">=3.6"
[package.dependencies]
-async-timeout = ">=3.0,<4.0"
+aiosignal = ">=1.1.2"
+async-timeout = ">=4.0.0a3,<5.0"
attrs = ">=17.3.0"
-chardet = ">=2.0,<5.0"
+charset-normalizer = ">=2.0,<3.0"
+frozenlist = ">=1.1.1"
multidict = ">=4.5,<7.0"
-typing-extensions = ">=3.6.5"
yarl = ">=1.0,<2.0"
[package.extras]
-speedups = ["aiodns", "brotlipy", "cchardet"]
+speedups = ["Brotli", "aiodns", "cchardet"]
[[package]]
name = "aioredis"
-version = "1.3.1"
+version = "2.0.1"
description = "asyncio (PEP 3156) Redis support"
category = "main"
optional = false
-python-versions = "*"
+python-versions = ">=3.6"
[package.dependencies]
async-timeout = "*"
-hiredis = "*"
+typing-extensions = "*"
+
+[package.extras]
+hiredis = ["hiredis (>=1.0)"]
+
+[[package]]
+name = "aiosignal"
+version = "1.2.0"
+description = "aiosignal: a list of registered asynchronous callbacks"
+category = "main"
+optional = false
+python-versions = ">=3.6"
+
+[package.dependencies]
+frozenlist = ">=1.1.0"
[[package]]
name = "arrow"
-version = "1.1.1"
+version = "1.2.3"
description = "Better dates & times for Python"
category = "main"
optional = false
@@ -53,48 +68,48 @@ python-dateutil = ">=2.7.0"
[[package]]
name = "async-rediscache"
-version = "0.1.4"
+version = "1.0.0rc2"
description = "An easy to use asynchronous Redis cache"
category = "main"
optional = false
python-versions = "~=3.7"
[package.dependencies]
-aioredis = ">=1"
-fakeredis = {version = ">=1.3.1", optional = true, markers = "extra == \"fakeredis\""}
+fakeredis = {version = ">=1.7.1", extras = ["lua"], optional = true, markers = "extra == \"fakeredis\""}
+redis = ">=4.2,<5.0"
[package.extras]
-fakeredis = ["fakeredis (>=1.3.1)"]
+fakeredis = ["fakeredis[lua] (>=1.7.1)"]
[[package]]
name = "async-timeout"
-version = "3.0.1"
+version = "4.0.2"
description = "Timeout context manager for asyncio programs"
category = "main"
optional = false
-python-versions = ">=3.5.3"
+python-versions = ">=3.6"
[[package]]
name = "attrs"
-version = "21.3.0"
+version = "22.1.0"
description = "Classes Without Boilerplate"
category = "main"
optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+python-versions = ">=3.5"
[package.extras]
-dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"]
-docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
-tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"]
-tests_no_zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"]
+dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"]
+docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"]
+tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"]
+tests-no-zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"]
[[package]]
name = "beautifulsoup4"
-version = "4.10.0"
+version = "4.11.1"
description = "Screen-scraping library"
category = "main"
optional = false
-python-versions = ">3.0.0"
+python-versions = ">=3.6.0"
[package.dependencies]
soupsieve = ">1.2"
@@ -104,16 +119,37 @@ html5lib = ["html5lib"]
lxml = ["lxml"]
[[package]]
+name = "bot-core"
+version = "8.2.1"
+description = "Bot-Core provides the core functionality and utilities for the bots of the Python Discord community."
+category = "main"
+optional = false
+python-versions = "3.10.*"
+
+[package.dependencies]
+aiodns = "3.0.0"
+async-rediscache = {version = "1.0.0rc2", extras = ["fakeredis"], optional = true, markers = "extra == \"async-rediscache\""}
+"discord.py" = "2.0.1"
+statsd = "3.3.0"
+
+[package.extras]
+async-rediscache = ["async-rediscache[fakeredis] (==1.0.0rc2)"]
+
+[package.source]
+type = "url"
+url = "https://github.com/python-discord/bot-core/archive/refs/tags/v8.2.1.zip"
+
+[[package]]
name = "certifi"
-version = "2021.10.8"
+version = "2022.9.14"
description = "Python package for providing Mozilla's CA Bundle."
category = "main"
optional = false
-python-versions = "*"
+python-versions = ">=3.6"
[[package]]
name = "cffi"
-version = "1.15.0"
+version = "1.15.1"
description = "Foreign Function Interface for Python calling C code."
category = "main"
optional = false
@@ -131,20 +167,23 @@ optional = false
python-versions = ">=3.6.1"
[[package]]
-name = "chardet"
-version = "4.0.0"
-description = "Universal encoding detector for Python 2 and 3"
+name = "charset-normalizer"
+version = "2.1.1"
+description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
category = "main"
optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+python-versions = ">=3.6.0"
+
+[package.extras]
+unicode-backport = ["unicodedata2"]
[[package]]
name = "colorama"
-version = "0.4.4"
+version = "0.4.6"
description = "Cross-platform colored terminal text."
category = "main"
optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
[[package]]
name = "coloredlogs"
@@ -161,7 +200,7 @@ humanfriendly = ">=9.1"
cron = ["capturer (>=2.4)"]
[[package]]
-name = "deprecated"
+name = "Deprecated"
version = "1.2.13"
description = "Python @deprecated decorator to deprecate old python classes, functions or methods."
category = "main"
@@ -172,31 +211,28 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
wrapt = ">=1.10,<2"
[package.extras]
-dev = ["tox", "bump2version (<1)", "sphinx (<2)", "importlib-metadata (<3)", "importlib-resources (<4)", "configparser (<5)", "sphinxcontrib-websupport (<2)", "zipp (<2)", "PyTest (<5)", "PyTest-Cov (<2.6)", "pytest", "pytest-cov"]
+dev = ["PyTest", "PyTest (<5)", "PyTest-Cov", "PyTest-Cov (<2.6)", "bump2version (<1)", "configparser (<5)", "importlib-metadata (<3)", "importlib-resources (<4)", "sphinx (<2)", "sphinxcontrib-websupport (<2)", "tox", "zipp (<2)"]
[[package]]
name = "discord.py"
-version = "2.0.0a0"
+version = "2.0.1"
description = "A Python wrapper for the Discord API"
category = "main"
optional = false
python-versions = ">=3.8.0"
[package.dependencies]
-aiohttp = ">=3.6.0,<3.8.0"
+aiohttp = ">=3.7.4,<4"
[package.extras]
-docs = ["sphinx (==4.0.2)", "sphinxcontrib-trio (==1.1.2)", "sphinxcontrib-websupport"]
-speed = ["orjson (>=3.5.4)"]
-voice = ["PyNaCl (>=1.3.0,<1.5)"]
-
-[package.source]
-type = "url"
-url = "https://github.com/Rapptz/discord.py/archive/45d498c1b76deaf3b394d17ccf56112fa691d160.zip"
+docs = ["sphinx (==4.4.0)", "sphinxcontrib-trio (==1.1.2)", "sphinxcontrib-websupport", "typing-extensions (>=4.3,<5)"]
+speed = ["Brotli", "aiodns (>=1.1)", "cchardet (==2.1.7)", "orjson (>=3.5.4)"]
+test = ["coverage[toml]", "pytest", "pytest-asyncio", "pytest-cov", "pytest-mock", "typing-extensions (>=4.3,<5)"]
+voice = ["PyNaCl (>=1.3.0,<1.6)"]
[[package]]
name = "distlib"
-version = "0.3.4"
+version = "0.3.6"
description = "Distribution utilities"
category = "dev"
optional = false
@@ -204,14 +240,14 @@ python-versions = "*"
[[package]]
name = "emoji"
-version = "1.6.3"
+version = "2.1.0"
description = "Emoji for Python"
category = "main"
optional = false
-python-versions = "*"
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[package.extras]
-dev = ["pytest", "coverage", "coveralls"]
+dev = ["coverage", "coveralls", "pytest"]
[[package]]
name = "emojis"
@@ -223,72 +259,73 @@ python-versions = "*"
[[package]]
name = "fakeredis"
-version = "1.7.0"
+version = "1.9.1"
description = "Fake implementation of redis API for testing purposes."
category = "main"
optional = false
-python-versions = ">=3.5"
+python-versions = ">=3.7,<4.0"
[package.dependencies]
-packaging = "*"
-redis = "<4.1.0"
-six = ">=1.12"
-sortedcontainers = "*"
+lupa = {version = ">=1.13,<2.0", optional = true, markers = "extra == \"lua\""}
+redis = "<4.4"
+six = ">=1.16.0,<2.0.0"
+sortedcontainers = ">=2.4.0,<3.0.0"
[package.extras]
-lua = ["lupa"]
-aioredis = ["aioredis"]
+aioredis = ["aioredis (>=2.0.1,<3.0.0)"]
+lua = ["lupa (>=1.13,<2.0)"]
[[package]]
name = "filelock"
-version = "3.4.2"
+version = "3.8.0"
description = "A platform independent file lock."
category = "dev"
optional = false
python-versions = ">=3.7"
[package.extras]
-docs = ["furo (>=2021.8.17b43)", "sphinx (>=4.1)", "sphinx-autodoc-typehints (>=1.12)"]
-testing = ["covdefaults (>=1.2.0)", "coverage (>=4)", "pytest (>=4)", "pytest-cov", "pytest-timeout (>=1.4.2)"]
+docs = ["furo (>=2022.6.21)", "sphinx (>=5.1.1)", "sphinx-autodoc-typehints (>=1.19.1)"]
+testing = ["covdefaults (>=2.2)", "coverage (>=6.4.2)", "pytest (>=7.1.2)", "pytest-cov (>=3)", "pytest-timeout (>=2.1)"]
[[package]]
name = "flake8"
-version = "3.9.2"
+version = "5.0.4"
description = "the modular source code checker: pep8 pyflakes and co"
category = "dev"
optional = false
-python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
+python-versions = ">=3.6.1"
[package.dependencies]
-mccabe = ">=0.6.0,<0.7.0"
-pycodestyle = ">=2.7.0,<2.8.0"
-pyflakes = ">=2.3.0,<2.4.0"
+mccabe = ">=0.7.0,<0.8.0"
+pycodestyle = ">=2.9.0,<2.10.0"
+pyflakes = ">=2.5.0,<2.6.0"
[[package]]
name = "flake8-annotations"
-version = "2.7.0"
+version = "2.9.1"
description = "Flake8 Type Annotation Checks"
category = "dev"
optional = false
-python-versions = ">=3.6.2,<4.0.0"
+python-versions = ">=3.7,<4.0"
[package.dependencies]
-flake8 = ">=3.7,<5.0"
+attrs = ">=21.4"
+flake8 = ">=3.7"
[[package]]
name = "flake8-bugbear"
-version = "20.11.1"
+version = "22.10.27"
description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle."
category = "dev"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
[package.dependencies]
attrs = ">=19.2.0"
flake8 = ">=3.0.0"
[package.extras]
-dev = ["coverage", "black", "hypothesis", "hypothesmith"]
+dev = ["coverage", "hypothesis", "hypothesmith (>=0.2)", "pre-commit", "tox"]
[[package]]
name = "flake8-docstrings"
@@ -304,30 +341,18 @@ pydocstyle = ">=2.1"
[[package]]
name = "flake8-isort"
-version = "4.1.1"
+version = "5.0.0"
description = "flake8 plugin that integrates isort ."
category = "dev"
optional = false
-python-versions = "*"
+python-versions = ">=3.7"
[package.dependencies]
-flake8 = ">=3.2.1,<5"
+flake8 = "*"
isort = ">=4.3.5,<6"
-testfixtures = ">=6.8.0,<7"
[package.extras]
-test = ["pytest-cov"]
-
-[[package]]
-name = "flake8-polyfill"
-version = "1.0.2"
-description = "Polyfill package for Flake8 plugins"
-category = "dev"
-optional = false
-python-versions = "*"
-
-[package.dependencies]
-flake8 = "*"
+test = ["pytest"]
[[package]]
name = "flake8-string-format"
@@ -342,14 +367,14 @@ flake8 = "*"
[[package]]
name = "flake8-tidy-imports"
-version = "4.5.0"
+version = "4.8.0"
description = "A flake8 plugin that helps you write tidier imports."
category = "dev"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
[package.dependencies]
-flake8 = ">=3.8.0,<5"
+flake8 = ">=3.8.0"
[[package]]
name = "flake8-todo"
@@ -363,12 +388,12 @@ python-versions = "*"
pycodestyle = ">=2.0.0,<3.0.0"
[[package]]
-name = "hiredis"
-version = "2.0.0"
-description = "Python wrapper for hiredis"
+name = "frozenlist"
+version = "1.3.1"
+description = "A list-like structure which implements collections.abc.MutableSequence"
category = "main"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
[[package]]
name = "humanfriendly"
@@ -383,18 +408,18 @@ pyreadline3 = {version = "*", markers = "sys_platform == \"win32\" and python_ve
[[package]]
name = "identify"
-version = "2.4.1"
+version = "2.5.5"
description = "File identification library for Python"
category = "dev"
optional = false
-python-versions = ">=3.6.1"
+python-versions = ">=3.7"
[package.extras]
license = ["ukkonen"]
[[package]]
name = "idna"
-version = "3.3"
+version = "3.4"
description = "Internationalized Domain Names in Applications (IDNA)"
category = "main"
optional = false
@@ -409,10 +434,18 @@ optional = false
python-versions = ">=3.6.1,<4.0"
[package.extras]
-pipfile_deprecated_finder = ["pipreqs", "requirementslib"]
-requirements_deprecated_finder = ["pipreqs", "pip-api"]
colors = ["colorama (>=0.4.3,<0.5.0)"]
+pipfile-deprecated-finder = ["pipreqs", "requirementslib"]
plugins = ["setuptools"]
+requirements-deprecated-finder = ["pip-api", "pipreqs"]
+
+[[package]]
+name = "lupa"
+version = "1.13"
+description = "Python wrapper around Lua and LuaJIT"
+category = "main"
+optional = false
+python-versions = "*"
[[package]]
name = "lxml"
@@ -425,16 +458,16 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*"
[package.extras]
cssselect = ["cssselect (>=0.7)"]
html5 = ["html5lib"]
-htmlsoup = ["beautifulsoup4"]
+htmlsoup = ["BeautifulSoup4"]
source = ["Cython (>=0.29.7)"]
[[package]]
name = "mccabe"
-version = "0.6.1"
+version = "0.7.0"
description = "McCabe checker, plugin for flake8"
category = "dev"
optional = false
-python-versions = "*"
+python-versions = ">=3.6"
[[package]]
name = "mslex"
@@ -446,19 +479,22 @@ python-versions = ">=3.5"
[[package]]
name = "multidict"
-version = "5.2.0"
+version = "6.0.2"
description = "multidict implementation"
category = "main"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
[[package]]
name = "nodeenv"
-version = "1.6.0"
+version = "1.7.0"
description = "Node.js virtual environment builder"
category = "dev"
optional = false
-python-versions = "*"
+python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*"
+
+[package.dependencies]
+setuptools = "*"
[[package]]
name = "packaging"
@@ -473,31 +509,34 @@ pyparsing = ">=2.0.2,<3.0.5 || >3.0.5"
[[package]]
name = "pep8-naming"
-version = "0.12.1"
+version = "0.13.2"
description = "Check PEP-8 naming conventions, plugin for flake8"
category = "dev"
optional = false
-python-versions = "*"
+python-versions = ">=3.7"
[package.dependencies]
flake8 = ">=3.9.1"
-flake8-polyfill = ">=1.0.2,<2"
[[package]]
-name = "pillow"
-version = "9.0.1"
+name = "Pillow"
+version = "9.2.0"
description = "Python Imaging Library (Fork)"
category = "main"
optional = false
python-versions = ">=3.7"
+[package.extras]
+docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-issues (>=3.0.1)", "sphinx-removed-in", "sphinxext-opengraph"]
+tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"]
+
[[package]]
name = "pip-licenses"
-version = "3.5.3"
+version = "3.5.5"
description = "Dump the software license list of Python packages installed with pip."
category = "dev"
optional = false
-python-versions = "~=3.6"
+python-versions = "~=3.7"
[package.dependencies]
PTable = "*"
@@ -507,23 +546,23 @@ test = ["docutils", "pytest-cov", "pytest-pycodestyle", "pytest-runner"]
[[package]]
name = "platformdirs"
-version = "2.4.1"
+version = "2.5.2"
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
category = "dev"
optional = false
python-versions = ">=3.7"
[package.extras]
-docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"]
+docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx (>=4)", "sphinx-autodoc-typehints (>=1.12)"]
test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"]
[[package]]
name = "pre-commit"
-version = "2.16.0"
+version = "2.20.0"
description = "A framework for managing and maintaining multi-language pre-commit hooks."
category = "dev"
optional = false
-python-versions = ">=3.6.1"
+python-versions = ">=3.7"
[package.dependencies]
cfgv = ">=2.0.0"
@@ -535,17 +574,17 @@ virtualenv = ">=20.0.8"
[[package]]
name = "psutil"
-version = "5.8.0"
+version = "5.9.2"
description = "Cross-platform lib for process and system monitoring in Python."
category = "dev"
optional = false
-python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[package.extras]
-test = ["ipaddress", "mock", "unittest2", "enum34", "pywin32", "wmi"]
+test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"]
[[package]]
-name = "ptable"
+name = "PTable"
version = "0.9.2"
description = "A simple Python library for easily displaying tabular data in a visually appealing ASCII table format"
category = "dev"
@@ -554,7 +593,7 @@ python-versions = "*"
[[package]]
name = "pycares"
-version = "4.2.0"
+version = "4.2.2"
description = "Python interface for c-ares"
category = "main"
optional = false
@@ -568,11 +607,11 @@ idna = ["idna (>=2.1)"]
[[package]]
name = "pycodestyle"
-version = "2.7.0"
+version = "2.9.1"
description = "Python style guide checker"
category = "dev"
optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+python-versions = ">=3.6"
[[package]]
name = "pycparser"
@@ -598,11 +637,11 @@ toml = ["toml"]
[[package]]
name = "pyflakes"
-version = "2.3.1"
+version = "2.5.0"
description = "passive checker of Python programs"
category = "dev"
optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+python-versions = ">=3.6"
[[package]]
name = "pyjokes"
@@ -613,23 +652,23 @@ optional = false
python-versions = "*"
[package.extras]
-test = ["tox", "coverage", "pytest"]
doc = ["mkdocs"]
+test = ["coverage", "pytest", "tox"]
[[package]]
name = "pyparsing"
-version = "3.0.6"
-description = "Python parsing module"
+version = "3.0.9"
+description = "pyparsing module - Classes and methods to define and execute parsing grammars"
category = "main"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.6.8"
[package.extras]
diagrams = ["jinja2", "railroad-diagrams"]
[[package]]
name = "pyreadline3"
-version = "3.3"
+version = "3.4.1"
description = "A python implementation of GNU readline."
category = "main"
optional = false
@@ -648,51 +687,54 @@ six = ">=1.5"
[[package]]
name = "python-dotenv"
-version = "0.19.2"
+version = "0.21.0"
description = "Read key-value pairs from a .env file and set them as environment variables"
category = "dev"
optional = false
-python-versions = ">=3.5"
+python-versions = ">=3.7"
[package.extras]
cli = ["click (>=5.0)"]
[[package]]
-name = "pyyaml"
-version = "5.4.1"
+name = "PyYAML"
+version = "6.0"
description = "YAML parser and emitter for Python"
category = "main"
optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
+python-versions = ">=3.6"
[[package]]
name = "rapidfuzz"
-version = "1.9.1"
+version = "2.12.0"
description = "rapid fuzzy string matching"
category = "main"
optional = false
-python-versions = ">=2.7"
+python-versions = ">=3.7"
[package.extras]
full = ["numpy"]
[[package]]
name = "redis"
-version = "4.0.2"
+version = "4.3.4"
description = "Python client for Redis database and key-value store"
category = "main"
optional = false
python-versions = ">=3.6"
[package.dependencies]
-deprecated = "*"
+async-timeout = ">=4.0.2"
+deprecated = ">=1.2.3"
+packaging = ">=20.4"
[package.extras]
hiredis = ["hiredis (>=1.0.0)"]
+ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"]
[[package]]
name = "sentry-sdk"
-version = "0.20.3"
+version = "1.10.1"
description = "Python client for Sentry (https://sentry.io)"
category = "main"
optional = false
@@ -700,7 +742,7 @@ python-versions = "*"
[package.dependencies]
certifi = "*"
-urllib3 = ">=1.10.0"
+urllib3 = {version = ">=1.26.11", markers = "python_version >= \"3.6\""}
[package.extras]
aiohttp = ["aiohttp (>=3.5)"]
@@ -710,15 +752,32 @@ celery = ["celery (>=3)"]
chalice = ["chalice (>=1.16.0)"]
django = ["django (>=1.8)"]
falcon = ["falcon (>=1.4)"]
-flask = ["flask (>=0.11)", "blinker (>=1.1)"]
-pure_eval = ["pure-eval", "executing", "asttokens"]
+fastapi = ["fastapi (>=0.79.0)"]
+flask = ["blinker (>=1.1)", "flask (>=0.11)"]
+httpx = ["httpx (>=0.16.0)"]
+pure-eval = ["asttokens", "executing", "pure-eval"]
pyspark = ["pyspark (>=2.4.4)"]
+quart = ["blinker (>=1.1)", "quart (>=0.16.1)"]
rq = ["rq (>=0.6)"]
sanic = ["sanic (>=0.8)"]
sqlalchemy = ["sqlalchemy (>=1.2)"]
+starlette = ["starlette (>=0.19.1)"]
tornado = ["tornado (>=5)"]
[[package]]
+name = "setuptools"
+version = "65.3.0"
+description = "Easily download, build, install, upgrade, and uninstall Python packages"
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+
+[package.extras]
+docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
+testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mock", "pip (>=19.1)", "pip-run (>=8.8)", "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", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
+testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
+
+[[package]]
name = "six"
version = "1.16.0"
description = "Python 2 and 3 compatibility utilities"
@@ -744,15 +803,23 @@ python-versions = "*"
[[package]]
name = "soupsieve"
-version = "2.3.1"
+version = "2.3.2.post1"
description = "A modern CSS selector implementation for Beautiful Soup."
category = "main"
optional = false
python-versions = ">=3.6"
[[package]]
+name = "statsd"
+version = "3.3.0"
+description = "A simple statsd client."
+category = "main"
+optional = false
+python-versions = "*"
+
+[[package]]
name = "taskipy"
-version = "1.9.0"
+version = "1.10.3"
description = "tasks runner for python projects"
category = "dev"
optional = false
@@ -762,20 +829,7 @@ python-versions = ">=3.6,<4.0"
colorama = ">=0.4.4,<0.5.0"
mslex = {version = ">=0.3.0,<0.4.0", markers = "sys_platform == \"win32\""}
psutil = ">=5.7.2,<6.0.0"
-toml = ">=0.10.0,<0.11.0"
-
-[[package]]
-name = "testfixtures"
-version = "6.18.3"
-description = "A collection of helpers and mock objects for unit tests and doc tests."
-category = "dev"
-optional = false
-python-versions = "*"
-
-[package.extras]
-build = ["setuptools-git", "wheel", "twine"]
-docs = ["sphinx", "zope.component", "sybil", "twisted", "mock", "django (<2)", "django"]
-test = ["pytest (>=3.6)", "pytest-cov", "pytest-django", "zope.component", "sybil", "twisted", "mock", "django (<2)", "django"]
+tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
[[package]]
name = "toml"
@@ -786,47 +840,54 @@ optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
[[package]]
+name = "tomli"
+version = "2.0.1"
+description = "A lil' TOML parser"
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+
+[[package]]
name = "typing-extensions"
-version = "4.0.1"
-description = "Backported and Experimental Type Hints for Python 3.6+"
+version = "4.3.0"
+description = "Backported and Experimental Type Hints for Python 3.7+"
category = "main"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
[[package]]
name = "urllib3"
-version = "1.26.7"
+version = "1.26.12"
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.*, <4"
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4"
[package.extras]
-brotli = ["brotlipy (>=0.6.0)"]
-secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
+brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"]
+secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"]
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
[[package]]
name = "virtualenv"
-version = "20.11.0"
+version = "20.16.5"
description = "Virtual Python Environment builder"
category = "dev"
optional = false
-python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
+python-versions = ">=3.6"
[package.dependencies]
-distlib = ">=0.3.1,<1"
-filelock = ">=3.2,<4"
-platformdirs = ">=2,<3"
-six = ">=1.9.0,<2"
+distlib = ">=0.3.5,<1"
+filelock = ">=3.4.1,<4"
+platformdirs = ">=2.4,<3"
[package.extras]
-docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=21.3)"]
-testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "packaging (>=20.0)"]
+docs = ["proselint (>=0.13)", "sphinx (>=5.1.1)", "sphinx-argparse (>=0.3.1)", "sphinx-rtd-theme (>=1)", "towncrier (>=21.9)"]
+testing = ["coverage (>=6.2)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=21.3)", "pytest (>=7.0.1)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.6.1)", "pytest-randomly (>=3.10.3)", "pytest-timeout (>=2.1)"]
[[package]]
name = "wrapt"
-version = "1.13.3"
+version = "1.14.1"
description = "Module for decorators, wrappers and monkey patching."
category = "main"
optional = false
@@ -834,11 +895,11 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
[[package]]
name = "yarl"
-version = "1.7.2"
+version = "1.8.1"
description = "Yet another URL library"
category = "main"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
[package.dependencies]
idna = ">=2.0"
@@ -846,81 +907,1068 @@ multidict = ">=4.0"
[metadata]
lock-version = "1.1"
-python-versions = "^3.9"
-content-hash = "86ef4c274176e805702da51d96711698a09ca6e04c145b607258c34d04638b9e"
+python-versions = "3.10.*"
+content-hash = "4c0cbdaf9033ce6c8c5aba3b2a824d67d453fd1a6503195b5c6aa6d92e111845"
[metadata.files]
-aiodns = []
-aiohttp = []
-aioredis = []
-arrow = []
-async-rediscache = []
-async-timeout = []
-attrs = []
-beautifulsoup4 = []
-certifi = []
-cffi = []
-cfgv = []
-chardet = []
-colorama = []
-coloredlogs = []
-deprecated = []
-"discord.py" = []
-distlib = []
-emoji = []
-emojis = []
-fakeredis = []
-filelock = []
-flake8 = []
-flake8-annotations = []
-flake8-bugbear = []
-flake8-docstrings = []
-flake8-isort = []
-flake8-polyfill = []
-flake8-string-format = []
-flake8-tidy-imports = []
-flake8-todo = []
-hiredis = []
-humanfriendly = []
-identify = []
-idna = []
-isort = []
-lxml = []
-mccabe = []
-mslex = []
-multidict = []
-nodeenv = []
-packaging = []
-pep8-naming = []
-pillow = []
-pip-licenses = []
-platformdirs = []
-pre-commit = []
-psutil = []
-ptable = []
-pycares = []
-pycodestyle = []
-pycparser = []
-pydocstyle = []
-pyflakes = []
-pyjokes = []
-pyparsing = []
-pyreadline3 = []
-python-dateutil = []
-python-dotenv = []
-pyyaml = []
-rapidfuzz = []
-redis = []
-sentry-sdk = []
-six = []
-snowballstemmer = []
-sortedcontainers = []
-soupsieve = []
-taskipy = []
-testfixtures = []
-toml = []
-typing-extensions = []
-urllib3 = []
-virtualenv = []
-wrapt = []
-yarl = []
+aiodns = [
+ {file = "aiodns-3.0.0-py3-none-any.whl", hash = "sha256:2b19bc5f97e5c936638d28e665923c093d8af2bf3aa88d35c43417fa25d136a2"},
+ {file = "aiodns-3.0.0.tar.gz", hash = "sha256:946bdfabe743fceeeb093c8a010f5d1645f708a241be849e17edfb0e49e08cd6"},
+]
+aiohttp = [
+ {file = "aiohttp-3.8.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1ed0b6477896559f17b9eaeb6d38e07f7f9ffe40b9f0f9627ae8b9926ae260a8"},
+ {file = "aiohttp-3.8.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7dadf3c307b31e0e61689cbf9e06be7a867c563d5a63ce9dca578f956609abf8"},
+ {file = "aiohttp-3.8.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a79004bb58748f31ae1cbe9fa891054baaa46fb106c2dc7af9f8e3304dc30316"},
+ {file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12de6add4038df8f72fac606dff775791a60f113a725c960f2bab01d8b8e6b15"},
+ {file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6f0d5f33feb5f69ddd57a4a4bd3d56c719a141080b445cbf18f238973c5c9923"},
+ {file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eaba923151d9deea315be1f3e2b31cc39a6d1d2f682f942905951f4e40200922"},
+ {file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:099ebd2c37ac74cce10a3527d2b49af80243e2a4fa39e7bce41617fbc35fa3c1"},
+ {file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2e5d962cf7e1d426aa0e528a7e198658cdc8aa4fe87f781d039ad75dcd52c516"},
+ {file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:fa0ffcace9b3aa34d205d8130f7873fcfefcb6a4dd3dd705b0dab69af6712642"},
+ {file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:61bfc23df345d8c9716d03717c2ed5e27374e0fe6f659ea64edcd27b4b044cf7"},
+ {file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:31560d268ff62143e92423ef183680b9829b1b482c011713ae941997921eebc8"},
+ {file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:01d7bdb774a9acc838e6b8f1d114f45303841b89b95984cbb7d80ea41172a9e3"},
+ {file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:97ef77eb6b044134c0b3a96e16abcb05ecce892965a2124c566af0fd60f717e2"},
+ {file = "aiohttp-3.8.1-cp310-cp310-win32.whl", hash = "sha256:c2aef4703f1f2ddc6df17519885dbfa3514929149d3ff900b73f45998f2532fa"},
+ {file = "aiohttp-3.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:713ac174a629d39b7c6a3aa757b337599798da4c1157114a314e4e391cd28e32"},
+ {file = "aiohttp-3.8.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:473d93d4450880fe278696549f2e7aed8cd23708c3c1997981464475f32137db"},
+ {file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99b5eeae8e019e7aad8af8bb314fb908dd2e028b3cdaad87ec05095394cce632"},
+ {file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3af642b43ce56c24d063325dd2cf20ee012d2b9ba4c3c008755a301aaea720ad"},
+ {file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3630c3ef435c0a7c549ba170a0633a56e92629aeed0e707fec832dee313fb7a"},
+ {file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4a4a4e30bf1edcad13fb0804300557aedd07a92cabc74382fdd0ba6ca2661091"},
+ {file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6f8b01295e26c68b3a1b90efb7a89029110d3a4139270b24fda961893216c440"},
+ {file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:a25fa703a527158aaf10dafd956f7d42ac6d30ec80e9a70846253dd13e2f067b"},
+ {file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:5bfde62d1d2641a1f5173b8c8c2d96ceb4854f54a44c23102e2ccc7e02f003ec"},
+ {file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:51467000f3647d519272392f484126aa716f747859794ac9924a7aafa86cd411"},
+ {file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:03a6d5349c9ee8f79ab3ff3694d6ce1cfc3ced1c9d36200cb8f08ba06bd3b782"},
+ {file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:102e487eeb82afac440581e5d7f8f44560b36cf0bdd11abc51a46c1cd88914d4"},
+ {file = "aiohttp-3.8.1-cp36-cp36m-win32.whl", hash = "sha256:4aed991a28ea3ce320dc8ce655875e1e00a11bdd29fe9444dd4f88c30d558602"},
+ {file = "aiohttp-3.8.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b0e20cddbd676ab8a64c774fefa0ad787cc506afd844de95da56060348021e96"},
+ {file = "aiohttp-3.8.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:37951ad2f4a6df6506750a23f7cbabad24c73c65f23f72e95897bb2cecbae676"},
+ {file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c23b1ad869653bc818e972b7a3a79852d0e494e9ab7e1a701a3decc49c20d51"},
+ {file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:15b09b06dae900777833fe7fc4b4aa426556ce95847a3e8d7548e2d19e34edb8"},
+ {file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:477c3ea0ba410b2b56b7efb072c36fa91b1e6fc331761798fa3f28bb224830dd"},
+ {file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2f2f69dca064926e79997f45b2f34e202b320fd3782f17a91941f7eb85502ee2"},
+ {file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ef9612483cb35171d51d9173647eed5d0069eaa2ee812793a75373447d487aa4"},
+ {file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6d69f36d445c45cda7b3b26afef2fc34ef5ac0cdc75584a87ef307ee3c8c6d00"},
+ {file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:55c3d1072704d27401c92339144d199d9de7b52627f724a949fc7d5fc56d8b93"},
+ {file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b9d00268fcb9f66fbcc7cd9fe423741d90c75ee029a1d15c09b22d23253c0a44"},
+ {file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:07b05cd3305e8a73112103c834e91cd27ce5b4bd07850c4b4dbd1877d3f45be7"},
+ {file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c34dc4958b232ef6188c4318cb7b2c2d80521c9a56c52449f8f93ab7bc2a8a1c"},
+ {file = "aiohttp-3.8.1-cp37-cp37m-win32.whl", hash = "sha256:d2f9b69293c33aaa53d923032fe227feac867f81682f002ce33ffae978f0a9a9"},
+ {file = "aiohttp-3.8.1-cp37-cp37m-win_amd64.whl", hash = "sha256:6ae828d3a003f03ae31915c31fa684b9890ea44c9c989056fea96e3d12a9fa17"},
+ {file = "aiohttp-3.8.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0c7ebbbde809ff4e970824b2b6cb7e4222be6b95a296e46c03cf050878fc1785"},
+ {file = "aiohttp-3.8.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8b7ef7cbd4fec9a1e811a5de813311ed4f7ac7d93e0fda233c9b3e1428f7dd7b"},
+ {file = "aiohttp-3.8.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c3d6a4d0619e09dcd61021debf7059955c2004fa29f48788a3dfaf9c9901a7cd"},
+ {file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:718626a174e7e467f0558954f94af117b7d4695d48eb980146016afa4b580b2e"},
+ {file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:589c72667a5febd36f1315aa6e5f56dd4aa4862df295cb51c769d16142ddd7cd"},
+ {file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2ed076098b171573161eb146afcb9129b5ff63308960aeca4b676d9d3c35e700"},
+ {file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:086f92daf51a032d062ec5f58af5ca6a44d082c35299c96376a41cbb33034675"},
+ {file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:11691cf4dc5b94236ccc609b70fec991234e7ef8d4c02dd0c9668d1e486f5abf"},
+ {file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:31d1e1c0dbf19ebccbfd62eff461518dcb1e307b195e93bba60c965a4dcf1ba0"},
+ {file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:11a67c0d562e07067c4e86bffc1553f2cf5b664d6111c894671b2b8712f3aba5"},
+ {file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:bb01ba6b0d3f6c68b89fce7305080145d4877ad3acaed424bae4d4ee75faa950"},
+ {file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:44db35a9e15d6fe5c40d74952e803b1d96e964f683b5a78c3cc64eb177878155"},
+ {file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:844a9b460871ee0a0b0b68a64890dae9c415e513db0f4a7e3cab41a0f2fedf33"},
+ {file = "aiohttp-3.8.1-cp38-cp38-win32.whl", hash = "sha256:7d08744e9bae2ca9c382581f7dce1273fe3c9bae94ff572c3626e8da5b193c6a"},
+ {file = "aiohttp-3.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:04d48b8ce6ab3cf2097b1855e1505181bdd05586ca275f2505514a6e274e8e75"},
+ {file = "aiohttp-3.8.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f5315a2eb0239185af1bddb1abf472d877fede3cc8d143c6cddad37678293237"},
+ {file = "aiohttp-3.8.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a996d01ca39b8dfe77440f3cd600825d05841088fd6bc0144cc6c2ec14cc5f74"},
+ {file = "aiohttp-3.8.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:13487abd2f761d4be7c8ff9080de2671e53fff69711d46de703c310c4c9317ca"},
+ {file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea302f34477fda3f85560a06d9ebdc7fa41e82420e892fc50b577e35fc6a50b2"},
+ {file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2f635ce61a89c5732537a7896b6319a8fcfa23ba09bec36e1b1ac0ab31270d2"},
+ {file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e999f2d0e12eea01caeecb17b653f3713d758f6dcc770417cf29ef08d3931421"},
+ {file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0770e2806a30e744b4e21c9d73b7bee18a1cfa3c47991ee2e5a65b887c49d5cf"},
+ {file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d15367ce87c8e9e09b0f989bfd72dc641bcd04ba091c68cd305312d00962addd"},
+ {file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6c7cefb4b0640703eb1069835c02486669312bf2f12b48a748e0a7756d0de33d"},
+ {file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:71927042ed6365a09a98a6377501af5c9f0a4d38083652bcd2281a06a5976724"},
+ {file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:28d490af82bc6b7ce53ff31337a18a10498303fe66f701ab65ef27e143c3b0ef"},
+ {file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:b6613280ccedf24354406caf785db748bebbddcf31408b20c0b48cb86af76866"},
+ {file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:81e3d8c34c623ca4e36c46524a3530e99c0bc95ed068fd6e9b55cb721d408fb2"},
+ {file = "aiohttp-3.8.1-cp39-cp39-win32.whl", hash = "sha256:7187a76598bdb895af0adbd2fb7474d7f6025d170bc0a1130242da817ce9e7d1"},
+ {file = "aiohttp-3.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:1c182cb873bc91b411e184dab7a2b664d4fea2743df0e4d57402f7f3fa644bac"},
+ {file = "aiohttp-3.8.1.tar.gz", hash = "sha256:fc5471e1a54de15ef71c1bc6ebe80d4dc681ea600e68bfd1cbce40427f0b7578"},
+]
+aioredis = [
+ {file = "aioredis-2.0.1-py3-none-any.whl", hash = "sha256:9ac0d0b3b485d293b8ca1987e6de8658d7dafcca1cddfcd1d506cae8cdebfdd6"},
+ {file = "aioredis-2.0.1.tar.gz", hash = "sha256:eaa51aaf993f2d71f54b70527c440437ba65340588afeb786cd87c55c89cd98e"},
+]
+aiosignal = [
+ {file = "aiosignal-1.2.0-py3-none-any.whl", hash = "sha256:26e62109036cd181df6e6ad646f91f0dcfd05fe16d0cb924138ff2ab75d64e3a"},
+ {file = "aiosignal-1.2.0.tar.gz", hash = "sha256:78ed67db6c7b7ced4f98e495e572106d5c432a93e1ddd1bf475e1dc05f5b7df2"},
+]
+arrow = [
+ {file = "arrow-1.2.3-py3-none-any.whl", hash = "sha256:5a49ab92e3b7b71d96cd6bfcc4df14efefc9dfa96ea19045815914a6ab6b1fe2"},
+ {file = "arrow-1.2.3.tar.gz", hash = "sha256:3934b30ca1b9f292376d9db15b19446088d12ec58629bc3f0da28fd55fb633a1"},
+]
+async-rediscache = [
+ {file = "async-rediscache-1.0.0rc2.tar.gz", hash = "sha256:65b1f67df0bd92defe37a3e645ea4c868da29eb41bfa493643a3b4ae7c0e109c"},
+ {file = "async_rediscache-1.0.0rc2-py3-none-any.whl", hash = "sha256:b156cc42b3285e1bd620487c594d7238552f95e48dc07b4e5d0b1c095c3acc86"},
+]
+async-timeout = [
+ {file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"},
+ {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"},
+]
+attrs = [
+ {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"},
+ {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"},
+]
+beautifulsoup4 = [
+ {file = "beautifulsoup4-4.11.1-py3-none-any.whl", hash = "sha256:58d5c3d29f5a36ffeb94f02f0d786cd53014cf9b3b3951d42e0080d8a9498d30"},
+ {file = "beautifulsoup4-4.11.1.tar.gz", hash = "sha256:ad9aa55b65ef2808eb405f46cf74df7fcb7044d5cbc26487f96eb2ef2e436693"},
+]
+bot-core = []
+certifi = [
+ {file = "certifi-2022.9.14-py3-none-any.whl", hash = "sha256:e232343de1ab72c2aa521b625c80f699e356830fd0e2c620b465b304b17b0516"},
+ {file = "certifi-2022.9.14.tar.gz", hash = "sha256:36973885b9542e6bd01dea287b2b4b3b21236307c56324fcc3f1160f2d655ed5"},
+]
+cffi = [
+ {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"},
+ {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"},
+ {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"},
+ {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"},
+ {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"},
+ {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"},
+ {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"},
+ {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"},
+ {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"},
+ {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"},
+ {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"},
+ {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"},
+ {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"},
+ {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"},
+ {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"},
+ {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"},
+ {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"},
+ {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"},
+ {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"},
+ {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"},
+ {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"},
+ {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"},
+ {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"},
+ {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"},
+ {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"},
+ {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"},
+ {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"},
+ {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"},
+ {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"},
+ {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"},
+ {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"},
+ {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"},
+ {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"},
+ {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"},
+ {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"},
+ {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"},
+ {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"},
+ {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"},
+ {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"},
+ {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"},
+ {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"},
+ {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"},
+ {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"},
+ {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"},
+ {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"},
+ {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"},
+ {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"},
+ {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"},
+ {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"},
+ {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"},
+ {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"},
+ {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"},
+ {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"},
+ {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"},
+ {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"},
+ {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"},
+ {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"},
+ {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"},
+ {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"},
+ {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"},
+ {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"},
+ {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"},
+ {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"},
+ {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"},
+]
+cfgv = [
+ {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"},
+ {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"},
+]
+charset-normalizer = [
+ {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"},
+ {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"},
+]
+colorama = [
+ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
+ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
+]
+coloredlogs = [
+ {file = "coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934"},
+ {file = "coloredlogs-15.0.1.tar.gz", hash = "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0"},
+]
+Deprecated = [
+ {file = "Deprecated-1.2.13-py2.py3-none-any.whl", hash = "sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d"},
+ {file = "Deprecated-1.2.13.tar.gz", hash = "sha256:43ac5335da90c31c24ba028af536a91d41d53f9e6901ddb021bcc572ce44e38d"},
+]
+"discord.py" = [
+ {file = "discord.py-2.0.1-py3-none-any.whl", hash = "sha256:aeb186348bf011708b085b2715cf92bbb72c692eb4f59c4c0b488130cc4c4b7e"},
+ {file = "discord.py-2.0.1.tar.gz", hash = "sha256:309146476e986cb8faf038cd5d604d4b3834ef15c2d34df697ce5064bf5cd779"},
+]
+distlib = [
+ {file = "distlib-0.3.6-py2.py3-none-any.whl", hash = "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e"},
+ {file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"},
+]
+emoji = [
+ {file = "emoji-2.1.0.tar.gz", hash = "sha256:56a8c5e906c11694eb7694b78e5452d745030869b3945f6306a8151ff5cdbc39"},
+]
+emojis = [
+ {file = "emojis-0.6.0-py3-none-any.whl", hash = "sha256:7da34c8a78ae262fd68cef9e2c78a3c1feb59784489eeea0f54ba1d4b7111c7c"},
+ {file = "emojis-0.6.0.tar.gz", hash = "sha256:bf605d1f1a27a81cd37fe82eb65781c904467f569295a541c33710b97e4225ec"},
+]
+fakeredis = [
+ {file = "fakeredis-1.9.1-py3-none-any.whl", hash = "sha256:b9830f68dafafc0abe6c037775765166e9e2ff6b0da8abd3838eb2c3910f8e65"},
+ {file = "fakeredis-1.9.1.tar.gz", hash = "sha256:e884776d7d0216e9c6c514527718259cfbd555777b36ba403ae680bd1489f7a1"},
+]
+filelock = [
+ {file = "filelock-3.8.0-py3-none-any.whl", hash = "sha256:617eb4e5eedc82fc5f47b6d61e4d11cb837c56cb4544e39081099fa17ad109d4"},
+ {file = "filelock-3.8.0.tar.gz", hash = "sha256:55447caa666f2198c5b6b13a26d2084d26fa5b115c00d065664b2124680c4edc"},
+]
+flake8 = [
+ {file = "flake8-5.0.4-py2.py3-none-any.whl", hash = "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248"},
+ {file = "flake8-5.0.4.tar.gz", hash = "sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db"},
+]
+flake8-annotations = [
+ {file = "flake8-annotations-2.9.1.tar.gz", hash = "sha256:11f09efb99ae63c8f9d6b492b75fe147fbc323179fddfe00b2e56eefeca42f57"},
+ {file = "flake8_annotations-2.9.1-py3-none-any.whl", hash = "sha256:a4385158a7a9fc8af1d8820a2f4c8d03387997006a83f5f8bfe5bc6085bdf88a"},
+]
+flake8-bugbear = [
+ {file = "flake8-bugbear-22.10.27.tar.gz", hash = "sha256:a6708608965c9e0de5fff13904fed82e0ba21ac929fe4896459226a797e11cd5"},
+ {file = "flake8_bugbear-22.10.27-py3-none-any.whl", hash = "sha256:6ad0ab754507319060695e2f2be80e6d8977cfcea082293089a9226276bd825d"},
+]
+flake8-docstrings = [
+ {file = "flake8-docstrings-1.6.0.tar.gz", hash = "sha256:9fe7c6a306064af8e62a055c2f61e9eb1da55f84bb39caef2b84ce53708ac34b"},
+ {file = "flake8_docstrings-1.6.0-py2.py3-none-any.whl", hash = "sha256:99cac583d6c7e32dd28bbfbef120a7c0d1b6dde4adb5a9fd441c4227a6534bde"},
+]
+flake8-isort = [
+ {file = "flake8-isort-5.0.0.tar.gz", hash = "sha256:e336f928c7edc509684930ab124414194b7f4e237c712af8fcbdf49d8747b10c"},
+ {file = "flake8_isort-5.0.0-py3-none-any.whl", hash = "sha256:c73f9cbd1bf209887f602a27b827164ccfeba1676801b2aa23cb49051a1be79c"},
+]
+flake8-string-format = [
+ {file = "flake8-string-format-0.3.0.tar.gz", hash = "sha256:65f3da786a1461ef77fca3780b314edb2853c377f2e35069723348c8917deaa2"},
+ {file = "flake8_string_format-0.3.0-py2.py3-none-any.whl", hash = "sha256:812ff431f10576a74c89be4e85b8e075a705be39bc40c4b4278b5b13e2afa9af"},
+]
+flake8-tidy-imports = [
+ {file = "flake8-tidy-imports-4.8.0.tar.gz", hash = "sha256:df44f9c841b5dfb3a7a1f0da8546b319d772c2a816a1afefcce43e167a593d83"},
+ {file = "flake8_tidy_imports-4.8.0-py3-none-any.whl", hash = "sha256:25bd9799358edefa0e010ce2c587b093c3aba942e96aeaa99b6d0500ae1bf09c"},
+]
+flake8-todo = [
+ {file = "flake8-todo-0.7.tar.gz", hash = "sha256:6e4c5491ff838c06fe5a771b0e95ee15fc005ca57196011011280fc834a85915"},
+]
+frozenlist = [
+ {file = "frozenlist-1.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5f271c93f001748fc26ddea409241312a75e13466b06c94798d1a341cf0e6989"},
+ {file = "frozenlist-1.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9c6ef8014b842f01f5d2b55315f1af5cbfde284eb184075c189fd657c2fd8204"},
+ {file = "frozenlist-1.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:219a9676e2eae91cb5cc695a78b4cb43d8123e4160441d2b6ce8d2c70c60e2f3"},
+ {file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b47d64cdd973aede3dd71a9364742c542587db214e63b7529fbb487ed67cddd9"},
+ {file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2af6f7a4e93f5d08ee3f9152bce41a6015b5cf87546cb63872cc19b45476e98a"},
+ {file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a718b427ff781c4f4e975525edb092ee2cdef6a9e7bc49e15063b088961806f8"},
+ {file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c56c299602c70bc1bb5d1e75f7d8c007ca40c9d7aebaf6e4ba52925d88ef826d"},
+ {file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:717470bfafbb9d9be624da7780c4296aa7935294bd43a075139c3d55659038ca"},
+ {file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:31b44f1feb3630146cffe56344704b730c33e042ffc78d21f2125a6a91168131"},
+ {file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c3b31180b82c519b8926e629bf9f19952c743e089c41380ddca5db556817b221"},
+ {file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:d82bed73544e91fb081ab93e3725e45dd8515c675c0e9926b4e1f420a93a6ab9"},
+ {file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:49459f193324fbd6413e8e03bd65789e5198a9fa3095e03f3620dee2f2dabff2"},
+ {file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:94e680aeedc7fd3b892b6fa8395b7b7cc4b344046c065ed4e7a1e390084e8cb5"},
+ {file = "frozenlist-1.3.1-cp310-cp310-win32.whl", hash = "sha256:fabb953ab913dadc1ff9dcc3a7a7d3dc6a92efab3a0373989b8063347f8705be"},
+ {file = "frozenlist-1.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:eee0c5ecb58296580fc495ac99b003f64f82a74f9576a244d04978a7e97166db"},
+ {file = "frozenlist-1.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0bc75692fb3770cf2b5856a6c2c9de967ca744863c5e89595df64e252e4b3944"},
+ {file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086ca1ac0a40e722d6833d4ce74f5bf1aba2c77cbfdc0cd83722ffea6da52a04"},
+ {file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b51eb355e7f813bcda00276b0114c4172872dc5fb30e3fea059b9367c18fbcb"},
+ {file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:74140933d45271c1a1283f708c35187f94e1256079b3c43f0c2267f9db5845ff"},
+ {file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee4c5120ddf7d4dd1eaf079af3af7102b56d919fa13ad55600a4e0ebe532779b"},
+ {file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97d9e00f3ac7c18e685320601f91468ec06c58acc185d18bb8e511f196c8d4b2"},
+ {file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6e19add867cebfb249b4e7beac382d33215d6d54476bb6be46b01f8cafb4878b"},
+ {file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a027f8f723d07c3f21963caa7d585dcc9b089335565dabe9c814b5f70c52705a"},
+ {file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:61d7857950a3139bce035ad0b0945f839532987dfb4c06cfe160254f4d19df03"},
+ {file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:53b2b45052e7149ee8b96067793db8ecc1ae1111f2f96fe1f88ea5ad5fd92d10"},
+ {file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:bbb1a71b1784e68870800b1bc9f3313918edc63dbb8f29fbd2e767ce5821696c"},
+ {file = "frozenlist-1.3.1-cp37-cp37m-win32.whl", hash = "sha256:ab6fa8c7871877810e1b4e9392c187a60611fbf0226a9e0b11b7b92f5ac72792"},
+ {file = "frozenlist-1.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:f89139662cc4e65a4813f4babb9ca9544e42bddb823d2ec434e18dad582543bc"},
+ {file = "frozenlist-1.3.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:4c0c99e31491a1d92cde8648f2e7ccad0e9abb181f6ac3ddb9fc48b63301808e"},
+ {file = "frozenlist-1.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:61e8cb51fba9f1f33887e22488bad1e28dd8325b72425f04517a4d285a04c519"},
+ {file = "frozenlist-1.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cc2f3e368ee5242a2cbe28323a866656006382872c40869b49b265add546703f"},
+ {file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58fb94a01414cddcdc6839807db77ae8057d02ddafc94a42faee6004e46c9ba8"},
+ {file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:022178b277cb9277d7d3b3f2762d294f15e85cd2534047e68a118c2bb0058f3e"},
+ {file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:572ce381e9fe027ad5e055f143763637dcbac2542cfe27f1d688846baeef5170"},
+ {file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19127f8dcbc157ccb14c30e6f00392f372ddb64a6ffa7106b26ff2196477ee9f"},
+ {file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42719a8bd3792744c9b523674b752091a7962d0d2d117f0b417a3eba97d1164b"},
+ {file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2743bb63095ef306041c8f8ea22bd6e4d91adabf41887b1ad7886c4c1eb43d5f"},
+ {file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:fa47319a10e0a076709644a0efbcaab9e91902c8bd8ef74c6adb19d320f69b83"},
+ {file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:52137f0aea43e1993264a5180c467a08a3e372ca9d378244c2d86133f948b26b"},
+ {file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:f5abc8b4d0c5b556ed8cd41490b606fe99293175a82b98e652c3f2711b452988"},
+ {file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:1e1cf7bc8cbbe6ce3881863671bac258b7d6bfc3706c600008925fb799a256e2"},
+ {file = "frozenlist-1.3.1-cp38-cp38-win32.whl", hash = "sha256:0dde791b9b97f189874d654c55c24bf7b6782343e14909c84beebd28b7217845"},
+ {file = "frozenlist-1.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:9494122bf39da6422b0972c4579e248867b6b1b50c9b05df7e04a3f30b9a413d"},
+ {file = "frozenlist-1.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:31bf9539284f39ff9398deabf5561c2b0da5bb475590b4e13dd8b268d7a3c5c1"},
+ {file = "frozenlist-1.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e0c8c803f2f8db7217898d11657cb6042b9b0553a997c4a0601f48a691480fab"},
+ {file = "frozenlist-1.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da5ba7b59d954f1f214d352308d1d86994d713b13edd4b24a556bcc43d2ddbc3"},
+ {file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74e6b2b456f21fc93ce1aff2b9728049f1464428ee2c9752a4b4f61e98c4db96"},
+ {file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:526d5f20e954d103b1d47232e3839f3453c02077b74203e43407b962ab131e7b"},
+ {file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b499c6abe62a7a8d023e2c4b2834fce78a6115856ae95522f2f974139814538c"},
+ {file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab386503f53bbbc64d1ad4b6865bf001414930841a870fc97f1546d4d133f141"},
+ {file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f63c308f82a7954bf8263a6e6de0adc67c48a8b484fab18ff87f349af356efd"},
+ {file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:12607804084d2244a7bd4685c9d0dca5df17a6a926d4f1967aa7978b1028f89f"},
+ {file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:da1cdfa96425cbe51f8afa43e392366ed0b36ce398f08b60de6b97e3ed4affef"},
+ {file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f810e764617b0748b49a731ffaa525d9bb36ff38332411704c2400125af859a6"},
+ {file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:35c3d79b81908579beb1fb4e7fcd802b7b4921f1b66055af2578ff7734711cfa"},
+ {file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c92deb5d9acce226a501b77307b3b60b264ca21862bd7d3e0c1f3594022f01bc"},
+ {file = "frozenlist-1.3.1-cp39-cp39-win32.whl", hash = "sha256:5e77a8bd41e54b05e4fb2708dc6ce28ee70325f8c6f50f3df86a44ecb1d7a19b"},
+ {file = "frozenlist-1.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:625d8472c67f2d96f9a4302a947f92a7adbc1e20bedb6aff8dbc8ff039ca6189"},
+ {file = "frozenlist-1.3.1.tar.gz", hash = "sha256:3a735e4211a04ccfa3f4833547acdf5d2f863bfeb01cfd3edaffbc251f15cec8"},
+]
+humanfriendly = [
+ {file = "humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477"},
+ {file = "humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc"},
+]
+identify = [
+ {file = "identify-2.5.5-py2.py3-none-any.whl", hash = "sha256:ef78c0d96098a3b5fe7720be4a97e73f439af7cf088ebf47b620aeaa10fadf97"},
+ {file = "identify-2.5.5.tar.gz", hash = "sha256:322a5699daecf7c6fd60e68852f36f2ecbb6a36ff6e6e973e0d2bb6fca203ee6"},
+]
+idna = [
+ {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"},
+ {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
+]
+isort = [
+ {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"},
+ {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"},
+]
+lupa = [
+ {file = "lupa-1.13-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:da1885faca29091f9e408c0cc6b43a0b29a2128acf8d08c188febc5d9f99129d"},
+ {file = "lupa-1.13-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4525e954e951562eb5609eca6ac694d0158a5351649656e50d524f87f71e2a35"},
+ {file = "lupa-1.13-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:5a04febcd3016cb992e6c5b2f97834ad53a2fd4b37767d9afdce116021c2463a"},
+ {file = "lupa-1.13-cp27-cp27m-win32.whl", hash = "sha256:98f6d3debc4d3668e5e19d70e288dbdbbedef021a75ac2e42c450c7679b4bf52"},
+ {file = "lupa-1.13-cp27-cp27m-win_amd64.whl", hash = "sha256:7009719bf65549c018a2f925ff06b9d862a5a1e22f8a7aeeef807eb1e99b56bc"},
+ {file = "lupa-1.13-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bde9e73b06d147d31b970123a013cc6d28a4bea7b3d6b64fe115650cbc62b1a3"},
+ {file = "lupa-1.13-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a122baad6c6f9aaae496a59318217c068ae73654f618526e404a28775b46da38"},
+ {file = "lupa-1.13-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:4d1588486ed16d6b53f41b080047d44db3aa9991cf8a30da844cb97486a63c8b"},
+ {file = "lupa-1.13-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:a79be3ca652c8392d612bdc2234074325a68ec572c4175a35347cd650ef4a4b9"},
+ {file = "lupa-1.13-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:d9105f3b098cd4c276d6258f8254224243066f51c5d3c923b8f460efac9de37b"},
+ {file = "lupa-1.13-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:2d1fbddfa2914c405004f805afb13f5fc385793f3ba28e86a6f0c85b4059b86c"},
+ {file = "lupa-1.13-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5a3c84994399887a8befc82aef4d837582db45a301413025c510e20fef9e9148"},
+ {file = "lupa-1.13-cp310-cp310-win32.whl", hash = "sha256:c665af2a92e79106045f973174e0849f92b44395f5247505d321bc1173d9f3fd"},
+ {file = "lupa-1.13-cp310-cp310-win_amd64.whl", hash = "sha256:c9b47a9e93cb8e8f342343f4e0963eb1966d36baeced482575141925eafc17dc"},
+ {file = "lupa-1.13-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:b3003d723faabb9502259662722462cbff368f26ed83a6311f65949d298593bf"},
+ {file = "lupa-1.13-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b341b8a4711558af771bd4a954a6ffe531bfe097c1f1cdce84b9ad56070dfe90"},
+ {file = "lupa-1.13-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ea049ee507a549eec553a9d27e3e6c034eae8c145e7bad5947e85c4b9e23757b"},
+ {file = "lupa-1.13-cp35-cp35m-win32.whl", hash = "sha256:ba6c49646ad42c836f18ff8f1b6b8db4ca32fc02e786e1bf401b0fa34fe82cca"},
+ {file = "lupa-1.13-cp35-cp35m-win_amd64.whl", hash = "sha256:de51177d1374fd9cce27b9cdb20771142d91a509e42337b3e7c6cffbba818d6f"},
+ {file = "lupa-1.13-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:dddfeb031ab67c8bdbeefd2de237a98bee58e2166d5ed629c3a0c3842bb91738"},
+ {file = "lupa-1.13-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57f00004c185bd60459586a9d08961541f5da1cfec5925a3fc1ab68deaa2e038"},
+ {file = "lupa-1.13-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:a940be5b38b68b344691558ffde1b44377ad66c105661f6f58c7d4c0c227d8ea"},
+ {file = "lupa-1.13-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:807b27c13f7598af9343455204a6a23b6b919180f01668c9b8fa4f9b0d75dedb"},
+ {file = "lupa-1.13-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0a52d5a8305f4854f91ee39f5ee6f175f4d38f362c6b00483fe618ae6f9dff5b"},
+ {file = "lupa-1.13-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0ad47549359df03b3e59796ba09df548e1fd046f9245391dae79699c9ffec0f6"},
+ {file = "lupa-1.13-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:fbf99cea003b38a146dff5333ba58edb8165e01c42f15d7f76fdb72e761b5827"},
+ {file = "lupa-1.13-cp36-cp36m-win32.whl", hash = "sha256:a101c84097fdfa7b1a38f9d5a3055759da4e222c255ab8e5ac5b683704e62c97"},
+ {file = "lupa-1.13-cp36-cp36m-win_amd64.whl", hash = "sha256:00376b3bcb00bb57e067740ea9ff00f610a44aff5338ea93d3198a035f8965c6"},
+ {file = "lupa-1.13-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:91001c9667d60b69c3ad623dc315d7b59712e1617fe6204e5852c31cda778678"},
+ {file = "lupa-1.13-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:65c9d034d7215e8929a4ab48c9d9d372786ef47c8e61c294851bf0b8f5b4fbf4"},
+ {file = "lupa-1.13-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:928527222b2a15bd3dcea646f7585852097302c078c338fb0f184ce560d48c6c"},
+ {file = "lupa-1.13-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:5e157d97e379931a7fa90d9afa66600f796960bc062e04a9bb37f24fa7c5c967"},
+ {file = "lupa-1.13-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a67336d542d71e095c07dacc72c16158745ae4ef08e8a7bfe75827da604b4979"},
+ {file = "lupa-1.13-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0c5cd027c998db5b29ca8dd956c255d50914aed614d1c9edb68bc3315f916f59"},
+ {file = "lupa-1.13-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:76b06355f0b3d3aece5c38d20a66ab7d3046add95b8d04b677ade162fce2ffd0"},
+ {file = "lupa-1.13-cp37-cp37m-win32.whl", hash = "sha256:2a6b0a7e45390de36d11dd8705b2a0a10739ba8ed2e99c130e983ad72d56ddc9"},
+ {file = "lupa-1.13-cp37-cp37m-win_amd64.whl", hash = "sha256:42ffbe43119225cc58c7ebd2210123b9367b098ac25a7f0ef5d473e2f65fc0d9"},
+ {file = "lupa-1.13-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:7ff445a5d8ab25e623f871c600af58f1cd6207f6873a42c3b8c1683f13a22db0"},
+ {file = "lupa-1.13-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:dd0404f11b9473372fe2a8bdf0d64b361852ae08699d6dcde1215db3bd6c7b9c"},
+ {file = "lupa-1.13-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:14419b29152667fb2d78c6d5176f9a704c765aeecb80fe6c079a8dba9f864529"},
+ {file = "lupa-1.13-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:9e644032b40b59420ffa0d58ca1705351785ce8e39b77d9f1a8c4cf78e371adb"},
+ {file = "lupa-1.13-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c090991e2b701ded6c9e330ea582a74dd9cb09069b3de9ae897b938bd97dc98f"},
+ {file = "lupa-1.13-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6812f16530a1dc88f66c76a002e1c16039d3d98e1ff283a2efd5a492342ba00c"},
+ {file = "lupa-1.13-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ff3989ab562fb62e9df2290739c7f82e05d5ba7d2fa2ea319991885dfc818c81"},
+ {file = "lupa-1.13-cp38-cp38-win32.whl", hash = "sha256:48fa15cf24d297c50f21bff1fe1883f7a6a15b34b70db5a6c18d2dfbed6b6e16"},
+ {file = "lupa-1.13-cp38-cp38-win_amd64.whl", hash = "sha256:ea32a62d404c3d9e119e83b653aa56c034cae63a4e830aefa15bf3a25299b29e"},
+ {file = "lupa-1.13-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:80d36fbdc6218332232b4c214a2f9c36b13136b546dca0b3d19aca12d77e1f8e"},
+ {file = "lupa-1.13-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:db4745132f8abe0c9daac155af9d196926c9e10662d999edd805756d91502a01"},
+ {file = "lupa-1.13-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:938fb12c556737f9e4ffb7912540e35423d1be3166c6d4099ca4f3e177fe619e"},
+ {file = "lupa-1.13-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:de913a471ee6dc86435b647dda3cdb787990b164d8c8c63ca03d6e934f305a55"},
+ {file = "lupa-1.13-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:488d1bd773f10331ca67b0914c880900316634fd14538f76c3c2fbc7e6b56043"},
+ {file = "lupa-1.13-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:dc101e6d82ffa1b3fcfc77f2430a10c02def972cf0f8c7a229e272697e22e35c"},
+ {file = "lupa-1.13-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:361a55883b692d25478a69104d8ecce4cad058ba39ec1b7378b1209f86867687"},
+ {file = "lupa-1.13-cp39-cp39-win32.whl", hash = "sha256:9a6cd192e789fbc7f6a777a17b5b517c447a6dc6049e60c1becb300f86205345"},
+ {file = "lupa-1.13-cp39-cp39-win_amd64.whl", hash = "sha256:9fe47cda7cc81bd9b111f1317ed60e3da2620f4fef5360b690dcf62f88bbc668"},
+ {file = "lupa-1.13-pp37-pypy37_pp73-macosx_10_14_x86_64.whl", hash = "sha256:7d860dc0062b3001993355b12b939f68e0e2871a19a81427d2a9ced893574b58"},
+ {file = "lupa-1.13-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:6c0358386f16afb50145b143774791c942c93a9721078a17983486a2d9f8f45b"},
+ {file = "lupa-1.13-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:a46962ebdc6278e82520c66d5dd1eed50099aa2f56b6827b7a4f001664d9ad1d"},
+ {file = "lupa-1.13-pp37-pypy37_pp73-win32.whl", hash = "sha256:436daf32385bcb9b6b9f922cbc0b64d133db141f0f7d8946a3a653e83b478713"},
+ {file = "lupa-1.13-pp38-pypy38_pp73-macosx_10_14_x86_64.whl", hash = "sha256:f1165e89aa8d2a0644619517e04410b9f5e3da2c9b3d105bf53f70e786f91f79"},
+ {file = "lupa-1.13-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:325069e4f3cf4b1232d03fb330ba1449867fc7dd727ecebaf0e602ddcacaf9d4"},
+ {file = "lupa-1.13-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:ce59c335b80ec4f9e98181970c18552f51adba5c3380ef5d46bdb3246b87963d"},
+ {file = "lupa-1.13-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:ad263ba6e54a13ac036364ae43ba7613c869c5ee6ff7dbb86791685a6cba13c5"},
+ {file = "lupa-1.13-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:86f4f46ee854e36cf5b6cf2317075023f395eede53efec0a694bc4a01fc03ab7"},
+ {file = "lupa-1.13-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:59799f40774dd5b8cfb99b11d6ce3a3f3a141e112472874389d47c81a7377ef9"},
+ {file = "lupa-1.13.tar.gz", hash = "sha256:e1d94ac2a630d271027dac2c21d1428771d9ea9d4d88f15f20a7781340f02a4e"},
+]
+lxml = [
+ {file = "lxml-4.9.1-cp27-cp27m-macosx_10_15_x86_64.whl", hash = "sha256:98cafc618614d72b02185ac583c6f7796202062c41d2eeecdf07820bad3295ed"},
+ {file = "lxml-4.9.1-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c62e8dd9754b7debda0c5ba59d34509c4688f853588d75b53c3791983faa96fc"},
+ {file = "lxml-4.9.1-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:21fb3d24ab430fc538a96e9fbb9b150029914805d551deeac7d7822f64631dfc"},
+ {file = "lxml-4.9.1-cp27-cp27m-win32.whl", hash = "sha256:86e92728ef3fc842c50a5cb1d5ba2bc66db7da08a7af53fb3da79e202d1b2cd3"},
+ {file = "lxml-4.9.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4cfbe42c686f33944e12f45a27d25a492cc0e43e1dc1da5d6a87cbcaf2e95627"},
+ {file = "lxml-4.9.1-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dad7b164905d3e534883281c050180afcf1e230c3d4a54e8038aa5cfcf312b84"},
+ {file = "lxml-4.9.1-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a614e4afed58c14254e67862456d212c4dcceebab2eaa44d627c2ca04bf86837"},
+ {file = "lxml-4.9.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:f9ced82717c7ec65a67667bb05865ffe38af0e835cdd78728f1209c8fffe0cad"},
+ {file = "lxml-4.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:d9fc0bf3ff86c17348dfc5d322f627d78273eba545db865c3cd14b3f19e57fa5"},
+ {file = "lxml-4.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e5f66bdf0976ec667fc4594d2812a00b07ed14d1b44259d19a41ae3fff99f2b8"},
+ {file = "lxml-4.9.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:fe17d10b97fdf58155f858606bddb4e037b805a60ae023c009f760d8361a4eb8"},
+ {file = "lxml-4.9.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8caf4d16b31961e964c62194ea3e26a0e9561cdf72eecb1781458b67ec83423d"},
+ {file = "lxml-4.9.1-cp310-cp310-win32.whl", hash = "sha256:4780677767dd52b99f0af1f123bc2c22873d30b474aa0e2fc3fe5e02217687c7"},
+ {file = "lxml-4.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:b122a188cd292c4d2fcd78d04f863b789ef43aa129b233d7c9004de08693728b"},
+ {file = "lxml-4.9.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:be9eb06489bc975c38706902cbc6888f39e946b81383abc2838d186f0e8b6a9d"},
+ {file = "lxml-4.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:f1be258c4d3dc609e654a1dc59d37b17d7fef05df912c01fc2e15eb43a9735f3"},
+ {file = "lxml-4.9.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:927a9dd016d6033bc12e0bf5dee1dde140235fc8d0d51099353c76081c03dc29"},
+ {file = "lxml-4.9.1-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9232b09f5efee6a495a99ae6824881940d6447debe272ea400c02e3b68aad85d"},
+ {file = "lxml-4.9.1-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:04da965dfebb5dac2619cb90fcf93efdb35b3c6994fea58a157a834f2f94b318"},
+ {file = "lxml-4.9.1-cp35-cp35m-win32.whl", hash = "sha256:4d5bae0a37af799207140652a700f21a85946f107a199bcb06720b13a4f1f0b7"},
+ {file = "lxml-4.9.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4878e667ebabe9b65e785ac8da4d48886fe81193a84bbe49f12acff8f7a383a4"},
+ {file = "lxml-4.9.1-cp36-cp36m-macosx_10_15_x86_64.whl", hash = "sha256:1355755b62c28950f9ce123c7a41460ed9743c699905cbe664a5bcc5c9c7c7fb"},
+ {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:bcaa1c495ce623966d9fc8a187da80082334236a2a1c7e141763ffaf7a405067"},
+ {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6eafc048ea3f1b3c136c71a86db393be36b5b3d9c87b1c25204e7d397cee9536"},
+ {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:13c90064b224e10c14dcdf8086688d3f0e612db53766e7478d7754703295c7c8"},
+ {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:206a51077773c6c5d2ce1991327cda719063a47adc02bd703c56a662cdb6c58b"},
+ {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e8f0c9d65da595cfe91713bc1222af9ecabd37971762cb830dea2fc3b3bb2acf"},
+ {file = "lxml-4.9.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8f0a4d179c9a941eb80c3a63cdb495e539e064f8054230844dcf2fcb812b71d3"},
+ {file = "lxml-4.9.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:830c88747dce8a3e7525defa68afd742b4580df6aa2fdd6f0855481e3994d391"},
+ {file = "lxml-4.9.1-cp36-cp36m-win32.whl", hash = "sha256:1e1cf47774373777936c5aabad489fef7b1c087dcd1f426b621fda9dcc12994e"},
+ {file = "lxml-4.9.1-cp36-cp36m-win_amd64.whl", hash = "sha256:5974895115737a74a00b321e339b9c3f45c20275d226398ae79ac008d908bff7"},
+ {file = "lxml-4.9.1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:1423631e3d51008871299525b541413c9b6c6423593e89f9c4cfbe8460afc0a2"},
+ {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:2aaf6a0a6465d39b5ca69688fce82d20088c1838534982996ec46633dc7ad6cc"},
+ {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:9f36de4cd0c262dd9927886cc2305aa3f2210db437aa4fed3fb4940b8bf4592c"},
+ {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:ae06c1e4bc60ee076292e582a7512f304abdf6c70db59b56745cca1684f875a4"},
+ {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:57e4d637258703d14171b54203fd6822fda218c6c2658a7d30816b10995f29f3"},
+ {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6d279033bf614953c3fc4a0aa9ac33a21e8044ca72d4fa8b9273fe75359d5cca"},
+ {file = "lxml-4.9.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a60f90bba4c37962cbf210f0188ecca87daafdf60271f4c6948606e4dabf8785"},
+ {file = "lxml-4.9.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6ca2264f341dd81e41f3fffecec6e446aa2121e0b8d026fb5130e02de1402785"},
+ {file = "lxml-4.9.1-cp37-cp37m-win32.whl", hash = "sha256:27e590352c76156f50f538dbcebd1925317a0f70540f7dc8c97d2931c595783a"},
+ {file = "lxml-4.9.1-cp37-cp37m-win_amd64.whl", hash = "sha256:eea5d6443b093e1545ad0210e6cf27f920482bfcf5c77cdc8596aec73523bb7e"},
+ {file = "lxml-4.9.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:f05251bbc2145349b8d0b77c0d4e5f3b228418807b1ee27cefb11f69ed3d233b"},
+ {file = "lxml-4.9.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:487c8e61d7acc50b8be82bda8c8d21d20e133c3cbf41bd8ad7eb1aaeb3f07c97"},
+ {file = "lxml-4.9.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8d1a92d8e90b286d491e5626af53afef2ba04da33e82e30744795c71880eaa21"},
+ {file = "lxml-4.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:b570da8cd0012f4af9fa76a5635cd31f707473e65a5a335b186069d5c7121ff2"},
+ {file = "lxml-4.9.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ef87fca280fb15342726bd5f980f6faf8b84a5287fcc2d4962ea8af88b35130"},
+ {file = "lxml-4.9.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:93e414e3206779ef41e5ff2448067213febf260ba747fc65389a3ddaa3fb8715"},
+ {file = "lxml-4.9.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6653071f4f9bac46fbc30f3c7838b0e9063ee335908c5d61fb7a4a86c8fd2036"},
+ {file = "lxml-4.9.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:32a73c53783becdb7eaf75a2a1525ea8e49379fb7248c3eeefb9412123536387"},
+ {file = "lxml-4.9.1-cp38-cp38-win32.whl", hash = "sha256:1a7c59c6ffd6ef5db362b798f350e24ab2cfa5700d53ac6681918f314a4d3b94"},
+ {file = "lxml-4.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:1436cf0063bba7888e43f1ba8d58824f085410ea2025befe81150aceb123e345"},
+ {file = "lxml-4.9.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:4beea0f31491bc086991b97517b9683e5cfb369205dac0148ef685ac12a20a67"},
+ {file = "lxml-4.9.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:41fb58868b816c202e8881fd0f179a4644ce6e7cbbb248ef0283a34b73ec73bb"},
+ {file = "lxml-4.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:bd34f6d1810d9354dc7e35158aa6cc33456be7706df4420819af6ed966e85448"},
+ {file = "lxml-4.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:edffbe3c510d8f4bf8640e02ca019e48a9b72357318383ca60e3330c23aaffc7"},
+ {file = "lxml-4.9.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6d949f53ad4fc7cf02c44d6678e7ff05ec5f5552b235b9e136bd52e9bf730b91"},
+ {file = "lxml-4.9.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:079b68f197c796e42aa80b1f739f058dcee796dc725cc9a1be0cdb08fc45b000"},
+ {file = "lxml-4.9.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9c3a88d20e4fe4a2a4a84bf439a5ac9c9aba400b85244c63a1ab7088f85d9d25"},
+ {file = "lxml-4.9.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4e285b5f2bf321fc0857b491b5028c5f276ec0c873b985d58d7748ece1d770dd"},
+ {file = "lxml-4.9.1-cp39-cp39-win32.whl", hash = "sha256:ef72013e20dd5ba86a8ae1aed7f56f31d3374189aa8b433e7b12ad182c0d2dfb"},
+ {file = "lxml-4.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:10d2017f9150248563bb579cd0d07c61c58da85c922b780060dcc9a3aa9f432d"},
+ {file = "lxml-4.9.1-pp37-pypy37_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0538747a9d7827ce3e16a8fdd201a99e661c7dee3c96c885d8ecba3c35d1032c"},
+ {file = "lxml-4.9.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:0645e934e940107e2fdbe7c5b6fb8ec6232444260752598bc4d09511bd056c0b"},
+ {file = "lxml-4.9.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:6daa662aba22ef3258934105be2dd9afa5bb45748f4f702a3b39a5bf53a1f4dc"},
+ {file = "lxml-4.9.1-pp38-pypy38_pp73-macosx_10_15_x86_64.whl", hash = "sha256:603a464c2e67d8a546ddaa206d98e3246e5db05594b97db844c2f0a1af37cf5b"},
+ {file = "lxml-4.9.1-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:c4b2e0559b68455c085fb0f6178e9752c4be3bba104d6e881eb5573b399d1eb2"},
+ {file = "lxml-4.9.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0f3f0059891d3254c7b5fb935330d6db38d6519ecd238ca4fce93c234b4a0f73"},
+ {file = "lxml-4.9.1-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:c852b1530083a620cb0de5f3cd6826f19862bafeaf77586f1aef326e49d95f0c"},
+ {file = "lxml-4.9.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:287605bede6bd36e930577c5925fcea17cb30453d96a7b4c63c14a257118dbb9"},
+ {file = "lxml-4.9.1.tar.gz", hash = "sha256:fe749b052bb7233fe5d072fcb549221a8cb1a16725c47c37e42b0b9cb3ff2c3f"},
+]
+mccabe = [
+ {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"},
+ {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"},
+]
+mslex = [
+ {file = "mslex-0.3.0-py2.py3-none-any.whl", hash = "sha256:380cb14abf8fabf40e56df5c8b21a6d533dc5cbdcfe42406bbf08dda8f42e42a"},
+ {file = "mslex-0.3.0.tar.gz", hash = "sha256:4a1ac3f25025cad78ad2fe499dd16d42759f7a3801645399cce5c404415daa97"},
+]
+multidict = [
+ {file = "multidict-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b9e95a740109c6047602f4db4da9949e6c5945cefbad34a1299775ddc9a62e2"},
+ {file = "multidict-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac0e27844758d7177989ce406acc6a83c16ed4524ebc363c1f748cba184d89d3"},
+ {file = "multidict-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:041b81a5f6b38244b34dc18c7b6aba91f9cdaf854d9a39e5ff0b58e2b5773b9c"},
+ {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fdda29a3c7e76a064f2477c9aab1ba96fd94e02e386f1e665bca1807fc5386f"},
+ {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3368bf2398b0e0fcbf46d85795adc4c259299fec50c1416d0f77c0a843a3eed9"},
+ {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4f052ee022928d34fe1f4d2bc743f32609fb79ed9c49a1710a5ad6b2198db20"},
+ {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:225383a6603c086e6cef0f2f05564acb4f4d5f019a4e3e983f572b8530f70c88"},
+ {file = "multidict-6.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50bd442726e288e884f7be9071016c15a8742eb689a593a0cac49ea093eef0a7"},
+ {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:47e6a7e923e9cada7c139531feac59448f1f47727a79076c0b1ee80274cd8eee"},
+ {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0556a1d4ea2d949efe5fd76a09b4a82e3a4a30700553a6725535098d8d9fb672"},
+ {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:626fe10ac87851f4cffecee161fc6f8f9853f0f6f1035b59337a51d29ff3b4f9"},
+ {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:8064b7c6f0af936a741ea1efd18690bacfbae4078c0c385d7c3f611d11f0cf87"},
+ {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2d36e929d7f6a16d4eb11b250719c39560dd70545356365b494249e2186bc389"},
+ {file = "multidict-6.0.2-cp310-cp310-win32.whl", hash = "sha256:fcb91630817aa8b9bc4a74023e4198480587269c272c58b3279875ed7235c293"},
+ {file = "multidict-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:8cbf0132f3de7cc6c6ce00147cc78e6439ea736cee6bca4f068bcf892b0fd658"},
+ {file = "multidict-6.0.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:05f6949d6169878a03e607a21e3b862eaf8e356590e8bdae4227eedadacf6e51"},
+ {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2c2e459f7050aeb7c1b1276763364884595d47000c1cddb51764c0d8976e608"},
+ {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d0509e469d48940147e1235d994cd849a8f8195e0bca65f8f5439c56e17872a3"},
+ {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:514fe2b8d750d6cdb4712346a2c5084a80220821a3e91f3f71eec11cf8d28fd4"},
+ {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19adcfc2a7197cdc3987044e3f415168fc5dc1f720c932eb1ef4f71a2067e08b"},
+ {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9d153e7f1f9ba0b23ad1568b3b9e17301e23b042c23870f9ee0522dc5cc79e8"},
+ {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:aef9cc3d9c7d63d924adac329c33835e0243b5052a6dfcbf7732a921c6e918ba"},
+ {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4571f1beddff25f3e925eea34268422622963cd8dc395bb8778eb28418248e43"},
+ {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:d48b8ee1d4068561ce8033d2c344cf5232cb29ee1a0206a7b828c79cbc5982b8"},
+ {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:45183c96ddf61bf96d2684d9fbaf6f3564d86b34cb125761f9a0ef9e36c1d55b"},
+ {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:75bdf08716edde767b09e76829db8c1e5ca9d8bb0a8d4bd94ae1eafe3dac5e15"},
+ {file = "multidict-6.0.2-cp37-cp37m-win32.whl", hash = "sha256:a45e1135cb07086833ce969555df39149680e5471c04dfd6a915abd2fc3f6dbc"},
+ {file = "multidict-6.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6f3cdef8a247d1eafa649085812f8a310e728bdf3900ff6c434eafb2d443b23a"},
+ {file = "multidict-6.0.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0327292e745a880459ef71be14e709aaea2f783f3537588fb4ed09b6c01bca60"},
+ {file = "multidict-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e875b6086e325bab7e680e4316d667fc0e5e174bb5611eb16b3ea121c8951b86"},
+ {file = "multidict-6.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:feea820722e69451743a3d56ad74948b68bf456984d63c1a92e8347b7b88452d"},
+ {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cc57c68cb9139c7cd6fc39f211b02198e69fb90ce4bc4a094cf5fe0d20fd8b0"},
+ {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:497988d6b6ec6ed6f87030ec03280b696ca47dbf0648045e4e1d28b80346560d"},
+ {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:89171b2c769e03a953d5969b2f272efa931426355b6c0cb508022976a17fd376"},
+ {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:684133b1e1fe91eda8fa7447f137c9490a064c6b7f392aa857bba83a28cfb693"},
+ {file = "multidict-6.0.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd9fc9c4849a07f3635ccffa895d57abce554b467d611a5009ba4f39b78a8849"},
+ {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e07c8e79d6e6fd37b42f3250dba122053fddb319e84b55dd3a8d6446e1a7ee49"},
+ {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4070613ea2227da2bfb2c35a6041e4371b0af6b0be57f424fe2318b42a748516"},
+ {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:47fbeedbf94bed6547d3aa632075d804867a352d86688c04e606971595460227"},
+ {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:5774d9218d77befa7b70d836004a768fb9aa4fdb53c97498f4d8d3f67bb9cfa9"},
+ {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2957489cba47c2539a8eb7ab32ff49101439ccf78eab724c828c1a54ff3ff98d"},
+ {file = "multidict-6.0.2-cp38-cp38-win32.whl", hash = "sha256:e5b20e9599ba74391ca0cfbd7b328fcc20976823ba19bc573983a25b32e92b57"},
+ {file = "multidict-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:8004dca28e15b86d1b1372515f32eb6f814bdf6f00952699bdeb541691091f96"},
+ {file = "multidict-6.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2e4a0785b84fb59e43c18a015ffc575ba93f7d1dbd272b4cdad9f5134b8a006c"},
+ {file = "multidict-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6701bf8a5d03a43375909ac91b6980aea74b0f5402fbe9428fc3f6edf5d9677e"},
+ {file = "multidict-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a007b1638e148c3cfb6bf0bdc4f82776cef0ac487191d093cdc316905e504071"},
+ {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07a017cfa00c9890011628eab2503bee5872f27144936a52eaab449be5eaf032"},
+ {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c207fff63adcdf5a485969131dc70e4b194327666b7e8a87a97fbc4fd80a53b2"},
+ {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:373ba9d1d061c76462d74e7de1c0c8e267e9791ee8cfefcf6b0b2495762c370c"},
+ {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfba7c6d5d7c9099ba21f84662b037a0ffd4a5e6b26ac07d19e423e6fdf965a9"},
+ {file = "multidict-6.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19d9bad105dfb34eb539c97b132057a4e709919ec4dd883ece5838bcbf262b80"},
+ {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:de989b195c3d636ba000ee4281cd03bb1234635b124bf4cd89eeee9ca8fcb09d"},
+ {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7c40b7bbece294ae3a87c1bc2abff0ff9beef41d14188cda94ada7bcea99b0fb"},
+ {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:d16cce709ebfadc91278a1c005e3c17dd5f71f5098bfae1035149785ea6e9c68"},
+ {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:a2c34a93e1d2aa35fbf1485e5010337c72c6791407d03aa5f4eed920343dd360"},
+ {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:feba80698173761cddd814fa22e88b0661e98cb810f9f986c54aa34d281e4937"},
+ {file = "multidict-6.0.2-cp39-cp39-win32.whl", hash = "sha256:23b616fdc3c74c9fe01d76ce0d1ce872d2d396d8fa8e4899398ad64fb5aa214a"},
+ {file = "multidict-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:4bae31803d708f6f15fd98be6a6ac0b6958fcf68fda3c77a048a4f9073704aae"},
+ {file = "multidict-6.0.2.tar.gz", hash = "sha256:5ff3bd75f38e4c43f1f470f2df7a4d430b821c4ce22be384e1459cb57d6bb013"},
+]
+nodeenv = [
+ {file = "nodeenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"},
+ {file = "nodeenv-1.7.0.tar.gz", hash = "sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b"},
+]
+packaging = [
+ {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
+ {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
+]
+pep8-naming = [
+ {file = "pep8-naming-0.13.2.tar.gz", hash = "sha256:93eef62f525fd12a6f8c98f4dcc17fa70baae2f37fa1f73bec00e3e44392fa48"},
+ {file = "pep8_naming-0.13.2-py3-none-any.whl", hash = "sha256:59e29e55c478db69cffbe14ab24b5bd2cd615c0413edf790d47d3fb7ba9a4e23"},
+]
+Pillow = [
+ {file = "Pillow-9.2.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:a9c9bc489f8ab30906d7a85afac4b4944a572a7432e00698a7239f44a44e6efb"},
+ {file = "Pillow-9.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:510cef4a3f401c246cfd8227b300828715dd055463cdca6176c2e4036df8bd4f"},
+ {file = "Pillow-9.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7888310f6214f19ab2b6df90f3f06afa3df7ef7355fc025e78a3044737fab1f5"},
+ {file = "Pillow-9.2.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:831e648102c82f152e14c1a0938689dbb22480c548c8d4b8b248b3e50967b88c"},
+ {file = "Pillow-9.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1cc1d2451e8a3b4bfdb9caf745b58e6c7a77d2e469159b0d527a4554d73694d1"},
+ {file = "Pillow-9.2.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:136659638f61a251e8ed3b331fc6ccd124590eeff539de57c5f80ef3a9594e58"},
+ {file = "Pillow-9.2.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:6e8c66f70fb539301e064f6478d7453e820d8a2c631da948a23384865cd95544"},
+ {file = "Pillow-9.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:37ff6b522a26d0538b753f0b4e8e164fdada12db6c6f00f62145d732d8a3152e"},
+ {file = "Pillow-9.2.0-cp310-cp310-win32.whl", hash = "sha256:c79698d4cd9318d9481d89a77e2d3fcaeff5486be641e60a4b49f3d2ecca4e28"},
+ {file = "Pillow-9.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:254164c57bab4b459f14c64e93df11eff5ded575192c294a0c49270f22c5d93d"},
+ {file = "Pillow-9.2.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:adabc0bce035467fb537ef3e5e74f2847c8af217ee0be0455d4fec8adc0462fc"},
+ {file = "Pillow-9.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:336b9036127eab855beec9662ac3ea13a4544a523ae273cbf108b228ecac8437"},
+ {file = "Pillow-9.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50dff9cc21826d2977ef2d2a205504034e3a4563ca6f5db739b0d1026658e004"},
+ {file = "Pillow-9.2.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cb6259196a589123d755380b65127ddc60f4c64b21fc3bb46ce3a6ea663659b0"},
+ {file = "Pillow-9.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b0554af24df2bf96618dac71ddada02420f946be943b181108cac55a7a2dcd4"},
+ {file = "Pillow-9.2.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:15928f824870535c85dbf949c09d6ae7d3d6ac2d6efec80f3227f73eefba741c"},
+ {file = "Pillow-9.2.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:bdd0de2d64688ecae88dd8935012c4a72681e5df632af903a1dca8c5e7aa871a"},
+ {file = "Pillow-9.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d5b87da55a08acb586bad5c3aa3b86505f559b84f39035b233d5bf844b0834b1"},
+ {file = "Pillow-9.2.0-cp311-cp311-win32.whl", hash = "sha256:b6d5e92df2b77665e07ddb2e4dbd6d644b78e4c0d2e9272a852627cdba0d75cf"},
+ {file = "Pillow-9.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6bf088c1ce160f50ea40764f825ec9b72ed9da25346216b91361eef8ad1b8f8c"},
+ {file = "Pillow-9.2.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:2c58b24e3a63efd22554c676d81b0e57f80e0a7d3a5874a7e14ce90ec40d3069"},
+ {file = "Pillow-9.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eef7592281f7c174d3d6cbfbb7ee5984a671fcd77e3fc78e973d492e9bf0eb3f"},
+ {file = "Pillow-9.2.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dcd7b9c7139dc8258d164b55696ecd16c04607f1cc33ba7af86613881ffe4ac8"},
+ {file = "Pillow-9.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a138441e95562b3c078746a22f8fca8ff1c22c014f856278bdbdd89ca36cff1b"},
+ {file = "Pillow-9.2.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:93689632949aff41199090eff5474f3990b6823404e45d66a5d44304e9cdc467"},
+ {file = "Pillow-9.2.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:f3fac744f9b540148fa7715a435d2283b71f68bfb6d4aae24482a890aed18b59"},
+ {file = "Pillow-9.2.0-cp37-cp37m-win32.whl", hash = "sha256:fa768eff5f9f958270b081bb33581b4b569faabf8774726b283edb06617101dc"},
+ {file = "Pillow-9.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:69bd1a15d7ba3694631e00df8de65a8cb031911ca11f44929c97fe05eb9b6c1d"},
+ {file = "Pillow-9.2.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:030e3460861488e249731c3e7ab59b07c7853838ff3b8e16aac9561bb345da14"},
+ {file = "Pillow-9.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:74a04183e6e64930b667d321524e3c5361094bb4af9083db5c301db64cd341f3"},
+ {file = "Pillow-9.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d33a11f601213dcd5718109c09a52c2a1c893e7461f0be2d6febc2879ec2402"},
+ {file = "Pillow-9.2.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fd6f5e3c0e4697fa7eb45b6e93996299f3feee73a3175fa451f49a74d092b9f"},
+ {file = "Pillow-9.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a647c0d4478b995c5e54615a2e5360ccedd2f85e70ab57fbe817ca613d5e63b8"},
+ {file = "Pillow-9.2.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:4134d3f1ba5f15027ff5c04296f13328fecd46921424084516bdb1b2548e66ff"},
+ {file = "Pillow-9.2.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:bc431b065722a5ad1dfb4df354fb9333b7a582a5ee39a90e6ffff688d72f27a1"},
+ {file = "Pillow-9.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:1536ad017a9f789430fb6b8be8bf99d2f214c76502becc196c6f2d9a75b01b76"},
+ {file = "Pillow-9.2.0-cp38-cp38-win32.whl", hash = "sha256:2ad0d4df0f5ef2247e27fc790d5c9b5a0af8ade9ba340db4a73bb1a4a3e5fb4f"},
+ {file = "Pillow-9.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:ec52c351b35ca269cb1f8069d610fc45c5bd38c3e91f9ab4cbbf0aebc136d9c8"},
+ {file = "Pillow-9.2.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0ed2c4ef2451de908c90436d6e8092e13a43992f1860275b4d8082667fbb2ffc"},
+ {file = "Pillow-9.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ad2f835e0ad81d1689f1b7e3fbac7b01bb8777d5a985c8962bedee0cc6d43da"},
+ {file = "Pillow-9.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea98f633d45f7e815db648fd7ff0f19e328302ac36427343e4432c84432e7ff4"},
+ {file = "Pillow-9.2.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7761afe0126d046974a01e030ae7529ed0ca6a196de3ec6937c11df0df1bc91c"},
+ {file = "Pillow-9.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a54614049a18a2d6fe156e68e188da02a046a4a93cf24f373bffd977e943421"},
+ {file = "Pillow-9.2.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:5aed7dde98403cd91d86a1115c78d8145c83078e864c1de1064f52e6feb61b20"},
+ {file = "Pillow-9.2.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:13b725463f32df1bfeacbf3dd197fb358ae8ebcd8c5548faa75126ea425ccb60"},
+ {file = "Pillow-9.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:808add66ea764ed97d44dda1ac4f2cfec4c1867d9efb16a33d158be79f32b8a4"},
+ {file = "Pillow-9.2.0-cp39-cp39-win32.whl", hash = "sha256:337a74fd2f291c607d220c793a8135273c4c2ab001b03e601c36766005f36885"},
+ {file = "Pillow-9.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:fac2d65901fb0fdf20363fbd345c01958a742f2dc62a8dd4495af66e3ff502a4"},
+ {file = "Pillow-9.2.0-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:ad2277b185ebce47a63f4dc6302e30f05762b688f8dc3de55dbae4651872cdf3"},
+ {file = "Pillow-9.2.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c7b502bc34f6e32ba022b4a209638f9e097d7a9098104ae420eb8186217ebbb"},
+ {file = "Pillow-9.2.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d1f14f5f691f55e1b47f824ca4fdcb4b19b4323fe43cc7bb105988cad7496be"},
+ {file = "Pillow-9.2.0-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:dfe4c1fedfde4e2fbc009d5ad420647f7730d719786388b7de0999bf32c0d9fd"},
+ {file = "Pillow-9.2.0-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:f07f1f00e22b231dd3d9b9208692042e29792d6bd4f6639415d2f23158a80013"},
+ {file = "Pillow-9.2.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1802f34298f5ba11d55e5bb09c31997dc0c6aed919658dfdf0198a2fe75d5490"},
+ {file = "Pillow-9.2.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17d4cafe22f050b46d983b71c707162d63d796a1235cdf8b9d7a112e97b15bac"},
+ {file = "Pillow-9.2.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:96b5e6874431df16aee0c1ba237574cb6dff1dcb173798faa6a9d8b399a05d0e"},
+ {file = "Pillow-9.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:0030fdbd926fb85844b8b92e2f9449ba89607231d3dd597a21ae72dc7fe26927"},
+ {file = "Pillow-9.2.0.tar.gz", hash = "sha256:75e636fd3e0fb872693f23ccb8a5ff2cd578801251f3a4f6854c6a5d437d3c04"},
+]
+pip-licenses = [
+ {file = "pip-licenses-3.5.5.tar.gz", hash = "sha256:748cfd7aca6e05032f9fa85691301295f4d943e87955be6914ca49abe3c075a4"},
+ {file = "pip_licenses-3.5.5-py3-none-any.whl", hash = "sha256:6129c116bab2b202d90d6e3a96092df4ad84c0c4d57bb70192fc03f8bf06d181"},
+]
+platformdirs = [
+ {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"},
+ {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"},
+]
+pre-commit = [
+ {file = "pre_commit-2.20.0-py2.py3-none-any.whl", hash = "sha256:51a5ba7c480ae8072ecdb6933df22d2f812dc897d5fe848778116129a681aac7"},
+ {file = "pre_commit-2.20.0.tar.gz", hash = "sha256:a978dac7bc9ec0bcee55c18a277d553b0f419d259dadb4b9418ff2d00eb43959"},
+]
+psutil = [
+ {file = "psutil-5.9.2-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:8f024fbb26c8daf5d70287bb3edfafa22283c255287cf523c5d81721e8e5d82c"},
+ {file = "psutil-5.9.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:b2f248ffc346f4f4f0d747ee1947963613216b06688be0be2e393986fe20dbbb"},
+ {file = "psutil-5.9.2-cp27-cp27m-win32.whl", hash = "sha256:b1928b9bf478d31fdffdb57101d18f9b70ed4e9b0e41af751851813547b2a9ab"},
+ {file = "psutil-5.9.2-cp27-cp27m-win_amd64.whl", hash = "sha256:404f4816c16a2fcc4eaa36d7eb49a66df2d083e829d3e39ee8759a411dbc9ecf"},
+ {file = "psutil-5.9.2-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:94e621c6a4ddb2573d4d30cba074f6d1aa0186645917df42c811c473dd22b339"},
+ {file = "psutil-5.9.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:256098b4f6ffea6441eb54ab3eb64db9ecef18f6a80d7ba91549195d55420f84"},
+ {file = "psutil-5.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:614337922702e9be37a39954d67fdb9e855981624d8011a9927b8f2d3c9625d9"},
+ {file = "psutil-5.9.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:39ec06dc6c934fb53df10c1672e299145ce609ff0611b569e75a88f313634969"},
+ {file = "psutil-5.9.2-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3ac2c0375ef498e74b9b4ec56df3c88be43fe56cac465627572dbfb21c4be34"},
+ {file = "psutil-5.9.2-cp310-cp310-win32.whl", hash = "sha256:e4c4a7636ffc47b7141864f1c5e7d649f42c54e49da2dd3cceb1c5f5d29bfc85"},
+ {file = "psutil-5.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:f4cb67215c10d4657e320037109939b1c1d2fd70ca3d76301992f89fe2edb1f1"},
+ {file = "psutil-5.9.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:dc9bda7d5ced744622f157cc8d8bdd51735dafcecff807e928ff26bdb0ff097d"},
+ {file = "psutil-5.9.2-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d75291912b945a7351d45df682f9644540d564d62115d4a20d45fa17dc2d48f8"},
+ {file = "psutil-5.9.2-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4018d5f9b6651f9896c7a7c2c9f4652e4eea53f10751c4e7d08a9093ab587ec"},
+ {file = "psutil-5.9.2-cp36-cp36m-win32.whl", hash = "sha256:f40ba362fefc11d6bea4403f070078d60053ed422255bd838cd86a40674364c9"},
+ {file = "psutil-5.9.2-cp36-cp36m-win_amd64.whl", hash = "sha256:9770c1d25aee91417eba7869139d629d6328a9422ce1cdd112bd56377ca98444"},
+ {file = "psutil-5.9.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:42638876b7f5ef43cef8dcf640d3401b27a51ee3fa137cb2aa2e72e188414c32"},
+ {file = "psutil-5.9.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91aa0dac0c64688667b4285fa29354acfb3e834e1fd98b535b9986c883c2ce1d"},
+ {file = "psutil-5.9.2-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4fb54941aac044a61db9d8eb56fc5bee207db3bc58645d657249030e15ba3727"},
+ {file = "psutil-5.9.2-cp37-cp37m-win32.whl", hash = "sha256:7cbb795dcd8ed8fd238bc9e9f64ab188f3f4096d2e811b5a82da53d164b84c3f"},
+ {file = "psutil-5.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:5d39e3a2d5c40efa977c9a8dd4f679763c43c6c255b1340a56489955dbca767c"},
+ {file = "psutil-5.9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fd331866628d18223a4265371fd255774affd86244fc307ef66eaf00de0633d5"},
+ {file = "psutil-5.9.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b315febaebae813326296872fdb4be92ad3ce10d1d742a6b0c49fb619481ed0b"},
+ {file = "psutil-5.9.2-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7929a516125f62399d6e8e026129c8835f6c5a3aab88c3fff1a05ee8feb840d"},
+ {file = "psutil-5.9.2-cp38-cp38-win32.whl", hash = "sha256:561dec454853846d1dd0247b44c2e66a0a0c490f937086930ec4b8f83bf44f06"},
+ {file = "psutil-5.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:67b33f27fc0427483b61563a16c90d9f3b547eeb7af0ef1b9fe024cdc9b3a6ea"},
+ {file = "psutil-5.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b3591616fa07b15050b2f87e1cdefd06a554382e72866fcc0ab2be9d116486c8"},
+ {file = "psutil-5.9.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14b29f581b5edab1f133563272a6011925401804d52d603c5c606936b49c8b97"},
+ {file = "psutil-5.9.2-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4642fd93785a29353d6917a23e2ac6177308ef5e8be5cc17008d885cb9f70f12"},
+ {file = "psutil-5.9.2-cp39-cp39-win32.whl", hash = "sha256:ed29ea0b9a372c5188cdb2ad39f937900a10fb5478dc077283bf86eeac678ef1"},
+ {file = "psutil-5.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:68b35cbff92d1f7103d8f1db77c977e72f49fcefae3d3d2b91c76b0e7aef48b8"},
+ {file = "psutil-5.9.2.tar.gz", hash = "sha256:feb861a10b6c3bb00701063b37e4afc754f8217f0f09c42280586bd6ac712b5c"},
+]
+PTable = [
+ {file = "PTable-0.9.2.tar.gz", hash = "sha256:aa7fc151cb40f2dabcd2275ba6f7fd0ff8577a86be3365cd3fb297cbe09cc292"},
+]
+pycares = [
+ {file = "pycares-4.2.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5dc6418e87729105d93162155793002b3fa95490e2f2df33afec08b0b0d44989"},
+ {file = "pycares-4.2.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9481ee42df7e34c9ef7b2f045e534062b980b2c971677868df9f17730b147ceb"},
+ {file = "pycares-4.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05e029e594c27a0066cdb89dfc5bba28ba94e2b27b0ca7aceb94f9aea06812cd"},
+ {file = "pycares-4.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0eb203ceedcf7f9865ed3abb6128dfbb3498c5e76342e3c820c4274cc0c8e873"},
+ {file = "pycares-4.2.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4a01ba75e8a2947fc0b954850f8db9d52166634a206056febef2f833c8cfa1e"},
+ {file = "pycares-4.2.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:064543e222e3587a92bccae704fcc5f4ce1ba1ce66aac96483c9cf504d554a67"},
+ {file = "pycares-4.2.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a5a28f1d041aa2102bd2512e7361671e4ef46bc927e95b6932ed95cc45273480"},
+ {file = "pycares-4.2.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:650b16f025bd3dad6a331e63bb8c9d55994c1b5d0d289ebe03c0bc16edad114f"},
+ {file = "pycares-4.2.2-cp310-cp310-win32.whl", hash = "sha256:f8b76c13275b319b850e28bb9b3f5815de7521b1e0a581453d1acf10011bafef"},
+ {file = "pycares-4.2.2-cp310-cp310-win_amd64.whl", hash = "sha256:bcfcafbb376376c9cca6d37a8497dfd6dbd82333bf37627067b34dcaf5039612"},
+ {file = "pycares-4.2.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ae5accd693c6910bbd1a99d1f4551a9e99decd65d792a80f10c27b8fcc32b497"},
+ {file = "pycares-4.2.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f1901b309cb5cf7ade5822d74b904f55c49369e4ff9328818e554d4c34b4714"},
+ {file = "pycares-4.2.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bc61edb98aff9cb4b2e07c25383100b81459a676ca0b0bd5fe77226eb1f850e"},
+ {file = "pycares-4.2.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:241155687db7b45cb4ef84a18755ebc78c3ad624fd2578b48ea52ac16a4c8d9f"},
+ {file = "pycares-4.2.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:27a21184ba35fff12eec36375d5b064516a0c3401dbf66a7eded7da34c5ca282"},
+ {file = "pycares-4.2.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:8a376e637ecd79db62761ca40cda080b9383a07d6dedbc799dd1a31e053862d9"},
+ {file = "pycares-4.2.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:6c411610be8de17cd5257845ebba5104b8e6356c62e66768728985a2ac0e9d1c"},
+ {file = "pycares-4.2.2-cp36-cp36m-win32.whl", hash = "sha256:6a5af6443a1cefb36ddca47af37e29cae94a734c6c7cea3eb94e5de5cc2a4f1a"},
+ {file = "pycares-4.2.2-cp36-cp36m-win_amd64.whl", hash = "sha256:a01ab41405dd4dd8449f9323b2dac25e1d856ef02d85c8aedea0130b65275b2a"},
+ {file = "pycares-4.2.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9a2053b34163d13d6d135248c65e71cefce3f25b3611677a1428ec7a57bae856"},
+ {file = "pycares-4.2.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8064eaae5084e5155008b8f9d089055a432ff2115960273fc570f55dccedf666"},
+ {file = "pycares-4.2.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc045040c094068d5de28e61a6fd0babe8522e8f61829839b893f7aff928173b"},
+ {file = "pycares-4.2.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:135a356d52773f02d7babd2b38ad64493418363274972cc786fdce847875ca03"},
+ {file = "pycares-4.2.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:512fb2c04c28e0e5a7de0b61624ab9c15d2df52db113f63a0aba6c6f1174b92f"},
+ {file = "pycares-4.2.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:0eb374525c6231920509612f197ca47bdaa6ec9a0728aa199ba536dc0c25bb55"},
+ {file = "pycares-4.2.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:47c6e18bbe6f2f4ce42fbdfa4ab2602268590f76110f06af60d02f964b72fada"},
+ {file = "pycares-4.2.2-cp37-cp37m-win32.whl", hash = "sha256:a2c7fb5d3cb633e3f23344194da9b5caa54eb40da34dbe4465f0ebcede2e1e1a"},
+ {file = "pycares-4.2.2-cp37-cp37m-win_amd64.whl", hash = "sha256:90f374fae2af5eb728841b4c2a0c8038a6889ba2a5a421e4c4e4e0f15bcc5912"},
+ {file = "pycares-4.2.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8c0a7e0f9371c47cf028e2389f11385e906ba2797900419509adfa86587a2ac"},
+ {file = "pycares-4.2.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0fb3944af9492cfde6e1167780c9b8a701a56cf7d3fb29086cfb906b8261648f"},
+ {file = "pycares-4.2.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7466315e76ab0ca4dc1354f3d7cb53f6d99d365b3778d9849e52643270beb6f2"},
+ {file = "pycares-4.2.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46f58398bd9fa99cc2dd79f7fecddc85837ccb452d673168037ea603b15aa11b"},
+ {file = "pycares-4.2.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47eae9809826cea5c0eb08eec9da584dd6330e51c075c2f6963ca2067555cd07"},
+ {file = "pycares-4.2.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6cbd4df536d2c32d2d74b854db25f1d15cc61cdd182b03206afbd7ccbe7b8f11"},
+ {file = "pycares-4.2.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3e4519bc51b744331c968eef0bd0071ca9c3e5863b8b8c1d99540ab8bfb04235"},
+ {file = "pycares-4.2.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5e2af8ca3bc49894a87d2b5629b993c22b0e602ecb7fd2fad660ebb9be584829"},
+ {file = "pycares-4.2.2-cp38-cp38-win32.whl", hash = "sha256:f6b5360e2278fae1e79479a4b56198fc7faf46ab350da18756c4de789835dbcd"},
+ {file = "pycares-4.2.2-cp38-cp38-win_amd64.whl", hash = "sha256:4304e5f0c10281abcee3c2547140a6b280c70866f2828956c9bcb2de6cffa211"},
+ {file = "pycares-4.2.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9155e95cbe26b4b57ca691e9d8bfb5a002c7ce14ac02ddfcfe7849d4d349badb"},
+ {file = "pycares-4.2.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:612a20514685a3d999dd0a99eede9da851be11171d599b211fac287eee452ff1"},
+ {file = "pycares-4.2.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:075d4bdde10590a2d0456eab20028aab997207e45469d30dd01a4a65caa7f8da"},
+ {file = "pycares-4.2.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f6eebdf34477c9bfb00497f8e58a674fd22b348bd928d19d29c84e8923554e1"},
+ {file = "pycares-4.2.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:55d39f2c38d1285d1ae248b9d2d965b161dcf51a4b6eacf97ff056da6f09dd30"},
+ {file = "pycares-4.2.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:64261640fd52910e7960f30888abeca4e6a7a91371d351ccebc70ac1625ca74e"},
+ {file = "pycares-4.2.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:72184b1510866c9bc97a6daca7d8218a6954c4a78640197f0840e604ba1182f9"},
+ {file = "pycares-4.2.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:02fdf5ce48b21da6eafc5cb4508d344a0d48ac1a31e8df178f7c2fb548fcbc14"},
+ {file = "pycares-4.2.2-cp39-cp39-win32.whl", hash = "sha256:fe8e0f8ed7fd795868bfc2211e345963174a9f4d1e2125753e1715a60441c8a0"},
+ {file = "pycares-4.2.2-cp39-cp39-win_amd64.whl", hash = "sha256:bb09c084de909206e6db1f014d4c6d662c7df04194df31f4831088d426afe8f1"},
+ {file = "pycares-4.2.2.tar.gz", hash = "sha256:e1f57a8004370080694bd6fb969a1ffc9171a59c6824d54f791c1b2e4d298385"},
+]
+pycodestyle = [
+ {file = "pycodestyle-2.9.1-py2.py3-none-any.whl", hash = "sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b"},
+ {file = "pycodestyle-2.9.1.tar.gz", hash = "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785"},
+]
+pycparser = [
+ {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"},
+ {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"},
+]
+pydocstyle = [
+ {file = "pydocstyle-6.1.1-py3-none-any.whl", hash = "sha256:6987826d6775056839940041beef5c08cc7e3d71d63149b48e36727f70144dc4"},
+ {file = "pydocstyle-6.1.1.tar.gz", hash = "sha256:1d41b7c459ba0ee6c345f2eb9ae827cab14a7533a88c5c6f7e94923f72df92dc"},
+]
+pyflakes = [
+ {file = "pyflakes-2.5.0-py2.py3-none-any.whl", hash = "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2"},
+ {file = "pyflakes-2.5.0.tar.gz", hash = "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"},
+]
+pyjokes = [
+ {file = "pyjokes-0.6.0-py2.py3-none-any.whl", hash = "sha256:70b6125186dee5845038505cd16b5e09250da46c730e36b44ffd870e3c81aaaa"},
+ {file = "pyjokes-0.6.0.tar.gz", hash = "sha256:08860eedb78cbfa4618243c8db088f21c39823ece1fdaf0133e52d9c56e981a5"},
+]
+pyparsing = [
+ {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"},
+ {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"},
+]
+pyreadline3 = [
+ {file = "pyreadline3-3.4.1-py3-none-any.whl", hash = "sha256:b0efb6516fd4fb07b45949053826a62fa4cb353db5be2bbb4a7aa1fdd1e345fb"},
+ {file = "pyreadline3-3.4.1.tar.gz", hash = "sha256:6f3d1f7b8a31ba32b73917cefc1f28cc660562f39aea8646d30bd6eff21f7bae"},
+]
+python-dateutil = [
+ {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
+ {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
+]
+python-dotenv = [
+ {file = "python-dotenv-0.21.0.tar.gz", hash = "sha256:b77d08274639e3d34145dfa6c7008e66df0f04b7be7a75fd0d5292c191d79045"},
+ {file = "python_dotenv-0.21.0-py3-none-any.whl", hash = "sha256:1684eb44636dd462b66c3ee016599815514527ad99965de77f43e0944634a7e5"},
+]
+PyYAML = [
+ {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"},
+ {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"},
+ {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"},
+ {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"},
+ {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"},
+ {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"},
+ {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"},
+ {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"},
+ {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"},
+ {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"},
+ {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"},
+ {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"},
+ {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"},
+ {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"},
+ {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"},
+ {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"},
+ {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"},
+ {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"},
+ {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"},
+ {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"},
+ {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"},
+ {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"},
+ {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"},
+ {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"},
+ {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"},
+ {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"},
+ {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"},
+ {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"},
+ {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"},
+ {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"},
+ {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"},
+ {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"},
+ {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"},
+ {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"},
+ {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"},
+ {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"},
+ {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"},
+ {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"},
+ {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"},
+ {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"},
+]
+rapidfuzz = [
+ {file = "rapidfuzz-2.12.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:129c93a76c4fed176b4eaaf78fecd290932971bca10315dee9feaf94a7b443b1"},
+ {file = "rapidfuzz-2.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c9c2b3b00033afdb745cc77b8c2ed858b08bb9a773c9a81a1160ece59a361545"},
+ {file = "rapidfuzz-2.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4f3f0ddfe3176e19c0a3cf6ad29e9ff216ff5fdec035b001ebabad91ef155107"},
+ {file = "rapidfuzz-2.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20f2f0f0746ffc165168ca160c5b1a1485076bdde5b656cf3dbe532ef2ac57ff"},
+ {file = "rapidfuzz-2.12.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27fa0e7d5e5291dc3e48c6512524f2f8e7ba3d397fa712a85a97639e3d6597e9"},
+ {file = "rapidfuzz-2.12.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4fc958b21416825c599e228278c69efb480169cd99d1a21787a54f53fbff026c"},
+ {file = "rapidfuzz-2.12.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:07c623741958dd49d8c2c51f7c2e62472f41b8d795cc9c734e441e30de3f8330"},
+ {file = "rapidfuzz-2.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33cfd01cb7f8a48c8e057198e3814a120323c0360017dd5c4eba07d097b43b39"},
+ {file = "rapidfuzz-2.12.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:1e0f6f878c20454a7e7ea2ed30970ae0334852c5e422e7014757821fa33c1588"},
+ {file = "rapidfuzz-2.12.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2e9709a163ec3b890f9a4173261e9ef586046feee74bbece62595bf103421178"},
+ {file = "rapidfuzz-2.12.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:35b34f33a9f0a86fdba39053b203d8d517da76f3553230a55867c51f0d802b67"},
+ {file = "rapidfuzz-2.12.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:7a67d93fd2e6e5a4e278eade2bbef16ba88d4efcb4eed106f075b0b21427a92f"},
+ {file = "rapidfuzz-2.12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:35737fd5766ca212d98e0598fb4d302f509e1cbf7b6dc42e2eddefd956150815"},
+ {file = "rapidfuzz-2.12.0-cp310-cp310-win32.whl", hash = "sha256:e333bb6a69c515a1fce149002aaf7d8902fddab54db14fe14c89c6da402410d2"},
+ {file = "rapidfuzz-2.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:4787d8e9f4b184d383ad000cdd48330ae75ec927c5832067a6b3617c5f6fb677"},
+ {file = "rapidfuzz-2.12.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2fda8c003d9ae4f3674c783887b31ecb76f4ab58670a8f01b93efd0917c1e503"},
+ {file = "rapidfuzz-2.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3e8707e98b645f80834e24103e7cd67f1b772999bb979da6d61ca1fcdc07672a"},
+ {file = "rapidfuzz-2.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2c2cd1e01e8aef2bd1b5152e66e0b865f31eb2d00a8d28cbbbb802f42e2dbe43"},
+ {file = "rapidfuzz-2.12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02a5c8b780af49a4e5f08033450d3f7c696f6c04e57c67ecbb19c9944ea3ce20"},
+ {file = "rapidfuzz-2.12.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eae4c6880dbabee9f363950510c09d7e12dea8dbc6ebcd2ff58e594a78d9370"},
+ {file = "rapidfuzz-2.12.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f74636ca4a3ce700f4fe2dbe10d224ee4fb52ecab12ea3007a2bc2fcd0d53888"},
+ {file = "rapidfuzz-2.12.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c62472a70c7f22f1ae9864c02554dbc234a1dfbac24388542bf87437a4169379"},
+ {file = "rapidfuzz-2.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e34c996cc245a21f376c3b8eede1296339845f039c8c270297a455d3a1ad71b"},
+ {file = "rapidfuzz-2.12.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3f7b798807ac9c5f632e8f359adf1393f81d9211e4961eedb5e2d4ce311e0078"},
+ {file = "rapidfuzz-2.12.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:917e3e2ffc0e078cce4a632f65d32a339f18cad22b5536a32c641bf1900e7f96"},
+ {file = "rapidfuzz-2.12.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:b2b81c6cb59b955b82a4853e3fbef7231da87c5522a69daaf9b01bd81d137ec3"},
+ {file = "rapidfuzz-2.12.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:5c6a9ada752149e23051852867596b35afc79015760e23676ac287bcad58e0b6"},
+ {file = "rapidfuzz-2.12.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:475a551c43ba23b4ca328c9bbcae39205729f4751280eb9763da08d97d328953"},
+ {file = "rapidfuzz-2.12.0-cp311-cp311-win32.whl", hash = "sha256:9f849d4889a0f1bc2260b981b1ae8393938e8a2c92666e1757e69f947c6ce868"},
+ {file = "rapidfuzz-2.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:241912c4f7f232c7518384f8cea719cf2ff290f80735355a217e9c690d274f62"},
+ {file = "rapidfuzz-2.12.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d6e6972c5bd1ee4f532029616dfe0f5133f7cc688ebc05dbbc03e19b4ec12199"},
+ {file = "rapidfuzz-2.12.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45def44f1140c6f5c7a5389645d02e8011d27a6e64f529f33cee687e7c25af07"},
+ {file = "rapidfuzz-2.12.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad5935f4a0ec3a2c3d19021fcd27addce4892ae00f71cc4180009bc4bed930ac"},
+ {file = "rapidfuzz-2.12.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7febf074f7de7ebc374100be0036fc592659af911b6efbc1135cdebfe939c57d"},
+ {file = "rapidfuzz-2.12.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:028aa9edfa044629a0a9e924a168a01f61c8f570c9ea919e2ed214826ba1cdfb"},
+ {file = "rapidfuzz-2.12.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac6ce417174a086a496aefc7caa614640dc33d418a922ee0a184b093d84f2f6c"},
+ {file = "rapidfuzz-2.12.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:9ceb8d6f1bd18a058cb8472c6e8cc84802413a65b029a7832589ba7b76c0eb11"},
+ {file = "rapidfuzz-2.12.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:13ad87a539b13794292fb661b8c4f4c19e6c066400d9db991e3a1441f55fc29b"},
+ {file = "rapidfuzz-2.12.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:9836bea98f25a67c296f57cf6de420c88f46e430ee85d25ae5f397968c7adcdf"},
+ {file = "rapidfuzz-2.12.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c74b960a1b93ac22e6cbf268ce509fb2c2338a29180c3d844df4a57bfff73273"},
+ {file = "rapidfuzz-2.12.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:22487992f4811c8aef449736f483514f0294d5593f5f9c95cbfb2474dbc363b9"},
+ {file = "rapidfuzz-2.12.0-cp37-cp37m-win32.whl", hash = "sha256:25db060ba8082c38f75da482ff15d3b60a4bc59f158b6d29a2c5bccadd2b71b0"},
+ {file = "rapidfuzz-2.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c1191a1c9f24134c6048770aabaa2f7def8d6d4c919da857d5e7dabdf63308f2"},
+ {file = "rapidfuzz-2.12.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b63402c5af2ad744c2c1ab2e7265eb317e75257fd27eb6f087fea76464b065db"},
+ {file = "rapidfuzz-2.12.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:96fe7da85d8721c3a5c362f6b1e7fd26ad74a76bebc369fb7ae62907cf069940"},
+ {file = "rapidfuzz-2.12.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ae0519d01a05c6204c2d27ae49b2231787d9a6efc801d5dbf131b20065fd21e3"},
+ {file = "rapidfuzz-2.12.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef812c73fff460678defaab3a95ec9b7551ef14d424eb6af7b75e376050119d2"},
+ {file = "rapidfuzz-2.12.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ac95a2ca4add04f349f8f5c05269d8b194a72ebdfc4f86a725c15d79a420d429"},
+ {file = "rapidfuzz-2.12.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:651664023726f28f7447e40fa2b8a015514f9db4b58654e9bf7d3729e2606eab"},
+ {file = "rapidfuzz-2.12.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2676f7ccd22a67638baff054a8e13924f20d87efb3a873f6ea248a395a80e2c8"},
+ {file = "rapidfuzz-2.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f2db0c684d9999c81084aa370e2e6b266b694e76c7e356bbeb3b282ca524475"},
+ {file = "rapidfuzz-2.12.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:589464c49a332c644b750f2ebc3737d444427669323ace623bd4948e414a641a"},
+ {file = "rapidfuzz-2.12.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c43579c7a64f21c9b4d4c3106ace46a8ebfb8e704372e6c8cc45807d1b86462f"},
+ {file = "rapidfuzz-2.12.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ad279e4892652583671a7ece977dd9b1eb17ae9752fbc9013c950095b044a315"},
+ {file = "rapidfuzz-2.12.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:22e8b127abcf0b10ebf8a9b3351c3c980e5c27cb60a865632d90d6a698060a9a"},
+ {file = "rapidfuzz-2.12.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c6c4064b2324b86f7a035379928fe1f3aca4ca5ba75ebedc9ea0d821b0e05606"},
+ {file = "rapidfuzz-2.12.0-cp38-cp38-win32.whl", hash = "sha256:d0fc1e32353afef426488d2e19cd295f1f504323215275ec0871bdae2b052a70"},
+ {file = "rapidfuzz-2.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:3abe9c25f9ba260a6828d24002a15112c5f21c6877c5f8c294ffe4b9d197c6d2"},
+ {file = "rapidfuzz-2.12.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2207927f42ae7b7fbcc1a4ff86f202647776200f3d8723603e7acf96af924e9f"},
+ {file = "rapidfuzz-2.12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5e2c0a5a0346ce95a965ed6fa941edcf129cac22bf63314b684a3fe64078c95b"},
+ {file = "rapidfuzz-2.12.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d5b65d9f2860210087739adadc075bd9215b363d00c3c8e68369560683a4c3df"},
+ {file = "rapidfuzz-2.12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0006c6450d02efdfef8d3f81e6a87790572486046676fe29f4c5da8708ea11b"},
+ {file = "rapidfuzz-2.12.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5fa88543c5744d725fc989afd79926c226e1c5f5c00904834851997f367da2b5"},
+ {file = "rapidfuzz-2.12.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:238fddfb90fab858ced88d064608bff9aed83cec11a7630a4e95b7e49734d8b1"},
+ {file = "rapidfuzz-2.12.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f030223aa618a48d2f8339fd674c4c03db88649313e2c65107e9c04e09edc7f2"},
+ {file = "rapidfuzz-2.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f96973d42caf0e4566882b6e7acbba753199d7acb4db486f14ab553c7b395cd5"},
+ {file = "rapidfuzz-2.12.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9e239e404dbb9fec308409e174710b5e53ff8bd9647e8875e2ca245b1f762f89"},
+ {file = "rapidfuzz-2.12.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c9fdbe8b1b32a731ee48a21a161358e55067c9cabd36ba0b8d844e5106056920"},
+ {file = "rapidfuzz-2.12.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:800b1498989bfb64118b219eeb42957b3d93ec7d6955dfc742a3cbf3be738f2f"},
+ {file = "rapidfuzz-2.12.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:16426b441d28efb3b1fe10f2b81aa469020655cef068a32de6ec24433590ee5b"},
+ {file = "rapidfuzz-2.12.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b75fe7abf55e7da6d32174b5ac207a465d1bc69d777049c277776472c0b7d82c"},
+ {file = "rapidfuzz-2.12.0-cp39-cp39-win32.whl", hash = "sha256:1a600b037a56a61111c01809b5e4c4b5aac12edf2769c094fefab02d496a95a4"},
+ {file = "rapidfuzz-2.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:9c8295dd49582dfb6a29e5f9dfa1691a0edd2e0512377ceb2c8dd11e7fabd38a"},
+ {file = "rapidfuzz-2.12.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:22646f54d44d98d6f462fb3f1ac997ea53aaebdd1344039e8f75090f43e47a89"},
+ {file = "rapidfuzz-2.12.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9a90ab26b12218d10d5f148e84e8facd62f562bc25d32e2c3cf3c743f7e0e67"},
+ {file = "rapidfuzz-2.12.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:74f821370ac01f677b5a26e0606084f2eb671f7bb4f3e2e82d94a100b1c28457"},
+ {file = "rapidfuzz-2.12.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c7f3c61e2d1530cf7e1647bdbb466f0f83fa30d2c579b6d75e444f88ff47913"},
+ {file = "rapidfuzz-2.12.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:0ae8c0c2f51f618d54579341c44ba198849d9cd845bb0dc85d1711fd8de9a159"},
+ {file = "rapidfuzz-2.12.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b1114da71974c86e64a98afff8d88cf3a3351b289d07f0218e67d56b506cb9e2"},
+ {file = "rapidfuzz-2.12.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6fa81c8d3c901d9f174482185f23b02052e71da015da3a613be98f28fd2672b"},
+ {file = "rapidfuzz-2.12.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5dcd7bd175d870338fc9ae43d0184ecd45958f5ca2ee7ea0a7953eedc4d9718e"},
+ {file = "rapidfuzz-2.12.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43398361d54fed476ccfdb52dc34d88c64461f0ec35f8abf10dd0413a3f19d8c"},
+ {file = "rapidfuzz-2.12.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:a8d5787f5c52c00991032b976b69f5c1e181a3bddce76fd43c91b2c4901c96ce"},
+ {file = "rapidfuzz-2.12.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:626eaa1b52a9dafa9bf377bcdcfdf1ea867dd51b5bb5dab1a05938c3303f317f"},
+ {file = "rapidfuzz-2.12.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6d78f967b7b162013fc85821a74cc7cd021fbf045f166629c9bd523799d8e51"},
+ {file = "rapidfuzz-2.12.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4581600ded8f37e8387d0eef93520fb33dafab6ccb37d005e20d05cd3fbdd9db"},
+ {file = "rapidfuzz-2.12.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8eadfb5394ab5b9c6e3d4bb00ef49e19f60a4e431190c103e647d4e4bff3332e"},
+ {file = "rapidfuzz-2.12.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:48539221026b0a84b6d2c2665c3dde784e3c0fac28975658c03fed352f8e1d7e"},
+ {file = "rapidfuzz-2.12.0.tar.gz", hash = "sha256:f371453d0c1109e93ef569741a27171e602ef1fbea5c27a8f190f403234fd36b"},
+]
+redis = [
+ {file = "redis-4.3.4-py3-none-any.whl", hash = "sha256:a52d5694c9eb4292770084fa8c863f79367ca19884b329ab574d5cb2036b3e54"},
+ {file = "redis-4.3.4.tar.gz", hash = "sha256:ddf27071df4adf3821c4f2ca59d67525c3a82e5f268bed97b813cb4fabf87880"},
+]
+sentry-sdk = [
+ {file = "sentry-sdk-1.10.1.tar.gz", hash = "sha256:105faf7bd7b7fa25653404619ee261527266b14103fe1389e0ce077bd23a9691"},
+ {file = "sentry_sdk-1.10.1-py2.py3-none-any.whl", hash = "sha256:06c0fa9ccfdc80d7e3b5d2021978d6eb9351fa49db9b5847cf4d1f2a473414ad"},
+]
+setuptools = [
+ {file = "setuptools-65.3.0-py3-none-any.whl", hash = "sha256:2e24e0bec025f035a2e72cdd1961119f557d78ad331bb00ff82efb2ab8da8e82"},
+ {file = "setuptools-65.3.0.tar.gz", hash = "sha256:7732871f4f7fa58fb6bdcaeadb0161b2bd046c85905dbaa066bdcbcc81953b57"},
+]
+six = [
+ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
+ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
+]
+snowballstemmer = [
+ {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"},
+ {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"},
+]
+sortedcontainers = [
+ {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"},
+ {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"},
+]
+soupsieve = [
+ {file = "soupsieve-2.3.2.post1-py3-none-any.whl", hash = "sha256:3b2503d3c7084a42b1ebd08116e5f81aadfaea95863628c80a3b774a11b7c759"},
+ {file = "soupsieve-2.3.2.post1.tar.gz", hash = "sha256:fc53893b3da2c33de295667a0e19f078c14bf86544af307354de5fcf12a3f30d"},
+]
+statsd = [
+ {file = "statsd-3.3.0-py2.py3-none-any.whl", hash = "sha256:c610fb80347fca0ef62666d241bce64184bd7cc1efe582f9690e045c25535eaa"},
+ {file = "statsd-3.3.0.tar.gz", hash = "sha256:e3e6db4c246f7c59003e51c9720a51a7f39a396541cb9b147ff4b14d15b5dd1f"},
+]
+taskipy = [
+ {file = "taskipy-1.10.3-py3-none-any.whl", hash = "sha256:4c0070ca53868d97989f7ab5c6f237525d52ee184f9b967576e8fe427ed9d0b8"},
+ {file = "taskipy-1.10.3.tar.gz", hash = "sha256:112beaf21e3d5569950b99162a1de003fa885fabee9e450757a6b874be914877"},
+]
+toml = [
+ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
+ {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
+]
+tomli = [
+ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
+ {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
+]
+typing-extensions = [
+ {file = "typing_extensions-4.3.0-py3-none-any.whl", hash = "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02"},
+ {file = "typing_extensions-4.3.0.tar.gz", hash = "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6"},
+]
+urllib3 = [
+ {file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"},
+ {file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"},
+]
+virtualenv = [
+ {file = "virtualenv-20.16.5-py3-none-any.whl", hash = "sha256:d07dfc5df5e4e0dbc92862350ad87a36ed505b978f6c39609dc489eadd5b0d27"},
+ {file = "virtualenv-20.16.5.tar.gz", hash = "sha256:227ea1b9994fdc5ea31977ba3383ef296d7472ea85be9d6732e42a91c04e80da"},
+]
+wrapt = [
+ {file = "wrapt-1.14.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3"},
+ {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef"},
+ {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28"},
+ {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ddaea91abf8b0d13443f6dac52e89051a5063c7d014710dcb4d4abb2ff811a59"},
+ {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:36f582d0c6bc99d5f39cd3ac2a9062e57f3cf606ade29a0a0d6b323462f4dd87"},
+ {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7ef58fb89674095bfc57c4069e95d7a31cfdc0939e2a579882ac7d55aadfd2a1"},
+ {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e2f83e18fe2f4c9e7db597e988f72712c0c3676d337d8b101f6758107c42425b"},
+ {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:ee2b1b1769f6707a8a445162ea16dddf74285c3964f605877a20e38545c3c462"},
+ {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:833b58d5d0b7e5b9832869f039203389ac7cbf01765639c7309fd50ef619e0b1"},
+ {file = "wrapt-1.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:80bb5c256f1415f747011dc3604b59bc1f91c6e7150bd7db03b19170ee06b320"},
+ {file = "wrapt-1.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07f7a7d0f388028b2df1d916e94bbb40624c59b48ecc6cbc232546706fac74c2"},
+ {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02b41b633c6261feff8ddd8d11c711df6842aba629fdd3da10249a53211a72c4"},
+ {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fe803deacd09a233e4762a1adcea5db5d31e6be577a43352936179d14d90069"},
+ {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:257fd78c513e0fb5cdbe058c27a0624c9884e735bbd131935fd49e9fe719d310"},
+ {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4fcc4649dc762cddacd193e6b55bc02edca674067f5f98166d7713b193932b7f"},
+ {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:11871514607b15cfeb87c547a49bca19fde402f32e2b1c24a632506c0a756656"},
+ {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c"},
+ {file = "wrapt-1.14.1-cp310-cp310-win32.whl", hash = "sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8"},
+ {file = "wrapt-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164"},
+ {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907"},
+ {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3"},
+ {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3"},
+ {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:a85d2b46be66a71bedde836d9e41859879cc54a2a04fad1191eb50c2066f6e9d"},
+ {file = "wrapt-1.14.1-cp35-cp35m-win32.whl", hash = "sha256:dbcda74c67263139358f4d188ae5faae95c30929281bc6866d00573783c422b7"},
+ {file = "wrapt-1.14.1-cp35-cp35m-win_amd64.whl", hash = "sha256:b21bb4c09ffabfa0e85e3a6b623e19b80e7acd709b9f91452b8297ace2a8ab00"},
+ {file = "wrapt-1.14.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9e0fd32e0148dd5dea6af5fee42beb949098564cc23211a88d799e434255a1f4"},
+ {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9736af4641846491aedb3c3f56b9bc5568d92b0692303b5a305301a95dfd38b1"},
+ {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b02d65b9ccf0ef6c34cba6cf5bf2aab1bb2f49c6090bafeecc9cd81ad4ea1c1"},
+ {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21ac0156c4b089b330b7666db40feee30a5d52634cc4560e1905d6529a3897ff"},
+ {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:9f3e6f9e05148ff90002b884fbc2a86bd303ae847e472f44ecc06c2cd2fcdb2d"},
+ {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:6e743de5e9c3d1b7185870f480587b75b1cb604832e380d64f9504a0535912d1"},
+ {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:d79d7d5dc8a32b7093e81e97dad755127ff77bcc899e845f41bf71747af0c569"},
+ {file = "wrapt-1.14.1-cp36-cp36m-win32.whl", hash = "sha256:81b19725065dcb43df02b37e03278c011a09e49757287dca60c5aecdd5a0b8ed"},
+ {file = "wrapt-1.14.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b014c23646a467558be7da3d6b9fa409b2c567d2110599b7cf9a0c5992b3b471"},
+ {file = "wrapt-1.14.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:88bd7b6bd70a5b6803c1abf6bca012f7ed963e58c68d76ee20b9d751c74a3248"},
+ {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5901a312f4d14c59918c221323068fad0540e34324925c8475263841dbdfe68"},
+ {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d77c85fedff92cf788face9bfa3ebaa364448ebb1d765302e9af11bf449ca36d"},
+ {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d649d616e5c6a678b26d15ece345354f7c2286acd6db868e65fcc5ff7c24a77"},
+ {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7d2872609603cb35ca513d7404a94d6d608fc13211563571117046c9d2bcc3d7"},
+ {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ee6acae74a2b91865910eef5e7de37dc6895ad96fa23603d1d27ea69df545015"},
+ {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2b39d38039a1fdad98c87279b48bc5dce2c0ca0d73483b12cb72aa9609278e8a"},
+ {file = "wrapt-1.14.1-cp37-cp37m-win32.whl", hash = "sha256:60db23fa423575eeb65ea430cee741acb7c26a1365d103f7b0f6ec412b893853"},
+ {file = "wrapt-1.14.1-cp37-cp37m-win_amd64.whl", hash = "sha256:709fe01086a55cf79d20f741f39325018f4df051ef39fe921b1ebe780a66184c"},
+ {file = "wrapt-1.14.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8c0ce1e99116d5ab21355d8ebe53d9460366704ea38ae4d9f6933188f327b456"},
+ {file = "wrapt-1.14.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e3fb1677c720409d5f671e39bac6c9e0e422584e5f518bfd50aa4cbbea02433f"},
+ {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:642c2e7a804fcf18c222e1060df25fc210b9c58db7c91416fb055897fc27e8cc"},
+ {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b7c050ae976e286906dd3f26009e117eb000fb2cf3533398c5ad9ccc86867b1"},
+ {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef3f72c9666bba2bab70d2a8b79f2c6d2c1a42a7f7e2b0ec83bb2f9e383950af"},
+ {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:01c205616a89d09827986bc4e859bcabd64f5a0662a7fe95e0d359424e0e071b"},
+ {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5a0f54ce2c092aaf439813735584b9537cad479575a09892b8352fea5e988dc0"},
+ {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2cf71233a0ed05ccdabe209c606fe0bac7379fdcf687f39b944420d2a09fdb57"},
+ {file = "wrapt-1.14.1-cp38-cp38-win32.whl", hash = "sha256:aa31fdcc33fef9eb2552cbcbfee7773d5a6792c137b359e82879c101e98584c5"},
+ {file = "wrapt-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:d1967f46ea8f2db647c786e78d8cc7e4313dbd1b0aca360592d8027b8508e24d"},
+ {file = "wrapt-1.14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3232822c7d98d23895ccc443bbdf57c7412c5a65996c30442ebe6ed3df335383"},
+ {file = "wrapt-1.14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:988635d122aaf2bdcef9e795435662bcd65b02f4f4c1ae37fbee7401c440b3a7"},
+ {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cca3c2cdadb362116235fdbd411735de4328c61425b0aa9f872fd76d02c4e86"},
+ {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d52a25136894c63de15a35bc0bdc5adb4b0e173b9c0d07a2be9d3ca64a332735"},
+ {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40e7bc81c9e2b2734ea4bc1aceb8a8f0ceaac7c5299bc5d69e37c44d9081d43b"},
+ {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b9b7a708dd92306328117d8c4b62e2194d00c365f18eff11a9b53c6f923b01e3"},
+ {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6a9a25751acb379b466ff6be78a315e2b439d4c94c1e99cb7266d40a537995d3"},
+ {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:34aa51c45f28ba7f12accd624225e2b1e5a3a45206aa191f6f9aac931d9d56fe"},
+ {file = "wrapt-1.14.1-cp39-cp39-win32.whl", hash = "sha256:dee0ce50c6a2dd9056c20db781e9c1cfd33e77d2d569f5d1d9321c641bb903d5"},
+ {file = "wrapt-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb"},
+ {file = "wrapt-1.14.1.tar.gz", hash = "sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d"},
+]
+yarl = [
+ {file = "yarl-1.8.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:abc06b97407868ef38f3d172762f4069323de52f2b70d133d096a48d72215d28"},
+ {file = "yarl-1.8.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:07b21e274de4c637f3e3b7104694e53260b5fc10d51fb3ec5fed1da8e0f754e3"},
+ {file = "yarl-1.8.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9de955d98e02fab288c7718662afb33aab64212ecb368c5dc866d9a57bf48880"},
+ {file = "yarl-1.8.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ec362167e2c9fd178f82f252b6d97669d7245695dc057ee182118042026da40"},
+ {file = "yarl-1.8.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:20df6ff4089bc86e4a66e3b1380460f864df3dd9dccaf88d6b3385d24405893b"},
+ {file = "yarl-1.8.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5999c4662631cb798496535afbd837a102859568adc67d75d2045e31ec3ac497"},
+ {file = "yarl-1.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed19b74e81b10b592084a5ad1e70f845f0aacb57577018d31de064e71ffa267a"},
+ {file = "yarl-1.8.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e4808f996ca39a6463f45182e2af2fae55e2560be586d447ce8016f389f626f"},
+ {file = "yarl-1.8.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2d800b9c2eaf0684c08be5f50e52bfa2aa920e7163c2ea43f4f431e829b4f0fd"},
+ {file = "yarl-1.8.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6628d750041550c5d9da50bb40b5cf28a2e63b9388bac10fedd4f19236ef4957"},
+ {file = "yarl-1.8.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:f5af52738e225fcc526ae64071b7e5342abe03f42e0e8918227b38c9aa711e28"},
+ {file = "yarl-1.8.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:76577f13333b4fe345c3704811ac7509b31499132ff0181f25ee26619de2c843"},
+ {file = "yarl-1.8.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0c03f456522d1ec815893d85fccb5def01ffaa74c1b16ff30f8aaa03eb21e453"},
+ {file = "yarl-1.8.1-cp310-cp310-win32.whl", hash = "sha256:ea30a42dc94d42f2ba4d0f7c0ffb4f4f9baa1b23045910c0c32df9c9902cb272"},
+ {file = "yarl-1.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:9130ddf1ae9978abe63808b6b60a897e41fccb834408cde79522feb37fb72fb0"},
+ {file = "yarl-1.8.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0ab5a138211c1c366404d912824bdcf5545ccba5b3ff52c42c4af4cbdc2c5035"},
+ {file = "yarl-1.8.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0fb2cb4204ddb456a8e32381f9a90000429489a25f64e817e6ff94879d432fc"},
+ {file = "yarl-1.8.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:85cba594433915d5c9a0d14b24cfba0339f57a2fff203a5d4fd070e593307d0b"},
+ {file = "yarl-1.8.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ca7e596c55bd675432b11320b4eacc62310c2145d6801a1f8e9ad160685a231"},
+ {file = "yarl-1.8.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0f77539733e0ec2475ddcd4e26777d08996f8cd55d2aef82ec4d3896687abda"},
+ {file = "yarl-1.8.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29e256649f42771829974e742061c3501cc50cf16e63f91ed8d1bf98242e5507"},
+ {file = "yarl-1.8.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7fce6cbc6c170ede0221cc8c91b285f7f3c8b9fe28283b51885ff621bbe0f8ee"},
+ {file = "yarl-1.8.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:59ddd85a1214862ce7c7c66457f05543b6a275b70a65de366030d56159a979f0"},
+ {file = "yarl-1.8.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:12768232751689c1a89b0376a96a32bc7633c08da45ad985d0c49ede691f5c0d"},
+ {file = "yarl-1.8.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:b19255dde4b4f4c32e012038f2c169bb72e7f081552bea4641cab4d88bc409dd"},
+ {file = "yarl-1.8.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6c8148e0b52bf9535c40c48faebb00cb294ee577ca069d21bd5c48d302a83780"},
+ {file = "yarl-1.8.1-cp37-cp37m-win32.whl", hash = "sha256:de839c3a1826a909fdbfe05f6fe2167c4ab033f1133757b5936efe2f84904c07"},
+ {file = "yarl-1.8.1-cp37-cp37m-win_amd64.whl", hash = "sha256:dd032e8422a52e5a4860e062eb84ac94ea08861d334a4bcaf142a63ce8ad4802"},
+ {file = "yarl-1.8.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:19cd801d6f983918a3f3a39f3a45b553c015c5aac92ccd1fac619bd74beece4a"},
+ {file = "yarl-1.8.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6347f1a58e658b97b0a0d1ff7658a03cb79bdbda0331603bed24dd7054a6dea1"},
+ {file = "yarl-1.8.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c0da7e44d0c9108d8b98469338705e07f4bb7dab96dbd8fa4e91b337db42548"},
+ {file = "yarl-1.8.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5587bba41399854703212b87071c6d8638fa6e61656385875f8c6dff92b2e461"},
+ {file = "yarl-1.8.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31a9a04ecccd6b03e2b0e12e82131f1488dea5555a13a4d32f064e22a6003cfe"},
+ {file = "yarl-1.8.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:205904cffd69ae972a1707a1bd3ea7cded594b1d773a0ce66714edf17833cdae"},
+ {file = "yarl-1.8.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea513a25976d21733bff523e0ca836ef1679630ef4ad22d46987d04b372d57fc"},
+ {file = "yarl-1.8.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0b51530877d3ad7a8d47b2fff0c8df3b8f3b8deddf057379ba50b13df2a5eae"},
+ {file = "yarl-1.8.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d2b8f245dad9e331540c350285910b20dd913dc86d4ee410c11d48523c4fd546"},
+ {file = "yarl-1.8.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ab2a60d57ca88e1d4ca34a10e9fb4ab2ac5ad315543351de3a612bbb0560bead"},
+ {file = "yarl-1.8.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:449c957ffc6bc2309e1fbe67ab7d2c1efca89d3f4912baeb8ead207bb3cc1cd4"},
+ {file = "yarl-1.8.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a165442348c211b5dea67c0206fc61366212d7082ba8118c8c5c1c853ea4d82e"},
+ {file = "yarl-1.8.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b3ded839a5c5608eec8b6f9ae9a62cb22cd037ea97c627f38ae0841a48f09eae"},
+ {file = "yarl-1.8.1-cp38-cp38-win32.whl", hash = "sha256:c1445a0c562ed561d06d8cbc5c8916c6008a31c60bc3655cdd2de1d3bf5174a0"},
+ {file = "yarl-1.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:56c11efb0a89700987d05597b08a1efcd78d74c52febe530126785e1b1a285f4"},
+ {file = "yarl-1.8.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e80ed5a9939ceb6fda42811542f31c8602be336b1fb977bccb012e83da7e4936"},
+ {file = "yarl-1.8.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6afb336e23a793cd3b6476c30f030a0d4c7539cd81649683b5e0c1b0ab0bf350"},
+ {file = "yarl-1.8.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4c322cbaa4ed78a8aac89b2174a6df398faf50e5fc12c4c191c40c59d5e28357"},
+ {file = "yarl-1.8.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fae37373155f5ef9b403ab48af5136ae9851151f7aacd9926251ab26b953118b"},
+ {file = "yarl-1.8.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5395da939ffa959974577eff2cbfc24b004a2fb6c346918f39966a5786874e54"},
+ {file = "yarl-1.8.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:076eede537ab978b605f41db79a56cad2e7efeea2aa6e0fa8f05a26c24a034fb"},
+ {file = "yarl-1.8.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d1a50e461615747dd93c099f297c1994d472b0f4d2db8a64e55b1edf704ec1c"},
+ {file = "yarl-1.8.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7de89c8456525650ffa2bb56a3eee6af891e98f498babd43ae307bd42dca98f6"},
+ {file = "yarl-1.8.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4a88510731cd8d4befaba5fbd734a7dd914de5ab8132a5b3dde0bbd6c9476c64"},
+ {file = "yarl-1.8.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2d93a049d29df172f48bcb09acf9226318e712ce67374f893b460b42cc1380ae"},
+ {file = "yarl-1.8.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:21ac44b763e0eec15746a3d440f5e09ad2ecc8b5f6dcd3ea8cb4773d6d4703e3"},
+ {file = "yarl-1.8.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:d0272228fabe78ce00a3365ffffd6f643f57a91043e119c289aaba202f4095b0"},
+ {file = "yarl-1.8.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:99449cd5366fe4608e7226c6cae80873296dfa0cde45d9b498fefa1de315a09e"},
+ {file = "yarl-1.8.1-cp39-cp39-win32.whl", hash = "sha256:8b0af1cf36b93cee99a31a545fe91d08223e64390c5ecc5e94c39511832a4bb6"},
+ {file = "yarl-1.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:de49d77e968de6626ba7ef4472323f9d2e5a56c1d85b7c0e2a190b2173d3b9be"},
+ {file = "yarl-1.8.1.tar.gz", hash = "sha256:af887845b8c2e060eb5605ff72b6f2dd2aab7a761379373fd89d314f4752abbf"},
+]
diff --git a/pyproject.toml b/pyproject.toml
index 729d67fa..0d2890c7 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -6,38 +6,40 @@ authors = ["Python Discord <[email protected]>"]
license = "MIT"
[tool.poetry.dependencies]
-python = "^3.9"
-"discord.py" = {url = "https://github.com/Rapptz/discord.py/archive/45d498c1b76deaf3b394d17ccf56112fa691d160.zip"}
-aiodns = "~=2.0"
-aioredis = "~1.3"
-rapidfuzz = "~=1.4"
-arrow = "~=1.1.0"
-beautifulsoup4 = "~=4.9"
-pillow = "~=9.0"
-sentry-sdk = "~=0.19"
-PyYAML = "~=5.4"
-async-rediscache = {extras = ["fakeredis"], version = "~=0.1.4"}
-emojis = "~=0.6.0"
-coloredlogs = "~=15.0"
-colorama = { version = "~=0.4.3", markers = "sys_platform == 'win32'" }
-lxml = "~=4.9"
-emoji = "^1.6.1"
+python = "3.10.*"
+
+# See https://bot-core.pythondiscord.com/ for docs.
+bot-core = {url = "https://github.com/python-discord/bot-core/archive/refs/tags/v8.2.1.zip", extras = ["async-rediscache"]}
+
+aiodns = "3.0.0"
+aioredis = "2.0.1"
+rapidfuzz = "2.12.0"
+arrow = "1.2.3"
+beautifulsoup4 = "4.11.1"
+pillow = "9.2.0"
+sentry-sdk = "1.10.1"
+PyYAML = "6.0"
+emojis = "0.6.0"
+coloredlogs = "15.0.1"
+colorama = { version = "0.4.6", markers = "sys_platform == 'win32'" }
+lxml = "4.9.1"
+emoji = "2.1.0"
pyjokes = "0.6.0"
[tool.poetry.dev-dependencies]
-flake8 = "~=3.8"
-flake8-annotations = "~=2.3"
-flake8-bugbear = "~=20.1"
-flake8-docstrings = "~=1.5"
-flake8-string-format = "~=0.3"
-flake8-tidy-imports = "~=4.1"
-flake8-todo = "~=0.7"
-flake8-isort = "~=4.0"
-pep8-naming = "~=0.11"
-pip-licenses = "~=3.5"
-pre-commit = "~=2.1"
-python-dotenv = "~=0.15"
-taskipy = "~=1.6"
+flake8 = "5.0.4"
+flake8-annotations = "2.9.1"
+flake8-bugbear = "22.10.27"
+flake8-docstrings = "1.6.0"
+flake8-string-format = "0.3.0"
+flake8-tidy-imports = "4.8.0"
+flake8-todo = "0.7"
+flake8-isort = "5.0.0"
+pep8-naming = "0.13.2"
+pip-licenses = "3.5.5"
+pre-commit = "2.20.0"
+python-dotenv = "0.21.0"
+taskipy = "1.10.3"
[tool.taskipy.tasks]
start = "python -m bot"
diff --git a/tox.ini b/tox.ini
index 61ff9616..7906e6d9 100644
--- a/tox.ini
+++ b/tox.ini
@@ -2,7 +2,7 @@
max-line-length=120
application_import_names=bot
docstring-convention=all
-ignore=
+extend-ignore=
P102,B311,W503,E226,S311,
# Missing Docstrings
D100,D104,D105,D107,