├── tests ├── __init__.py ├── .env.example └── test_pretty_help.py ├── images ├── example.gif ├── example-app.gif └── example-emoji.gif ├── pretty_help ├── __init__.py ├── abc_menu.py ├── app_menu.py ├── emoji_menu.py └── pretty_help.py ├── pyproject.toml ├── LICENSE ├── .gitignore ├── README.md └── poetry.lock /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/.env.example: -------------------------------------------------------------------------------- 1 | TOKEN= 2 | GUILD_ID= -------------------------------------------------------------------------------- /images/example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CasuallyCalm/discord-pretty-help/HEAD/images/example.gif -------------------------------------------------------------------------------- /images/example-app.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CasuallyCalm/discord-pretty-help/HEAD/images/example-app.gif -------------------------------------------------------------------------------- /images/example-emoji.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CasuallyCalm/discord-pretty-help/HEAD/images/example-emoji.gif -------------------------------------------------------------------------------- /pretty_help/__init__.py: -------------------------------------------------------------------------------- 1 | from .emoji_menu import * 2 | from .pretty_help import * 3 | from .app_menu import * 4 | 5 | __version__ = "2.0.7" 6 | -------------------------------------------------------------------------------- /pretty_help/abc_menu.py: -------------------------------------------------------------------------------- 1 | __all__ = ["PrettyMenu"] 2 | 3 | from abc import ABCMeta 4 | from typing import List 5 | 6 | import discord 7 | from discord.ext import commands 8 | 9 | 10 | class PrettyMenu(metaclass=ABCMeta): 11 | """ 12 | A base class for menus used with PrettyHelp 13 | """ 14 | 15 | async def send_pages( 16 | self, 17 | ctx: commands.Context, 18 | destination: discord.abc.Messageable, 19 | pages: List[discord.Embed], 20 | ): 21 | """The function called by :class:`PrettyHelp` that will send pages""" 22 | pass 23 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "discord-pretty-help" 3 | version = "2.0.7" 4 | description = "And nicer looking interactive help menu for discord.py" 5 | authors = ["CasuallyCalm <29642143+casuallycalm@users.noreply.github.com>"] 6 | readme = "README.md" 7 | license = "MIT" 8 | repository = "https://github.com/casuallycalm/discord-pretty-help" 9 | keywords=["discord", "discord.py", "discord bot"] 10 | packages = [ 11 | {include = "pretty_help"} 12 | ] 13 | 14 | [tool.poetry.dependencies] 15 | python = "^3.8" 16 | 17 | [tool.poetry.dev-dependencies] 18 | "discord.py" = "^2" 19 | black = "^22" 20 | python-dotenv = "*" 21 | 22 | [tool.poetry.scripts] 23 | test = "tests.test_pretty_help:run" 24 | emoji = "tests.test_pretty_help:run_emoji" 25 | 26 | [build-system] 27 | requires = ["poetry>=0.12"] 28 | build-backend = "poetry.masonry.api" 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 CasuallyCalm 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | .vscode/ 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | testbot.py 30 | 31 | # PyInstaller 32 | # Usually these files are written by a python script from a template 33 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 34 | *.manifest 35 | *.spec 36 | 37 | # Installer logs 38 | pip-log.txt 39 | pip-delete-this-directory.txt 40 | 41 | # Unit test / coverage reports 42 | htmlcov/ 43 | .tox/ 44 | .nox/ 45 | .coverage 46 | .coverage.* 47 | .cache 48 | nosetests.xml 49 | coverage.xml 50 | *.cover 51 | *.py,cover 52 | .hypothesis/ 53 | .pytest_cache/ 54 | 55 | # Translations 56 | *.mo 57 | *.pot 58 | 59 | # Django stuff: 60 | *.log 61 | local_settings.py 62 | db.sqlite3 63 | db.sqlite3-journal 64 | 65 | # Flask stuff: 66 | instance/ 67 | .webassets-cache 68 | 69 | # Scrapy stuff: 70 | .scrapy 71 | 72 | # Sphinx documentation 73 | docs/_build/ 74 | 75 | # PyBuilder 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | .python-version 87 | 88 | # pipenv 89 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 90 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 91 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 92 | # install all needed dependencies. 93 | #Pipfile.lock 94 | 95 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 96 | __pypackages__/ 97 | 98 | # Celery stuff 99 | celerybeat-schedule 100 | celerybeat.pid 101 | 102 | # SageMath parsed files 103 | *.sage.py 104 | 105 | # Environments 106 | .env 107 | .venv 108 | env/ 109 | venv/ 110 | ENV/ 111 | env.bak/ 112 | venv.bak/ 113 | 114 | # Spyder project settings 115 | .spyderproject 116 | .spyproject 117 | 118 | # Rope project settings 119 | .ropeproject 120 | 121 | # mkdocs documentation 122 | /site 123 | 124 | # mypy 125 | .mypy_cache/ 126 | .dmypy.json 127 | dmypy.json 128 | 129 | # Pyre type checker 130 | .pyre/ 131 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![version](https://img.shields.io/pypi/v/discord-pretty-help) ![python](https://img.shields.io/badge/python-3.8+-blue) 2 | 3 | # discord-pretty-help 4 | 5 | An embed version of the built-in help command for discord.py 6 | 7 | 8 | 9 | Inspired by the DefaultHelpCommand that discord.py uses, but revised for embeds and additional sorting on individual pages that can be "scrolled" through. 10 | 11 | ## Installation 12 | 13 | `pip install discord-pretty-help` 14 | 15 | ## Usage 16 | 17 | Example of how to use it: 18 | 19 | ```python 20 | from discord.ext import commands 21 | from pretty_help import PrettyHelp 22 | 23 | bot = commands.Bot(command_prefix="!", help_command=PrettyHelp()) 24 | ``` 25 | 26 | 27 | 28 | ### Added Optional Args 29 | 30 | - `color` - Set the default embed color 31 | - `delete_invoke` - Delete the message that invoked the help command. Requires message delete permission. Defaults is `False` 32 | - `ending_note` - Set the footer of the embed. Ending notes are fed a `commands.Context` (`ctx`) and a `PrettyHelp` (`help`) instance for more advanced customization. 33 | - `image_url` - The url of the image to be used on the embed 34 | - `index_title` - Set the index page name default is *"Categories"* 35 | - `menu` - The menu to use for navigating pages. Uses a `pretty_help.PrettyMenu()` instance. Default is `pretty_help.AppMenu()` 36 | - `no_category` - Set the name of the page with commands not part of a category. Default is "*No Category*" 37 | - `paginator`- The paginator to use. One is created by default. 38 | - `send_typing` - A bool that indicates if the bot will send a typing indicator. Defaults to ``True`` 39 | - `show_index` - Show the index page or not 40 | - `sort_commands` - Sort commands and categories alphabetically 41 | - `thumbnail_url` - The url of the thumbnail to be used on the embed 42 | 43 | ## Menus 44 | 45 | ### pretty_help.EmojiMenu 46 | - Uses Emojis to navigate 47 | - `active_time` - Set the time (in seconds) that the message will be active. Default is 30s 48 | - `delete_after_timeout` - Delete the message after `active_time` instead of removing reactions. Default `False` 49 | - `page_left` - The emoji to use to page left 50 | - `page_right` - The emoji to use to page right 51 | - `remove` - The emoji to use to remove the help message 52 | 53 | ![example](/images/example-emoji.gif) 54 | 55 | ### pretty_help.AppMenu 56 | - Uses Application Interactions (buttons) for navigating 57 | - `timeout` - The duration the interaction will be active for. Defaults to `None`. 58 | - `ephemeral` - Send as an ephemeral message. Defaults to `False`. 59 | 60 | ![example](/images/example-app.gif) 61 | 62 | By default, the help will just pick a random color on every invoke. You can change this using the `color` argument: 63 | 64 | ### Example of using a different menu and customization: 65 | 66 | ```python 67 | 68 | from discord.ext import commands 69 | from pretty_help import EmojiMenu, PrettyHelp 70 | 71 | # ":discord:743511195197374563" is a custom discord emoji format. Adjust to match your own custom emoji. 72 | menu = EmojiMenu(page_left="\U0001F44D", page_right="👎", remove=":discord:743511195197374563", active_time=5) 73 | 74 | # Custom ending note 75 | ending_note = "The ending note from {ctx.bot.user.name}\nFor command {help.clean_prefix}{help.invoked_with}" 76 | 77 | bot = commands.Bot(command_prefix="!") 78 | 79 | bot.help_command = PrettyHelp(menu=menu, ending_note=ending_note) 80 | ``` 81 | 82 | The basic `help` command will break commands up by cogs. Each cog will be a different page. Those pages can be navigated. 83 | 84 | ![example](/images/example.gif) 85 | 86 | 87 | # Changelog 88 | 89 | ## [2.0.0] 90 | - Subcommands in pages are indicated with a 🔗, previously it was unclear they were sub commands of the page title 91 | - Support Application commands 92 | - Support for GroupCogs 93 | - Navigation using discord interactions e.g. Buttons and select menus 94 | 95 | 96 | # Notes: 97 | - discord.py must already be installed to use this 98 | - `manage-messages` permission is recommended so reactions can be removed automatically 99 | 100 | ## Forks for other discord.py based libraries (could be out of date): 101 | * [nextcord-pretty-help](https://github.com/squigjess/nextcord-pretty-help) -------------------------------------------------------------------------------- /pretty_help/app_menu.py: -------------------------------------------------------------------------------- 1 | __all__ = ["AppMenu", "AppNav"] 2 | 3 | from typing import List, Optional 4 | 5 | import discord 6 | from discord.ext import commands 7 | from discord.ui import Select, View 8 | 9 | from .abc_menu import PrettyMenu 10 | 11 | 12 | class AppNav(View): 13 | """ 14 | The actual View for controlling the menu interaction 15 | 16 | Args: 17 | pages (List[discord.Embed], optional): List of pages the cycle through. Defaults to None. 18 | timeout (Optional[float], optional): The duration the interaction will be active for. Defaults to None. 19 | ephemeral (Optional[bool], optional): Send as an ephemeral message. Defaults to False. 20 | """ 21 | 22 | index = 0 23 | 24 | def __init__( 25 | self, 26 | pages: List[discord.Embed] = None, 27 | timeout: Optional[float] = None, 28 | ephemeral: Optional[bool] = False, 29 | allowed_user: Optional[discord.Member] = None, 30 | ): 31 | super().__init__(timeout=timeout) 32 | self.page_count = len(pages) if pages else None 33 | self.pages = pages 34 | self.allowed_user = allowed_user 35 | 36 | if pages and len(pages) == 1: 37 | self.remove_item(self.previous) 38 | self.remove_item(self.next) 39 | self.remove_item(self.select) 40 | 41 | if ephemeral: 42 | self.remove_item(self._delete) 43 | 44 | if pages and len(pages) > 1: 45 | for index, page in enumerate(pages): 46 | self.select.add_option( 47 | label=f"{page.title}", 48 | description=f"{page.description[:96]}...".replace("`", ""), 49 | value=index, 50 | ) 51 | 52 | @discord.ui.button( 53 | label="Previous", 54 | style=discord.ButtonStyle.success, 55 | row=1, 56 | custom_id="pretty_help:previous", 57 | ) 58 | async def previous(self, interaction: discord.Interaction, button: discord.Button): 59 | self.index -= 1 60 | await self.update(interaction) 61 | 62 | @discord.ui.button( 63 | label="Next", 64 | style=discord.ButtonStyle.primary, 65 | row=1, 66 | custom_id="pretty_help:next", 67 | ) 68 | async def next(self, interaction: discord.Interaction, button: discord.Button): 69 | self.index += 1 70 | await self.update(interaction) 71 | 72 | @discord.ui.button( 73 | label="Delete", 74 | style=discord.ButtonStyle.danger, 75 | row=1, 76 | custom_id="pretty_help:delete", 77 | ) 78 | async def _delete(self, interaction: discord.Interaction, button: discord.Button): 79 | await interaction.message.delete() 80 | 81 | @discord.ui.select(row=2, custom_id="pretty_help:select") 82 | async def select(self, interaction: discord.Interaction, select: Select): 83 | self.index = int(select.values[0]) 84 | await self.update(interaction) 85 | 86 | async def update(self, interaction: discord.Interaction): 87 | await interaction.response.edit_message( 88 | embed=self.pages[self.index % self.page_count], view=self 89 | ) 90 | 91 | async def interaction_check(self, interaction: discord.Interaction) -> bool: 92 | if ( 93 | not self.allowed_user 94 | and interaction.data.get("custom_id") == self._delete.custom_id 95 | ): 96 | return True 97 | return interaction.user == self.allowed_user 98 | 99 | 100 | class AppMenu(PrettyMenu): 101 | """ 102 | Navigate pages using the Discord UI components. 103 | 104 | This menu can be *partially* persistent with `client.add_view(AppMenu())` 105 | This will allow the delete button to work on past messages 106 | 107 | Args: 108 | timeout (Optional[float], optional): The duration the interaction will be active for. Defaults to None. 109 | ephemeral (Optional[bool], optional): Send as an ephemeral message. Defaults to False. 110 | """ 111 | 112 | def __init__( 113 | self, 114 | timeout: Optional[float] = None, 115 | ephemeral: Optional[bool] = False, 116 | ) -> None: 117 | # super().__init__() 118 | self.timeout = timeout 119 | self.ephemeral = ephemeral 120 | 121 | async def send_pages( 122 | self, 123 | ctx: commands.Context, 124 | destination: discord.abc.Messageable, 125 | pages: List[discord.Embed], 126 | ): 127 | if ctx.interaction: 128 | await ctx.interaction.response.send_message( 129 | embed=pages[0], 130 | view=AppNav( 131 | pages=pages, 132 | timeout=self.timeout, 133 | ephemeral=self.ephemeral, 134 | allowed_user=ctx.author, 135 | ), 136 | ephemeral=self.ephemeral, 137 | ) 138 | else: 139 | await destination.send( 140 | embed=pages[0], 141 | view=AppNav(pages=pages, timeout=self.timeout, allowed_user=ctx.author), 142 | ) 143 | -------------------------------------------------------------------------------- /pretty_help/emoji_menu.py: -------------------------------------------------------------------------------- 1 | import contextlib 2 | 3 | __all__ = ["EmojiMenu"] 4 | 5 | import asyncio 6 | import re 7 | from typing import List 8 | 9 | import discord 10 | from discord.ext import commands 11 | 12 | from .abc_menu import PrettyMenu 13 | 14 | 15 | class EmojiMenu(PrettyMenu): 16 | """The default navigation menu for PrettyHelp. 17 | 18 | Accepts standard emojis in multiple ways: 19 | - Emoji:: "👍" 20 | - Unicode:: "\\U0001F44D" 21 | - Unicode Name:: "\\N{THUMBS UP SIGN}" 22 | 23 | Using a custom emoji: 24 | - Discord emoji id:: ":custom_emoji:8675309" 25 | 26 | Use `\` to get the discord representation: 27 | Example: '\\\:custom_emoji:' in discord 28 | 29 | Args: 30 | active_time: :class: `int` 31 | The time in seconds the menu will be active for. Default is 10. 32 | delete_after_timeout: :class: `bool` 33 | Delete the message after `active_time` instead of removing reactions. 34 | page_left (str, optional): The emoji to use for going left. Defaults to "◀". 35 | page_right (str, optional): The emoji to use for going right. Defaults to "▶". 36 | remove (str, optional): The emoji to use for removing the help message. Defaults to "❌". 37 | """ 38 | 39 | def __init__( 40 | self, 41 | page_left="◀", 42 | page_right="▶", 43 | remove="❌", 44 | active_time=30, 45 | delete_after_timeout=False, 46 | ) -> None: 47 | self.delete_after_timeout = delete_after_timeout 48 | self.page_left = self.__match(page_left) 49 | self.page_right = self.__match(page_right) 50 | self.remove = self.__match(remove) 51 | self.active_time = active_time 52 | 53 | @property 54 | def _dict(self) -> dict: 55 | return { 56 | self.page_left: -1, 57 | self.page_right: 1, 58 | self.remove: 0, 59 | } 60 | 61 | @staticmethod 62 | def custom(emoji): 63 | return f":{emoji.name}:{emoji.id}" 64 | 65 | def get(self, emoji): 66 | if isinstance(emoji, str): 67 | return self._dict.get(emoji) 68 | else: 69 | return self._dict.get(self.custom(emoji)) 70 | 71 | def __contains__(self, emoji): 72 | if isinstance(emoji, str): 73 | return emoji in self._dict 74 | else: 75 | return self.custom(emoji) in self._dict 76 | 77 | @staticmethod 78 | def __match(emoji: str): 79 | try: 80 | pattern = r":[a-zA-Z0-9]+:[0-9]+" 81 | return re.search(pattern=pattern, string=emoji)[0] 82 | except TypeError: 83 | return emoji 84 | 85 | def __iter__(self): 86 | return self._dict.__iter__() 87 | 88 | def __repr__(self) -> str: 89 | return f"" 90 | 91 | async def send_pages( 92 | self, 93 | ctx: commands.Context, 94 | destination: discord.abc.Messageable, 95 | pages: List[discord.Embed], 96 | ): 97 | total = len(pages) 98 | 99 | # this is a quick way to make the emoji menu appear to work correctly when called as an app command 100 | # otherwise the interaction will error 101 | if ctx.interaction: 102 | await ctx.interaction.response.defer() 103 | await ctx.interaction.delete_original_response() 104 | 105 | message: discord.Message = await destination.send(embed=pages[0]) 106 | 107 | if total > 1: 108 | bot: commands.Bot = ctx.bot 109 | navigating = True 110 | index = 0 111 | 112 | for reaction in self: 113 | await message.add_reaction(reaction) 114 | 115 | while navigating: 116 | try: 117 | 118 | def check(payload: discord.RawReactionActionEvent): 119 | 120 | if ( 121 | payload.user_id != bot.user.id 122 | and message.id == payload.message_id 123 | ): 124 | return True 125 | 126 | payload: discord.RawReactionActionEvent = await bot.wait_for( 127 | "raw_reaction_add", timeout=self.active_time, check=check 128 | ) 129 | 130 | emoji_name = ( 131 | payload.emoji.name 132 | if payload.emoji.id is None 133 | else f":{payload.emoji.name}:{payload.emoji.id}" 134 | ) 135 | 136 | if emoji_name in self and payload.user_id == ctx.author.id: 137 | nav = self.get(emoji_name) 138 | if not nav: 139 | 140 | navigating = False 141 | return await message.delete() 142 | else: 143 | index += nav 144 | embed: discord.Embed = pages[index % total] 145 | 146 | await message.edit(embed=embed) 147 | 148 | with contextlib.suppress(discord.errors.Forbidden): 149 | await message.remove_reaction( 150 | payload.emoji, discord.Object(id=payload.user_id) 151 | ) 152 | 153 | except asyncio.TimeoutError: 154 | navigating = False 155 | if self.delete_after_timeout: 156 | await message.delete() 157 | else: 158 | for emoji in self: 159 | with contextlib.suppress(Exception): 160 | await message.remove_reaction(emoji, bot.user) 161 | -------------------------------------------------------------------------------- /tests/test_pretty_help.py: -------------------------------------------------------------------------------- 1 | """ 2 | Note: Rename `env.example` to `.env` and enter your token then run `poetry run test` in your terminal 3 | """ 4 | import os 5 | 6 | import discord 7 | import dotenv 8 | from discord import app_commands 9 | from discord.ext import commands 10 | from pretty_help import EmojiMenu, PrettyHelp, AppNav, AppMenu 11 | 12 | 13 | dotenv.load_dotenv("./tests/.env") 14 | 15 | # for testing standard text based commands, ie !ping, make sure the message content intent ON in the discord bot app page 16 | intents = discord.Intents.default() 17 | intents.message_content = True 18 | menu = None 19 | 20 | MY_GUILD = discord.Object(id=os.environ.get("GUILD_ID")) 21 | 22 | 23 | # Custom ending note 24 | ending_note = "The ending note from {ctx.bot.user.name}\nFor command {help.clean_prefix}{help.invoked_with}" 25 | 26 | menu = AppMenu(ephemeral=True) 27 | 28 | bot = commands.Bot( 29 | command_prefix="~", 30 | description="this is the bots description, ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor", 31 | intents=intents, 32 | help_command=PrettyHelp( 33 | ending_note=ending_note, 34 | menu=menu, 35 | # send_typing=False, 36 | # image_url="https://assets-global.website-files.com/6257adef93867e50d84d30e2/62f0a9e560a799075a4e0cea_Discord-Logo-White%20(3).png", # white discord icon 37 | # thumbnail_url="https://assets-global.website-files.com/6257adef93867e50d84d30e2/625e5fcef7ab80b8c1fe559e_Discord-Logo-Color.png", # blurple discord icon 38 | ), 39 | ) 40 | 41 | 42 | def use_emoji_menu(): 43 | # ":discord:743511195197374563" is a custom discord emoji format. Adjust to match your own custom emoji. 44 | menu = EmojiMenu( 45 | "\U0001F44D", 46 | "👎", 47 | ":discord:743511195197374563", 48 | active_time=60, 49 | delete_after_timeout=False, 50 | ) 51 | bot.help_command = PrettyHelp(menu=menu, ending_note=ending_note) 52 | 53 | 54 | ####### Text command Stuff 55 | class TextCommandCog(commands.Cog): 56 | """This is a cog for testing purposes""" 57 | 58 | @commands.command(description="This is acommand description") 59 | async def testcommand(self, ctx: commands.Context, arg: str, args: str = None): 60 | """This is command help""" 61 | await ctx.send("This is a test command") 62 | 63 | @commands.command(description="This is a command description") 64 | async def testcommand2(self, ctx: commands.Context): 65 | await ctx.send("This is a test command") 66 | 67 | @commands.command() 68 | async def testcommand3(self, ctx: commands.Context): 69 | """This is command help""" 70 | await ctx.send("This is a test command") 71 | 72 | 73 | class TextGroupCog(commands.Cog, name="Z Cog"): 74 | """This is a cog for testing purposes""" 75 | 76 | @commands.group(description="This is a group description") 77 | async def groupCommand1(self, ctx: commands.Context): 78 | """This is group help""" 79 | await ctx.send("This is a test command") 80 | 81 | @groupCommand1.command() 82 | async def subCommand1(self, ctx: commands.Context): 83 | await ctx.send("this is a subcommand") 84 | 85 | 86 | class LargeTextCommandCog(commands.Cog): 87 | @commands.command() 88 | async def command00(self, ctx: commands.Context): 89 | print("command 00") 90 | 91 | @commands.command() 92 | async def command01(self, ctx: commands.Context): 93 | print("command 01") 94 | 95 | @commands.command() 96 | async def command02(self, ctx: commands.Context): 97 | print("command 02") 98 | 99 | @commands.command() 100 | async def command03(self, ctx: commands.Context): 101 | print("command 03") 102 | 103 | @commands.command() 104 | async def command04(self, ctx: commands.Context): 105 | print("command 04") 106 | 107 | @commands.command() 108 | async def command05(self, ctx: commands.Context): 109 | print("command 05") 110 | 111 | @commands.command() 112 | async def command06(self, ctx: commands.Context): 113 | print("command 06") 114 | 115 | @commands.command() 116 | async def command07(self, ctx: commands.Context): 117 | print("command 07") 118 | 119 | @commands.command() 120 | async def command08(self, ctx: commands.Context): 121 | print("command 08") 122 | 123 | @commands.command() 124 | async def command09(self, ctx: commands.Context): 125 | print("command 09") 126 | 127 | @commands.command() 128 | async def command10(self, ctx: commands.Context): 129 | print("command 10") 130 | 131 | @commands.command() 132 | async def command11(self, ctx: commands.Context): 133 | print("command 11") 134 | 135 | @commands.command() 136 | async def command12(self, ctx: commands.Context): 137 | print("command 12") 138 | 139 | @commands.command() 140 | async def command13(self, ctx: commands.Context): 141 | print("command 13") 142 | 143 | @commands.command() 144 | async def command14(self, ctx: commands.Context): 145 | print("command 14") 146 | 147 | @commands.command() 148 | async def command15(self, ctx: commands.Context): 149 | print("command 15") 150 | 151 | @commands.command() 152 | async def command16(self, ctx: commands.Context): 153 | print("command 16") 154 | 155 | @commands.command() 156 | async def command17(self, ctx: commands.Context): 157 | print("command 17") 158 | 159 | @commands.command() 160 | async def command18(self, ctx: commands.Context): 161 | print("command 18") 162 | 163 | @commands.command() 164 | async def command19(self, ctx: commands.Context): 165 | print("command 19") 166 | 167 | @commands.command() 168 | async def command20(self, ctx: commands.Context): 169 | print("command 20") 170 | 171 | @commands.command() 172 | async def command21(self, ctx: commands.Context): 173 | print("command 21") 174 | 175 | @commands.command() 176 | async def command22(self, ctx: commands.Context): 177 | print("command 22") 178 | 179 | @commands.command() 180 | async def command23(self, ctx: commands.Context): 181 | print("command 23") 182 | 183 | @commands.command() 184 | async def command24(self, ctx: commands.Context): 185 | print("command 24") 186 | 187 | @commands.command() 188 | async def command25(self, ctx: commands.Context): 189 | print("command 25") 190 | 191 | @commands.command() 192 | async def command26(self, ctx: commands.Context): 193 | print("command 26") 194 | 195 | @commands.command() 196 | async def command27(self, ctx: commands.Context): 197 | print("command 27") 198 | 199 | @commands.command() 200 | async def command28(self, ctx: commands.Context): 201 | print("command 28") 202 | 203 | @commands.command() 204 | async def command29(self, ctx: commands.Context): 205 | print("command 29") 206 | 207 | 208 | ####### App Command stuff 209 | class AppCommandCog(commands.Cog): 210 | """And Cog with app commands and a message command. ornare massa eget egestas purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae auctor""" 211 | 212 | @commands.command() 213 | async def text_command(self, ctx: commands.Context): 214 | """normal message command with app commands""" 215 | await ctx.send("normal message command with app commands") 216 | 217 | @app_commands.command() 218 | async def _app_command( 219 | self, interaction: discord.Interaction, arg: str, args: str = None 220 | ): 221 | """This is an app command description in a cog""" 222 | await interaction.response.send_message("This is an app command in a cog") 223 | 224 | @app_commands.command(nsfw=True) 225 | async def nsfw_app_command(self, interaction: discord.Interaction): 226 | """This is an app command description and is NSFW""" 227 | await interaction.response.send_message("This is an app command, also NSFW") 228 | 229 | @app_commands.command() 230 | @app_commands.describe(message="The message the will be repeated") 231 | async def repeat(self, interaction: discord.Interaction, message: str): 232 | await interaction.response.send_message(message) 233 | 234 | 235 | class GroupAppCommandCog(commands.GroupCog): 236 | """A group of app commands in a cog""" 237 | 238 | @app_commands.command() 239 | async def _app_command( 240 | self, interaction: discord.Interaction, arg: str, args: str = None 241 | ): 242 | """This is an app command description in a group cog""" 243 | await interaction.response.send_message("This is an app command in a group") 244 | 245 | @app_commands.command(nsfw=True) 246 | async def nsfw_app_command(self, interaction: discord.Interaction): 247 | """This is an app command description and is NSFW""" 248 | await interaction.response.send_message("This is an app command, also NSFW") 249 | 250 | # @app_commands.describe(message="The message the will be repeated") 251 | @app_commands.command() 252 | async def repeat(self, interaction: discord.Interaction, message: str): 253 | await interaction.response.send_message(message) 254 | 255 | 256 | ######## Context Menus 257 | 258 | 259 | @bot.tree.command() 260 | async def sa_app_command(interaction: discord.Interaction): 261 | await interaction.response.send_message("Stand alone app command") 262 | 263 | 264 | @bot.hybrid_command(with_app_command=True) 265 | async def hybrid_command(ctx: commands.Context): 266 | await ctx.send("Hybrid command") 267 | 268 | 269 | @bot.tree.context_menu(nsfw=True) 270 | async def nsfw_reply(interaction: discord.Interaction, message: discord.Message): 271 | await message.reply(f"That's a nice message! - {interaction.user.mention}") 272 | 273 | 274 | @bot.tree.context_menu(name="reply") 275 | async def reply(interaction: discord.Interaction, message: discord.Message): 276 | await message.reply(f"That's a nice message! - {interaction.user.mention}") 277 | 278 | 279 | @bot.tree.context_menu(nsfw=True) 280 | async def nsfw_ban(interaction: discord.Interaction, member: discord.Member): 281 | await interaction.response.send_message( 282 | f"Ban {member.display_name}?", ephemeral=True 283 | ) 284 | 285 | 286 | @bot.tree.context_menu() 287 | async def ban(interaction: discord.Interaction, member: discord.Member): 288 | await interaction.response.send_message( 289 | f"Ban {member.display_name}?", ephemeral=True 290 | ) 291 | 292 | 293 | ######## 294 | 295 | 296 | @bot.command() 297 | async def test(ctx: commands.Context): 298 | await ctx.send("this is the test command") 299 | 300 | 301 | @commands.cooldown(1, 60) 302 | @bot.command() 303 | async def cooldown_command(ctx: commands.Context): 304 | cooldown: commands.Cooldown = ctx.command._buckets._cooldown 305 | print(cooldown.per, cooldown.rate) 306 | await ctx.send("This command has a cooldown") 307 | 308 | 309 | async def setup(): 310 | await bot.add_cog(TextCommandCog()) 311 | await bot.add_cog(TextGroupCog()) 312 | await bot.add_cog(LargeTextCommandCog()) 313 | await bot.add_cog(AppCommandCog()) 314 | await bot.add_cog(GroupAppCommandCog()) 315 | bot.add_view(AppNav()) 316 | bot.tree.copy_global_to(guild=MY_GUILD) 317 | await bot.tree.sync(guild=MY_GUILD) 318 | print(f"Logged in as: {bot.user.name}") 319 | print(f"With ID: {bot.user.id}") 320 | 321 | 322 | bot.setup_hook = setup 323 | 324 | 325 | def run(): 326 | bot.run(os.environ.get("TOKEN")) 327 | 328 | 329 | def run_emoji(): 330 | use_emoji_menu() 331 | run() 332 | 333 | 334 | if __name__ == "__main__": 335 | run() 336 | -------------------------------------------------------------------------------- /pretty_help/pretty_help.py: -------------------------------------------------------------------------------- 1 | __all__ = ["PrettyHelp", "Paginator"] 2 | 3 | from random import randint 4 | from typing import List, Optional, Union 5 | 6 | import discord 7 | from discord import app_commands 8 | from discord.ext import commands 9 | from discord.ext.commands.help import HelpCommand 10 | 11 | from .abc_menu import PrettyMenu 12 | from .app_menu import AppMenu 13 | 14 | 15 | class Paginator: 16 | """A class that creates pages for Discord messages. 17 | 18 | Attributes 19 | ----------- 20 | prefix: Optional[:class:`str`] 21 | The prefix inserted to every page. e.g. three backticks. 22 | suffix: Optional[:class:`str`] 23 | The suffix appended at the end of every page. e.g. three backticks. 24 | max_size: :class:`int` 25 | The maximum amount of codepoints allowed in a page. 26 | color: Optional[:class:`discord.Color`, :class: `int`] 27 | The color of the discord embed. Default is a random color for every invoke 28 | ending_note: Optional[:class:`str`] 29 | The footer in of the help embed 30 | image_url: Optional[:class:`str`] 31 | The url of the image to be used on the embed 32 | thumbnail_url: Optional[:class:`str`] 33 | The url of the thumbnail to be used on the embed 34 | """ 35 | 36 | ending_note: str 37 | 38 | def __init__( 39 | self, 40 | show_index: bool, 41 | color: discord.Color = 0, 42 | image_url: str = None, 43 | thumbnail_url: str = None, 44 | ): 45 | self.char_limit = 6000 46 | self.color = color 47 | self.ending_note = "" 48 | self.field_limit = 25 49 | self.image_url = image_url 50 | self.prefix = "```" 51 | self.show_index = show_index 52 | self.suffix = "```" 53 | self.thumbnail_url = thumbnail_url 54 | self.clear() 55 | 56 | def clear(self): 57 | """Clears the paginator to have no pages.""" 58 | self._pages = [] 59 | 60 | def _check_embed(self, embed: discord.Embed, *chars: str): 61 | """ 62 | Check if the embed is too big to be sent on discord 63 | 64 | Args: 65 | embed (discord.Embed): The embed to check 66 | 67 | Returns: 68 | bool: Will return True if the embed isn't too large 69 | """ 70 | return ( 71 | len(embed) + sum(len(char) for char in chars if char) < self.char_limit 72 | and len(embed.fields) < self.field_limit 73 | ) 74 | 75 | def _new_page(self, title: str, description: str): 76 | """ 77 | Create a new page 78 | 79 | Args: 80 | title (str): The title of the new page 81 | 82 | Returns: 83 | discord.Embed: Returns an embed with the title and color set 84 | """ 85 | embed = discord.Embed(title=title, description=description, color=self.color) 86 | embed.set_image(url=self.image_url) 87 | embed.set_thumbnail(url=self.thumbnail_url) 88 | return embed 89 | 90 | def _add_page(self, page: discord.Embed): 91 | """ 92 | Add a page to the paginator 93 | 94 | Args: 95 | page (discord.Embed): The page to add 96 | """ 97 | page.set_footer(text=self.ending_note) 98 | self._pages.append(page) 99 | 100 | def add_cog( 101 | self, title: Union[str, commands.Cog], commands_list: List[commands.Command] 102 | ): 103 | """ 104 | Add a cog page to the help menu 105 | 106 | Args: 107 | title (Union[str, commands.Cog]): The title of the embed 108 | commands_list (List[commands.Command]): List of commands 109 | """ 110 | cog = isinstance(title, commands.Cog) 111 | if not commands_list: 112 | return 113 | 114 | page_title = title.qualified_name if cog else title 115 | embed = self._new_page(page_title, (title.description or "") if cog else "") 116 | 117 | self._add_command_fields(embed, page_title, commands_list) 118 | 119 | def _add_command_fields( 120 | self, 121 | embed: discord.Embed, 122 | page_title: str, 123 | command_list: List[Union[commands.Command, app_commands.commands.Command]], 124 | group: bool = False, 125 | ): 126 | """ 127 | Adds command fields to Category/Cog and Command Group pages 128 | 129 | Args: 130 | embed (discord.Embed): The page to add command descriptions 131 | page_title (str): The title of the page 132 | commands_list(List[Union[commands.Command, app_commands.commands.Command]]): The list of commands for the fields 133 | """ 134 | 135 | for command in command_list: 136 | command_name = command.name 137 | if group or isinstance(command, commands.Group): 138 | command_name = "🔗 " + command_name 139 | if isinstance(command, commands.Command): 140 | short_doc = command.short_doc 141 | else: 142 | short_doc = command.description.split("\n", 1)[0] 143 | if not self._check_embed( 144 | embed, 145 | self.ending_note, 146 | command_name, 147 | short_doc, 148 | self.prefix, 149 | self.suffix, 150 | ): 151 | self._add_page(embed) 152 | embed = self._new_page(page_title, embed.description) 153 | 154 | embed.add_field( 155 | name=command_name, 156 | value=f'{self.prefix}{short_doc or "No Description"}{self.suffix}', 157 | inline=False, 158 | ) 159 | 160 | self._add_page(embed) 161 | 162 | @staticmethod 163 | def __command_info(command: Union[commands.Command, commands.Group]): 164 | info = "" 165 | if command.description: 166 | info += command.description + "\n\n" 167 | if command.help: 168 | info += command.help 169 | if not info: 170 | info = "None" 171 | return info 172 | 173 | def add_app_command(self, command: app_commands.commands.Command, signature: str): 174 | """ 175 | Add an application command to the help page 176 | 177 | Args: 178 | command (app_commands.commands.Command): The application command to add 179 | """ 180 | page = self._new_page( 181 | command.name, f"{self.prefix}{command.description}{self.suffix}" 182 | ) 183 | page.add_field( 184 | name="Usage", 185 | value=f"{self.prefix}{signature}{self.suffix}", 186 | inline=False, 187 | ) 188 | 189 | for parameter in sorted( 190 | command.parameters, key=lambda x: (not x.required, x.name) 191 | ): 192 | if parameter.description: 193 | description = ( 194 | "" if parameter.description == "…" else parameter.description 195 | ) 196 | page.add_field( 197 | name=parameter.name, 198 | value=f"```Required: {parameter.required}\n{description}```", 199 | inline=False, 200 | ) 201 | 202 | self._add_page(page) 203 | 204 | def add_app_group(self, group: app_commands.commands.Group, signature: str): 205 | """ 206 | Add an application command to the help page 207 | 208 | Args: 209 | command (app_commands.commands.Group): The application group command to add 210 | """ 211 | page = self._new_page( 212 | group.qualified_name, f"{self.prefix}{group.description}{self.suffix}" 213 | ) 214 | self._add_command_fields(page, group.name, group.walk_commands(), group=True) 215 | 216 | def add_command(self, command: commands.Command, signature: str): 217 | """ 218 | Add a command help page 219 | 220 | Args: 221 | command (commands.Command): The command to get help for 222 | signature (str): The command signature/usage string 223 | """ 224 | page = self._new_page( 225 | command.qualified_name, 226 | f"{self.prefix}{self.__command_info(command)}{self.suffix}" or "", 227 | ) 228 | if command.aliases: 229 | aliases = ", ".join(command.aliases) 230 | page.add_field( 231 | name="Aliases", 232 | value=f"{self.prefix}{aliases}{self.suffix}", 233 | inline=False, 234 | ) 235 | if cooldown := command._buckets._cooldown: 236 | page.add_field( 237 | name="Cooldown", 238 | value=f"`{cooldown.rate} time(s) every {cooldown.per} second(s)`", 239 | ) 240 | 241 | page.add_field( 242 | name="Usage", value=f"{self.prefix}{signature}{self.suffix}", inline=False 243 | ) 244 | self._add_page(page) 245 | 246 | def add_group(self, group: commands.Group, commands_list: List[commands.Command]): 247 | """ 248 | Add a group help page 249 | 250 | Args: 251 | group (commands.Group): The command group to get help for 252 | commands_list (List[commands.Command]): The list of commands in the group 253 | """ 254 | page = self._new_page( 255 | group.name, f"{self.prefix}{self.__command_info(group)}{self.suffix}" or "" 256 | ) 257 | 258 | self._add_command_fields(page, group.name, commands_list, group=True) 259 | 260 | def add_index(self, title: str, bot: commands.Bot): 261 | """ 262 | Add an index page to the response of the bot_help command 263 | 264 | Args: 265 | title (str): The title of the index page 266 | bot (commands.Bot): The bot instance 267 | """ 268 | if self.show_index: 269 | index = self._new_page(title, bot.description or "") 270 | 271 | for page_no, page in enumerate(self._pages, 1): 272 | index.add_field( 273 | name=f"{page_no}) {page.title}", 274 | value=f'{self.prefix}{page.description or "No Description"}{self.suffix}', 275 | inline=False, 276 | ) 277 | index.set_footer(text=self.ending_note) 278 | self._pages.insert(0, index) 279 | else: 280 | self._pages[0].description = bot.description 281 | 282 | @property 283 | def pages(self): 284 | """Returns the rendered list of pages.""" 285 | if len(self._pages) == 1: 286 | return self._pages 287 | lst = [] 288 | start = 0 if self.show_index else 1 289 | pages = len(self._pages) - 1 if self.show_index else len(self._pages) 290 | for page_no, page in enumerate(self._pages, start): 291 | page: discord.Embed 292 | if not self.show_index or page_no != 0: 293 | page.description = f"`Page: {page_no}/{pages}`\n{page.description}" 294 | lst.append(page) 295 | return lst 296 | 297 | 298 | class PrettyHelp(HelpCommand, commands.Cog): 299 | """The implementation of the prettier help command. 300 | A more refined help command format 301 | This inherits from :class:`HelpCommand`. 302 | It extends it with the following attributes. 303 | 304 | Attributes 305 | ------------ 306 | 307 | case_insensitive: :class: `bool` 308 | Ignore case when searching for commands ie 'HELP' --> 'help' Defaults to ``False``. 309 | color: :class: `discord.Color` 310 | The color to use for the help embeds. Default is a random color. 311 | delete_invoke: Optional[:class:`bool`] 312 | Delete the message that invoked the help command. Requires message delete permission. 313 | Defaults to ``False``. 314 | dm_help: Optional[:class:`bool`] 315 | A tribool that indicates if the help command should DM the user instead of 316 | sending it to the channel it received it from. If the boolean is set to 317 | ``True``, then all help output is DM'd. If ``False``, none of the help 318 | output is DM'd. If ``None``, then the bot will only DM when the help 319 | message becomes too long (dictated by more than :attr:`dm_help_threshold` characters). 320 | Defaults to ``False``. 321 | ending_note: Optional[:class:`str`] 322 | The footer in of the help embed 323 | image_url: Optional[:class:`str`] 324 | The url of the image to be used on the embed 325 | index_title: :class: `str` 326 | The string used when the index page is shown. Defaults to ``"Categories"`` 327 | menu: Optional[:class:`pretty_help.PrettyMenu`] 328 | The menu to use for navigating pages. Default is :class:`pretty_help.DefaultMenu` 329 | Custom menus should inherit from :class:`pretty_help.PrettyMenu` 330 | no_category: :class:`str` 331 | The string used when there is a command which does not belong to any category(cog). 332 | Useful for i18n. Defaults to ``"No Category"`` 333 | paginator: :class: `pretty_help.Paginator` 334 | The paginator to use. One is created by default. 335 | send_typing: :class: `bool` 336 | A bool that indicates if the bot will send a typing indicator. Defaults to ``True`` 337 | show_index: class: `bool` 338 | A bool that indicates if the index page should be shown listing the available cogs 339 | Defaults to ``True``. 340 | sort_commands: :class:`bool` 341 | Whether to sort the commands in the output alphabetically. Defaults to ``True``. 342 | thumbnail_url: Optional[:class:`str`] 343 | The url of the thumbnail to be used on the embed 344 | """ 345 | 346 | def __init__( 347 | self, 348 | case_insensitive: Optional[bool] = False, 349 | color: Optional[discord.Color] = discord.Color.from_rgb( 350 | randint(0, 255), randint(0, 255), randint(0, 255) 351 | ), 352 | delete_invoke: Optional[bool] = False, 353 | dm_help: Optional[bool] = False, 354 | ending_note: Optional[str] = "", 355 | image_url: Optional[str] = None, 356 | index_title: Optional[str] = "Categories", 357 | menu: Optional[PrettyMenu] = AppMenu(), 358 | no_category: Optional[str] = "No Category", 359 | paginator: Optional[Paginator] = None, 360 | send_typing: Optional[bool] = True, 361 | show_index: Optional[bool] = True, 362 | sort_commands: Optional[bool] = True, 363 | thumbnail_url: Optional[str] = None, 364 | **options, 365 | ): 366 | self.dm_help = dm_help 367 | self.index_title = index_title 368 | self.no_category = no_category 369 | self.sort_commands = sort_commands 370 | self.menu = menu 371 | self.paginator = paginator or Paginator( 372 | show_index=show_index, 373 | color=color, 374 | image_url=image_url, 375 | thumbnail_url=thumbnail_url, 376 | ) 377 | self.case_insensitive = case_insensitive 378 | self.ending_note = ending_note 379 | self.delete_invoke = delete_invoke 380 | self.send_typing = send_typing 381 | 382 | super().__init__(**options) 383 | 384 | def _add_to_bot(self, bot: commands.Bot) -> None: 385 | super()._add_to_bot(bot) 386 | self.bot = bot 387 | bot.tree.add_command(self._app_command_callback) 388 | 389 | def _remove_from_bot(self, bot) -> None: 390 | super()._remove_from_bot(bot) 391 | bot.tree.remove_command(self._app_command_callback.name) 392 | 393 | # Hacky, but it works I guess. 394 | # Might figure out a better solution later 🤷‍♂️ 395 | @app_commands.describe( 396 | command="The command or chain of commands/subcommands to get help for" 397 | ) 398 | @app_commands.command(name="help") 399 | async def _app_command_callback( 400 | self, interaction: discord.Interaction, command: str = None 401 | ): 402 | """Application help command""" 403 | bot = interaction.client 404 | ctx = await commands.Context.from_interaction(interaction) 405 | ctx.bot = bot 406 | await ctx.invoke(bot.get_command("help"), command=command) 407 | 408 | @_app_command_callback.autocomplete("command") 409 | async def __help_autocomplete( 410 | self, interaction: discord.Interaction, current: str 411 | ) -> List[app_commands.Choice[str]]: 412 | cmds = [cmd.qualified_name for cmd in self.bot.walk_commands()] 413 | cmds += [ 414 | app_cmd.name 415 | for app_cmd in self.bot.tree.get_commands( 416 | type=discord.AppCommandType.chat_input, 417 | guild=interaction.guild, 418 | ) 419 | ] 420 | 421 | cmds = sorted(cmds, key=lambda x: x.lower()) # Sort the commands alphabetically 422 | 423 | return [ 424 | app_commands.Choice(name=cmd, value=cmd) 425 | for cmd in cmds 426 | if current.lower() in cmd.lower() 427 | ][:24] 428 | 429 | async def filter_app_commands( 430 | self, app_commands: List[app_commands.AppCommand], sort: bool = True 431 | ): 432 | """Filter Application Commands and optionally sort them""" 433 | if sort: 434 | app_commands.sort(key=lambda x: x.name) 435 | return app_commands 436 | 437 | async def prepare_help_command( 438 | self, ctx: commands.Context, command: commands.Command 439 | ): 440 | self.context = ctx 441 | if ctx.guild is not None: 442 | perms = ctx.channel.permissions_for(ctx.guild.me) 443 | if not perms.embed_links: 444 | raise commands.BotMissingPermissions(("embed links",)) 445 | if not perms.read_message_history: 446 | raise commands.BotMissingPermissions(("read message history",)) 447 | if not perms.add_reactions: 448 | raise commands.BotMissingPermissions(["add reactions permission"]) 449 | self.paginator.clear() 450 | self.paginator.ending_note = self.get_ending_note() 451 | await super().prepare_help_command(ctx, command) 452 | 453 | async def command_callback( 454 | self, ctx: commands.Context, /, *, command: Optional[str] = None 455 | ) -> None: 456 | await self.prepare_help_command(ctx, command) 457 | if command is not None: 458 | keys = command.split(" ") 459 | bot: commands.Bot = ctx.bot 460 | if cmd := bot.tree.get_command(keys[0]): 461 | for key in keys[1:]: 462 | try: 463 | found = cmd.get_command(key) 464 | except AttributeError: 465 | pass 466 | else: 467 | cmd = found 468 | if isinstance(cmd, app_commands.commands.Group): 469 | await self.send_app_group_help(cmd) 470 | else: 471 | await self.send_app_command_help(cmd) 472 | return 473 | await super().command_callback(ctx, command=command) 474 | 475 | def get_ending_note(self): 476 | """Returns help command's ending note. This is mainly useful to override for i18n purposes.""" 477 | note = self.ending_note or ( 478 | "Type {help.clean_prefix}{help.invoked_with} command for more info on a command.\n" 479 | "You can also type {help.clean_prefix}{help.invoked_with} category for more info on a category." 480 | ) 481 | return note.format( 482 | ctx=self.context, 483 | help=self if hasattr(self, "clean_prefix") else self.context, 484 | ) 485 | 486 | async def send_pages(self): 487 | """ 488 | Send the pages that have been created 489 | """ 490 | pages = self.paginator.pages 491 | destination = self.get_destination() 492 | if self.delete_invoke and self.context.interaction is None: 493 | try: 494 | await self.context.message.delete() 495 | except (discord.errors.Forbidden, commands.errors.CommandInvokeError): 496 | print("Missing permissions to delete invoked message") 497 | if not pages: 498 | await destination.send(f"```{self.get_ending_note()}```") 499 | else: 500 | await self.menu.send_pages(self.context, destination, pages) 501 | 502 | def get_destination(self): 503 | ctx = self.context 504 | return ctx.author if self.dm_help is True else ctx.channel 505 | 506 | async def send_bot_help(self, mapping: dict): 507 | """ 508 | Creates and sends the help command if there are no other arguments included 509 | Called internally 510 | """ 511 | bot = self.context.bot 512 | channel = self.get_destination() 513 | app_mapping = list( 514 | filter( 515 | lambda cmd: isinstance(cmd, app_commands.commands.Command) 516 | and not isinstance(cmd, commands.hybrid.HybridAppCommand) 517 | and cmd.name != "help", 518 | bot.tree.get_commands(), 519 | ) 520 | ) 521 | if self.send_typing: 522 | await channel.typing() 523 | mapping = {name: [] for name in mapping} 524 | help_filtered = ( 525 | filter(lambda c: c.name != "help", bot.commands) 526 | if len(bot.commands) > 1 527 | else bot.commands 528 | ) 529 | for cmd in ( 530 | await self.filter_commands( 531 | help_filtered, 532 | sort=self.sort_commands, 533 | ) 534 | + app_mapping 535 | ): 536 | if hasattr(cmd, "binding"): 537 | mapping[cmd.binding].append(cmd) 538 | else: 539 | mapping[cmd.cog].append(cmd) 540 | self.paginator.add_cog(self.no_category, mapping.pop(None)) 541 | sorted_map = sorted( 542 | mapping.items(), 543 | key=lambda cg: cg[0].qualified_name 544 | if isinstance(cg[0], commands.Cog) 545 | else str(cg[0]), 546 | ) 547 | for cog, command_list in sorted_map: 548 | # if a cog has the app_command attribute, it's an AppGroup Cog 549 | if cog.app_command: 550 | command_list += cog.app_command.commands 551 | self.paginator.add_cog(cog, command_list) 552 | self.paginator.add_index(self.index_title, bot) 553 | await self.send_pages() 554 | 555 | def get_app_command_signature(self, command: app_commands.commands.Command): 556 | """ 557 | Returns the application command signature 558 | 559 | Args: 560 | command (app_commands.commands.Command): The Application command to get a signature for 561 | """ 562 | required = "" 563 | not_required = "" 564 | if command.parameters: 565 | required = " ".join( 566 | f"<{parameter.name}>" 567 | for parameter in command.parameters 568 | if parameter.required 569 | ) 570 | not_required = " ".join( 571 | f"[{parameter.name}]" 572 | for parameter in command.parameters 573 | if not parameter.required 574 | ) 575 | 576 | return f"/{command.qualified_name} {required} {not_required}" 577 | 578 | def get_app_group_signature(self, group: app_commands.commands.Group): 579 | """ 580 | Returns the application command group signature 581 | 582 | Args: 583 | group (app_commands.commands.Group): The Application group to get a signature for 584 | """ 585 | return f"/{group.qualified_name}" 586 | 587 | async def send_app_command_help(self, command: app_commands.commands.Command): 588 | self.paginator.add_app_command(command, self.get_app_command_signature(command)) 589 | await self.send_pages() 590 | 591 | async def send_app_group_help(self, group: app_commands.commands.Group): 592 | self.paginator.add_app_group(group, self.get_app_group_signature(group)) 593 | await self.send_pages() 594 | 595 | async def send_command_help(self, command: commands.Command): 596 | filtered = await self.filter_commands([command]) 597 | if filtered: 598 | self.paginator.add_command(command, self.get_command_signature(command)) 599 | await self.send_pages() 600 | 601 | async def send_group_help(self, group: commands.Group): 602 | if self.send_typing: 603 | await self.get_destination().typing() 604 | filtered = await self.filter_commands(group.commands, sort=self.sort_commands) 605 | self.paginator.add_group(group, filtered) 606 | await self.send_pages() 607 | 608 | async def send_cog_help(self, cog: commands.Cog): 609 | if self.send_typing: 610 | await self.get_destination().typing() 611 | filtered = await self.filter_commands( 612 | cog.get_commands(), sort=self.sort_commands 613 | ) 614 | filtered += await self.filter_app_commands(cog.get_app_commands()) 615 | if cog.app_command: 616 | filtered += await self.filter_app_commands(cog.app_command.commands) 617 | self.paginator.add_cog(cog, filtered) 618 | await self.send_pages() 619 | 620 | async def send_error_message(self, error: str, /) -> None: 621 | """Check if the context is from an app command or text command and send an error message""" 622 | if self.context.interaction: 623 | return await self.context.interaction.response.send_message( 624 | error, ephemeral=True 625 | ) 626 | 627 | return await super().send_error_message(error) 628 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. 2 | 3 | [[package]] 4 | name = "aiohttp" 5 | version = "3.8.4" 6 | description = "Async http client/server framework (asyncio)" 7 | category = "dev" 8 | optional = false 9 | python-versions = ">=3.6" 10 | files = [ 11 | {file = "aiohttp-3.8.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5ce45967538fb747370308d3145aa68a074bdecb4f3a300869590f725ced69c1"}, 12 | {file = "aiohttp-3.8.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b744c33b6f14ca26b7544e8d8aadff6b765a80ad6164fb1a430bbadd593dfb1a"}, 13 | {file = "aiohttp-3.8.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1a45865451439eb320784918617ba54b7a377e3501fb70402ab84d38c2cd891b"}, 14 | {file = "aiohttp-3.8.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a86d42d7cba1cec432d47ab13b6637bee393a10f664c425ea7b305d1301ca1a3"}, 15 | {file = "aiohttp-3.8.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee3c36df21b5714d49fc4580247947aa64bcbe2939d1b77b4c8dcb8f6c9faecc"}, 16 | {file = "aiohttp-3.8.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:176a64b24c0935869d5bbc4c96e82f89f643bcdf08ec947701b9dbb3c956b7dd"}, 17 | {file = "aiohttp-3.8.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c844fd628851c0bc309f3c801b3a3d58ce430b2ce5b359cd918a5a76d0b20cb5"}, 18 | {file = "aiohttp-3.8.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5393fb786a9e23e4799fec788e7e735de18052f83682ce2dfcabaf1c00c2c08e"}, 19 | {file = "aiohttp-3.8.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e4b09863aae0dc965c3ef36500d891a3ff495a2ea9ae9171e4519963c12ceefd"}, 20 | {file = "aiohttp-3.8.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:adfbc22e87365a6e564c804c58fc44ff7727deea782d175c33602737b7feadb6"}, 21 | {file = "aiohttp-3.8.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:147ae376f14b55f4f3c2b118b95be50a369b89b38a971e80a17c3fd623f280c9"}, 22 | {file = "aiohttp-3.8.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:eafb3e874816ebe2a92f5e155f17260034c8c341dad1df25672fb710627c6949"}, 23 | {file = "aiohttp-3.8.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c6cc15d58053c76eacac5fa9152d7d84b8d67b3fde92709195cb984cfb3475ea"}, 24 | {file = "aiohttp-3.8.4-cp310-cp310-win32.whl", hash = "sha256:59f029a5f6e2d679296db7bee982bb3d20c088e52a2977e3175faf31d6fb75d1"}, 25 | {file = "aiohttp-3.8.4-cp310-cp310-win_amd64.whl", hash = "sha256:fe7ba4a51f33ab275515f66b0a236bcde4fb5561498fe8f898d4e549b2e4509f"}, 26 | {file = "aiohttp-3.8.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3d8ef1a630519a26d6760bc695842579cb09e373c5f227a21b67dc3eb16cfea4"}, 27 | {file = "aiohttp-3.8.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b3f2e06a512e94722886c0827bee9807c86a9f698fac6b3aee841fab49bbfb4"}, 28 | {file = "aiohttp-3.8.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3a80464982d41b1fbfe3154e440ba4904b71c1a53e9cd584098cd41efdb188ef"}, 29 | {file = "aiohttp-3.8.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b631e26df63e52f7cce0cce6507b7a7f1bc9b0c501fcde69742130b32e8782f"}, 30 | {file = "aiohttp-3.8.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f43255086fe25e36fd5ed8f2ee47477408a73ef00e804cb2b5cba4bf2ac7f5e"}, 31 | {file = "aiohttp-3.8.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4d347a172f866cd1d93126d9b239fcbe682acb39b48ee0873c73c933dd23bd0f"}, 32 | {file = "aiohttp-3.8.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3fec6a4cb5551721cdd70473eb009d90935b4063acc5f40905d40ecfea23e05"}, 33 | {file = "aiohttp-3.8.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80a37fe8f7c1e6ce8f2d9c411676e4bc633a8462844e38f46156d07a7d401654"}, 34 | {file = "aiohttp-3.8.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d1e6a862b76f34395a985b3cd39a0d949ca80a70b6ebdea37d3ab39ceea6698a"}, 35 | {file = "aiohttp-3.8.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cd468460eefef601ece4428d3cf4562459157c0f6523db89365202c31b6daebb"}, 36 | {file = "aiohttp-3.8.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:618c901dd3aad4ace71dfa0f5e82e88b46ef57e3239fc7027773cb6d4ed53531"}, 37 | {file = "aiohttp-3.8.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:652b1bff4f15f6287550b4670546a2947f2a4575b6c6dff7760eafb22eacbf0b"}, 38 | {file = "aiohttp-3.8.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80575ba9377c5171407a06d0196b2310b679dc752d02a1fcaa2bc20b235dbf24"}, 39 | {file = "aiohttp-3.8.4-cp311-cp311-win32.whl", hash = "sha256:bbcf1a76cf6f6dacf2c7f4d2ebd411438c275faa1dc0c68e46eb84eebd05dd7d"}, 40 | {file = "aiohttp-3.8.4-cp311-cp311-win_amd64.whl", hash = "sha256:6e74dd54f7239fcffe07913ff8b964e28b712f09846e20de78676ce2a3dc0bfc"}, 41 | {file = "aiohttp-3.8.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:880e15bb6dad90549b43f796b391cfffd7af373f4646784795e20d92606b7a51"}, 42 | {file = "aiohttp-3.8.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb96fa6b56bb536c42d6a4a87dfca570ff8e52de2d63cabebfd6fb67049c34b6"}, 43 | {file = "aiohttp-3.8.4-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a6cadebe132e90cefa77e45f2d2f1a4b2ce5c6b1bfc1656c1ddafcfe4ba8131"}, 44 | {file = "aiohttp-3.8.4-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f352b62b45dff37b55ddd7b9c0c8672c4dd2eb9c0f9c11d395075a84e2c40f75"}, 45 | {file = "aiohttp-3.8.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ab43061a0c81198d88f39aaf90dae9a7744620978f7ef3e3708339b8ed2ef01"}, 46 | {file = "aiohttp-3.8.4-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9cb1565a7ad52e096a6988e2ee0397f72fe056dadf75d17fa6b5aebaea05622"}, 47 | {file = "aiohttp-3.8.4-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:1b3ea7edd2d24538959c1c1abf97c744d879d4e541d38305f9bd7d9b10c9ec41"}, 48 | {file = "aiohttp-3.8.4-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:7c7837fe8037e96b6dd5cfcf47263c1620a9d332a87ec06a6ca4564e56bd0f36"}, 49 | {file = "aiohttp-3.8.4-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:3b90467ebc3d9fa5b0f9b6489dfb2c304a1db7b9946fa92aa76a831b9d587e99"}, 50 | {file = "aiohttp-3.8.4-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:cab9401de3ea52b4b4c6971db5fb5c999bd4260898af972bf23de1c6b5dd9d71"}, 51 | {file = "aiohttp-3.8.4-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:d1f9282c5f2b5e241034a009779e7b2a1aa045f667ff521e7948ea9b56e0c5ff"}, 52 | {file = "aiohttp-3.8.4-cp36-cp36m-win32.whl", hash = "sha256:5e14f25765a578a0a634d5f0cd1e2c3f53964553a00347998dfdf96b8137f777"}, 53 | {file = "aiohttp-3.8.4-cp36-cp36m-win_amd64.whl", hash = "sha256:4c745b109057e7e5f1848c689ee4fb3a016c8d4d92da52b312f8a509f83aa05e"}, 54 | {file = "aiohttp-3.8.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:aede4df4eeb926c8fa70de46c340a1bc2c6079e1c40ccf7b0eae1313ffd33519"}, 55 | {file = "aiohttp-3.8.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ddaae3f3d32fc2cb4c53fab020b69a05c8ab1f02e0e59665c6f7a0d3a5be54f"}, 56 | {file = "aiohttp-3.8.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4eb3b82ca349cf6fadcdc7abcc8b3a50ab74a62e9113ab7a8ebc268aad35bb9"}, 57 | {file = "aiohttp-3.8.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bcb89336efa095ea21b30f9e686763f2be4478f1b0a616969551982c4ee4c3b"}, 58 | {file = "aiohttp-3.8.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c08e8ed6fa3d477e501ec9db169bfac8140e830aa372d77e4a43084d8dd91ab"}, 59 | {file = "aiohttp-3.8.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c6cd05ea06daca6ad6a4ca3ba7fe7dc5b5de063ff4daec6170ec0f9979f6c332"}, 60 | {file = "aiohttp-3.8.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7a00a9ed8d6e725b55ef98b1b35c88013245f35f68b1b12c5cd4100dddac333"}, 61 | {file = "aiohttp-3.8.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:de04b491d0e5007ee1b63a309956eaed959a49f5bb4e84b26c8f5d49de140fa9"}, 62 | {file = "aiohttp-3.8.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:40653609b3bf50611356e6b6554e3a331f6879fa7116f3959b20e3528783e699"}, 63 | {file = "aiohttp-3.8.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:dbf3a08a06b3f433013c143ebd72c15cac33d2914b8ea4bea7ac2c23578815d6"}, 64 | {file = "aiohttp-3.8.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:854f422ac44af92bfe172d8e73229c270dc09b96535e8a548f99c84f82dde241"}, 65 | {file = "aiohttp-3.8.4-cp37-cp37m-win32.whl", hash = "sha256:aeb29c84bb53a84b1a81c6c09d24cf33bb8432cc5c39979021cc0f98c1292a1a"}, 66 | {file = "aiohttp-3.8.4-cp37-cp37m-win_amd64.whl", hash = "sha256:db3fc6120bce9f446d13b1b834ea5b15341ca9ff3f335e4a951a6ead31105480"}, 67 | {file = "aiohttp-3.8.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fabb87dd8850ef0f7fe2b366d44b77d7e6fa2ea87861ab3844da99291e81e60f"}, 68 | {file = "aiohttp-3.8.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:91f6d540163f90bbaef9387e65f18f73ffd7c79f5225ac3d3f61df7b0d01ad15"}, 69 | {file = "aiohttp-3.8.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d265f09a75a79a788237d7f9054f929ced2e69eb0bb79de3798c468d8a90f945"}, 70 | {file = "aiohttp-3.8.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d89efa095ca7d442a6d0cbc755f9e08190ba40069b235c9886a8763b03785da"}, 71 | {file = "aiohttp-3.8.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4dac314662f4e2aa5009977b652d9b8db7121b46c38f2073bfeed9f4049732cd"}, 72 | {file = "aiohttp-3.8.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe11310ae1e4cd560035598c3f29d86cef39a83d244c7466f95c27ae04850f10"}, 73 | {file = "aiohttp-3.8.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ddb2a2026c3f6a68c3998a6c47ab6795e4127315d2e35a09997da21865757f8"}, 74 | {file = "aiohttp-3.8.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e75b89ac3bd27d2d043b234aa7b734c38ba1b0e43f07787130a0ecac1e12228a"}, 75 | {file = "aiohttp-3.8.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6e601588f2b502c93c30cd5a45bfc665faaf37bbe835b7cfd461753068232074"}, 76 | {file = "aiohttp-3.8.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a5d794d1ae64e7753e405ba58e08fcfa73e3fad93ef9b7e31112ef3c9a0efb52"}, 77 | {file = "aiohttp-3.8.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:a1f4689c9a1462f3df0a1f7e797791cd6b124ddbee2b570d34e7f38ade0e2c71"}, 78 | {file = "aiohttp-3.8.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:3032dcb1c35bc330134a5b8a5d4f68c1a87252dfc6e1262c65a7e30e62298275"}, 79 | {file = "aiohttp-3.8.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8189c56eb0ddbb95bfadb8f60ea1b22fcfa659396ea36f6adcc521213cd7b44d"}, 80 | {file = "aiohttp-3.8.4-cp38-cp38-win32.whl", hash = "sha256:33587f26dcee66efb2fff3c177547bd0449ab7edf1b73a7f5dea1e38609a0c54"}, 81 | {file = "aiohttp-3.8.4-cp38-cp38-win_amd64.whl", hash = "sha256:e595432ac259af2d4630008bf638873d69346372d38255774c0e286951e8b79f"}, 82 | {file = "aiohttp-3.8.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5a7bdf9e57126dc345b683c3632e8ba317c31d2a41acd5800c10640387d193ed"}, 83 | {file = "aiohttp-3.8.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:22f6eab15b6db242499a16de87939a342f5a950ad0abaf1532038e2ce7d31567"}, 84 | {file = "aiohttp-3.8.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7235604476a76ef249bd64cb8274ed24ccf6995c4a8b51a237005ee7a57e8643"}, 85 | {file = "aiohttp-3.8.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea9eb976ffdd79d0e893869cfe179a8f60f152d42cb64622fca418cd9b18dc2a"}, 86 | {file = "aiohttp-3.8.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92c0cea74a2a81c4c76b62ea1cac163ecb20fb3ba3a75c909b9fa71b4ad493cf"}, 87 | {file = "aiohttp-3.8.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:493f5bc2f8307286b7799c6d899d388bbaa7dfa6c4caf4f97ef7521b9cb13719"}, 88 | {file = "aiohttp-3.8.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a63f03189a6fa7c900226e3ef5ba4d3bd047e18f445e69adbd65af433add5a2"}, 89 | {file = "aiohttp-3.8.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10c8cefcff98fd9168cdd86c4da8b84baaa90bf2da2269c6161984e6737bf23e"}, 90 | {file = "aiohttp-3.8.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bca5f24726e2919de94f047739d0a4fc01372801a3672708260546aa2601bf57"}, 91 | {file = "aiohttp-3.8.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:03baa76b730e4e15a45f81dfe29a8d910314143414e528737f8589ec60cf7391"}, 92 | {file = "aiohttp-3.8.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:8c29c77cc57e40f84acef9bfb904373a4e89a4e8b74e71aa8075c021ec9078c2"}, 93 | {file = "aiohttp-3.8.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:03543dcf98a6619254b409be2d22b51f21ec66272be4ebda7b04e6412e4b2e14"}, 94 | {file = "aiohttp-3.8.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:17b79c2963db82086229012cff93ea55196ed31f6493bb1ccd2c62f1724324e4"}, 95 | {file = "aiohttp-3.8.4-cp39-cp39-win32.whl", hash = "sha256:34ce9f93a4a68d1272d26030655dd1b58ff727b3ed2a33d80ec433561b03d67a"}, 96 | {file = "aiohttp-3.8.4-cp39-cp39-win_amd64.whl", hash = "sha256:41a86a69bb63bb2fc3dc9ad5ea9f10f1c9c8e282b471931be0268ddd09430b04"}, 97 | {file = "aiohttp-3.8.4.tar.gz", hash = "sha256:bf2e1a9162c1e441bf805a1fd166e249d574ca04e03b34f97e2928769e91ab5c"}, 98 | ] 99 | 100 | [package.dependencies] 101 | aiosignal = ">=1.1.2" 102 | async-timeout = ">=4.0.0a3,<5.0" 103 | attrs = ">=17.3.0" 104 | charset-normalizer = ">=2.0,<4.0" 105 | frozenlist = ">=1.1.1" 106 | multidict = ">=4.5,<7.0" 107 | yarl = ">=1.0,<2.0" 108 | 109 | [package.extras] 110 | speedups = ["Brotli", "aiodns", "cchardet"] 111 | 112 | [[package]] 113 | name = "aiosignal" 114 | version = "1.3.1" 115 | description = "aiosignal: a list of registered asynchronous callbacks" 116 | category = "dev" 117 | optional = false 118 | python-versions = ">=3.7" 119 | files = [ 120 | {file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"}, 121 | {file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"}, 122 | ] 123 | 124 | [package.dependencies] 125 | frozenlist = ">=1.1.0" 126 | 127 | [[package]] 128 | name = "async-timeout" 129 | version = "4.0.2" 130 | description = "Timeout context manager for asyncio programs" 131 | category = "dev" 132 | optional = false 133 | python-versions = ">=3.6" 134 | files = [ 135 | {file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"}, 136 | {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, 137 | ] 138 | 139 | [[package]] 140 | name = "attrs" 141 | version = "23.1.0" 142 | description = "Classes Without Boilerplate" 143 | category = "dev" 144 | optional = false 145 | python-versions = ">=3.7" 146 | files = [ 147 | {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, 148 | {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, 149 | ] 150 | 151 | [package.extras] 152 | cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] 153 | dev = ["attrs[docs,tests]", "pre-commit"] 154 | docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] 155 | tests = ["attrs[tests-no-zope]", "zope-interface"] 156 | tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] 157 | 158 | [[package]] 159 | name = "black" 160 | version = "22.12.0" 161 | description = "The uncompromising code formatter." 162 | category = "dev" 163 | optional = false 164 | python-versions = ">=3.7" 165 | files = [ 166 | {file = "black-22.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eedd20838bd5d75b80c9f5487dbcb06836a43833a37846cf1d8c1cc01cef59d"}, 167 | {file = "black-22.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:159a46a4947f73387b4d83e87ea006dbb2337eab6c879620a3ba52699b1f4351"}, 168 | {file = "black-22.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d30b212bffeb1e252b31dd269dfae69dd17e06d92b87ad26e23890f3efea366f"}, 169 | {file = "black-22.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:7412e75863aa5c5411886804678b7d083c7c28421210180d67dfd8cf1221e1f4"}, 170 | {file = "black-22.12.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c116eed0efb9ff870ded8b62fe9f28dd61ef6e9ddd28d83d7d264a38417dcee2"}, 171 | {file = "black-22.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1f58cbe16dfe8c12b7434e50ff889fa479072096d79f0a7f25e4ab8e94cd8350"}, 172 | {file = "black-22.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d86c9f3db9b1bf6761244bc0b3572a546f5fe37917a044e02f3166d5aafa7d"}, 173 | {file = "black-22.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:82d9fe8fee3401e02e79767016b4907820a7dc28d70d137eb397b92ef3cc5bfc"}, 174 | {file = "black-22.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:101c69b23df9b44247bd88e1d7e90154336ac4992502d4197bdac35dd7ee3320"}, 175 | {file = "black-22.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:559c7a1ba9a006226f09e4916060982fd27334ae1998e7a38b3f33a37f7a2148"}, 176 | {file = "black-22.12.0-py3-none-any.whl", hash = "sha256:436cc9167dd28040ad90d3b404aec22cedf24a6e4d7de221bec2730ec0c97bcf"}, 177 | {file = "black-22.12.0.tar.gz", hash = "sha256:229351e5a18ca30f447bf724d007f890f97e13af070bb6ad4c0a441cd7596a2f"}, 178 | ] 179 | 180 | [package.dependencies] 181 | click = ">=8.0.0" 182 | mypy-extensions = ">=0.4.3" 183 | pathspec = ">=0.9.0" 184 | platformdirs = ">=2" 185 | tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} 186 | typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} 187 | 188 | [package.extras] 189 | colorama = ["colorama (>=0.4.3)"] 190 | d = ["aiohttp (>=3.7.4)"] 191 | jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] 192 | uvloop = ["uvloop (>=0.15.2)"] 193 | 194 | [[package]] 195 | name = "charset-normalizer" 196 | version = "3.1.0" 197 | description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." 198 | category = "dev" 199 | optional = false 200 | python-versions = ">=3.7.0" 201 | files = [ 202 | {file = "charset-normalizer-3.1.0.tar.gz", hash = "sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5"}, 203 | {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b"}, 204 | {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60"}, 205 | {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1"}, 206 | {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0"}, 207 | {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f"}, 208 | {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0"}, 209 | {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795"}, 210 | {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c"}, 211 | {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203"}, 212 | {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1"}, 213 | {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137"}, 214 | {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce"}, 215 | {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a"}, 216 | {file = "charset_normalizer-3.1.0-cp310-cp310-win32.whl", hash = "sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448"}, 217 | {file = "charset_normalizer-3.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8"}, 218 | {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19"}, 219 | {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017"}, 220 | {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df"}, 221 | {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a"}, 222 | {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41"}, 223 | {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1"}, 224 | {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62"}, 225 | {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6"}, 226 | {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5"}, 227 | {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be"}, 228 | {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb"}, 229 | {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac"}, 230 | {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324"}, 231 | {file = "charset_normalizer-3.1.0-cp311-cp311-win32.whl", hash = "sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909"}, 232 | {file = "charset_normalizer-3.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755"}, 233 | {file = "charset_normalizer-3.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373"}, 234 | {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab"}, 235 | {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9"}, 236 | {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f"}, 237 | {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28"}, 238 | {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d"}, 239 | {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d"}, 240 | {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d"}, 241 | {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6"}, 242 | {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84"}, 243 | {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c"}, 244 | {file = "charset_normalizer-3.1.0-cp37-cp37m-win32.whl", hash = "sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974"}, 245 | {file = "charset_normalizer-3.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23"}, 246 | {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531"}, 247 | {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c"}, 248 | {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14"}, 249 | {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb"}, 250 | {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1"}, 251 | {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b"}, 252 | {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0"}, 253 | {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649"}, 254 | {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326"}, 255 | {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11"}, 256 | {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b"}, 257 | {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd"}, 258 | {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8"}, 259 | {file = "charset_normalizer-3.1.0-cp38-cp38-win32.whl", hash = "sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0"}, 260 | {file = "charset_normalizer-3.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59"}, 261 | {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e"}, 262 | {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31"}, 263 | {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f"}, 264 | {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e"}, 265 | {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f"}, 266 | {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854"}, 267 | {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706"}, 268 | {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e"}, 269 | {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0"}, 270 | {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230"}, 271 | {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7"}, 272 | {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e"}, 273 | {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f"}, 274 | {file = "charset_normalizer-3.1.0-cp39-cp39-win32.whl", hash = "sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1"}, 275 | {file = "charset_normalizer-3.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b"}, 276 | {file = "charset_normalizer-3.1.0-py3-none-any.whl", hash = "sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d"}, 277 | ] 278 | 279 | [[package]] 280 | name = "click" 281 | version = "8.1.3" 282 | description = "Composable command line interface toolkit" 283 | category = "dev" 284 | optional = false 285 | python-versions = ">=3.7" 286 | files = [ 287 | {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, 288 | {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, 289 | ] 290 | 291 | [package.dependencies] 292 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 293 | 294 | [[package]] 295 | name = "colorama" 296 | version = "0.4.6" 297 | description = "Cross-platform colored terminal text." 298 | category = "dev" 299 | optional = false 300 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" 301 | files = [ 302 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, 303 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, 304 | ] 305 | 306 | [[package]] 307 | name = "discord-py" 308 | version = "2.2.2" 309 | description = "A Python wrapper for the Discord API" 310 | category = "dev" 311 | optional = false 312 | python-versions = ">=3.8.0" 313 | files = [ 314 | {file = "discord.py-2.2.2-py3-none-any.whl", hash = "sha256:38fc52a784727b8e5e5749267089400035b187a009028eddfabeb182abcc6d52"}, 315 | {file = "discord.py-2.2.2.tar.gz", hash = "sha256:b9944056bcb5711b2d04088848fd004466cf117c15c84fa798bf55470f28275f"}, 316 | ] 317 | 318 | [package.dependencies] 319 | aiohttp = ">=3.7.4,<4" 320 | 321 | [package.extras] 322 | docs = ["sphinx (==4.4.0)", "sphinxcontrib-trio (==1.1.2)", "sphinxcontrib-websupport", "typing-extensions (>=4.3,<5)"] 323 | speed = ["Brotli", "aiodns (>=1.1)", "cchardet (==2.1.7)", "orjson (>=3.5.4)"] 324 | test = ["coverage[toml]", "pytest", "pytest-asyncio", "pytest-cov", "pytest-mock", "typing-extensions (>=4.3,<5)"] 325 | voice = ["PyNaCl (>=1.3.0,<1.6)"] 326 | 327 | [[package]] 328 | name = "frozenlist" 329 | version = "1.3.3" 330 | description = "A list-like structure which implements collections.abc.MutableSequence" 331 | category = "dev" 332 | optional = false 333 | python-versions = ">=3.7" 334 | files = [ 335 | {file = "frozenlist-1.3.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff8bf625fe85e119553b5383ba0fb6aa3d0ec2ae980295aaefa552374926b3f4"}, 336 | {file = "frozenlist-1.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dfbac4c2dfcc082fcf8d942d1e49b6aa0766c19d3358bd86e2000bf0fa4a9cf0"}, 337 | {file = "frozenlist-1.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b1c63e8d377d039ac769cd0926558bb7068a1f7abb0f003e3717ee003ad85530"}, 338 | {file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7fdfc24dcfce5b48109867c13b4cb15e4660e7bd7661741a391f821f23dfdca7"}, 339 | {file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2c926450857408e42f0bbc295e84395722ce74bae69a3b2aa2a65fe22cb14b99"}, 340 | {file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1841e200fdafc3d51f974d9d377c079a0694a8f06de2e67b48150328d66d5483"}, 341 | {file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f470c92737afa7d4c3aacc001e335062d582053d4dbe73cda126f2d7031068dd"}, 342 | {file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:783263a4eaad7c49983fe4b2e7b53fa9770c136c270d2d4bbb6d2192bf4d9caf"}, 343 | {file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:924620eef691990dfb56dc4709f280f40baee568c794b5c1885800c3ecc69816"}, 344 | {file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ae4dc05c465a08a866b7a1baf360747078b362e6a6dbeb0c57f234db0ef88ae0"}, 345 | {file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:bed331fe18f58d844d39ceb398b77d6ac0b010d571cba8267c2e7165806b00ce"}, 346 | {file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:02c9ac843e3390826a265e331105efeab489ffaf4dd86384595ee8ce6d35ae7f"}, 347 | {file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9545a33965d0d377b0bc823dcabf26980e77f1b6a7caa368a365a9497fb09420"}, 348 | {file = "frozenlist-1.3.3-cp310-cp310-win32.whl", hash = "sha256:d5cd3ab21acbdb414bb6c31958d7b06b85eeb40f66463c264a9b343a4e238642"}, 349 | {file = "frozenlist-1.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:b756072364347cb6aa5b60f9bc18e94b2f79632de3b0190253ad770c5df17db1"}, 350 | {file = "frozenlist-1.3.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b4395e2f8d83fbe0c627b2b696acce67868793d7d9750e90e39592b3626691b7"}, 351 | {file = "frozenlist-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:14143ae966a6229350021384870458e4777d1eae4c28d1a7aa47f24d030e6678"}, 352 | {file = "frozenlist-1.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5d8860749e813a6f65bad8285a0520607c9500caa23fea6ee407e63debcdbef6"}, 353 | {file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23d16d9f477bb55b6154654e0e74557040575d9d19fe78a161bd33d7d76808e8"}, 354 | {file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb82dbba47a8318e75f679690190c10a5e1f447fbf9df41cbc4c3afd726d88cb"}, 355 | {file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9309869032abb23d196cb4e4db574232abe8b8be1339026f489eeb34a4acfd91"}, 356 | {file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a97b4fe50b5890d36300820abd305694cb865ddb7885049587a5678215782a6b"}, 357 | {file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c188512b43542b1e91cadc3c6c915a82a5eb95929134faf7fd109f14f9892ce4"}, 358 | {file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:303e04d422e9b911a09ad499b0368dc551e8c3cd15293c99160c7f1f07b59a48"}, 359 | {file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:0771aed7f596c7d73444c847a1c16288937ef988dc04fb9f7be4b2aa91db609d"}, 360 | {file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:66080ec69883597e4d026f2f71a231a1ee9887835902dbe6b6467d5a89216cf6"}, 361 | {file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:41fe21dc74ad3a779c3d73a2786bdf622ea81234bdd4faf90b8b03cad0c2c0b4"}, 362 | {file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f20380df709d91525e4bee04746ba612a4df0972c1b8f8e1e8af997e678c7b81"}, 363 | {file = "frozenlist-1.3.3-cp311-cp311-win32.whl", hash = "sha256:f30f1928162e189091cf4d9da2eac617bfe78ef907a761614ff577ef4edfb3c8"}, 364 | {file = "frozenlist-1.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:a6394d7dadd3cfe3f4b3b186e54d5d8504d44f2d58dcc89d693698e8b7132b32"}, 365 | {file = "frozenlist-1.3.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8df3de3a9ab8325f94f646609a66cbeeede263910c5c0de0101079ad541af332"}, 366 | {file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0693c609e9742c66ba4870bcee1ad5ff35462d5ffec18710b4ac89337ff16e27"}, 367 | {file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd4210baef299717db0a600d7a3cac81d46ef0e007f88c9335db79f8979c0d3d"}, 368 | {file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:394c9c242113bfb4b9aa36e2b80a05ffa163a30691c7b5a29eba82e937895d5e"}, 369 | {file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6327eb8e419f7d9c38f333cde41b9ae348bec26d840927332f17e887a8dcb70d"}, 370 | {file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e24900aa13212e75e5b366cb9065e78bbf3893d4baab6052d1aca10d46d944c"}, 371 | {file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:3843f84a6c465a36559161e6c59dce2f2ac10943040c2fd021cfb70d58c4ad56"}, 372 | {file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:84610c1502b2461255b4c9b7d5e9c48052601a8957cd0aea6ec7a7a1e1fb9420"}, 373 | {file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:c21b9aa40e08e4f63a2f92ff3748e6b6c84d717d033c7b3438dd3123ee18f70e"}, 374 | {file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:efce6ae830831ab6a22b9b4091d411698145cb9b8fc869e1397ccf4b4b6455cb"}, 375 | {file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:40de71985e9042ca00b7953c4f41eabc3dc514a2d1ff534027f091bc74416401"}, 376 | {file = "frozenlist-1.3.3-cp37-cp37m-win32.whl", hash = "sha256:180c00c66bde6146a860cbb81b54ee0df350d2daf13ca85b275123bbf85de18a"}, 377 | {file = "frozenlist-1.3.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9bbbcedd75acdfecf2159663b87f1bb5cfc80e7cd99f7ddd9d66eb98b14a8411"}, 378 | {file = "frozenlist-1.3.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:034a5c08d36649591be1cbb10e09da9f531034acfe29275fc5454a3b101ce41a"}, 379 | {file = "frozenlist-1.3.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ba64dc2b3b7b158c6660d49cdb1d872d1d0bf4e42043ad8d5006099479a194e5"}, 380 | {file = "frozenlist-1.3.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:47df36a9fe24054b950bbc2db630d508cca3aa27ed0566c0baf661225e52c18e"}, 381 | {file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:008a054b75d77c995ea26629ab3a0c0d7281341f2fa7e1e85fa6153ae29ae99c"}, 382 | {file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:841ea19b43d438a80b4de62ac6ab21cfe6827bb8a9dc62b896acc88eaf9cecba"}, 383 | {file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e235688f42b36be2b6b06fc37ac2126a73b75fb8d6bc66dd632aa35286238703"}, 384 | {file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca713d4af15bae6e5d79b15c10c8522859a9a89d3b361a50b817c98c2fb402a2"}, 385 | {file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ac5995f2b408017b0be26d4a1d7c61bce106ff3d9e3324374d66b5964325448"}, 386 | {file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a4ae8135b11652b08a8baf07631d3ebfe65a4c87909dbef5fa0cdde440444ee4"}, 387 | {file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4ea42116ceb6bb16dbb7d526e242cb6747b08b7710d9782aa3d6732bd8d27649"}, 388 | {file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:810860bb4bdce7557bc0febb84bbd88198b9dbc2022d8eebe5b3590b2ad6c842"}, 389 | {file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:ee78feb9d293c323b59a6f2dd441b63339a30edf35abcb51187d2fc26e696d13"}, 390 | {file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0af2e7c87d35b38732e810befb9d797a99279cbb85374d42ea61c1e9d23094b3"}, 391 | {file = "frozenlist-1.3.3-cp38-cp38-win32.whl", hash = "sha256:899c5e1928eec13fd6f6d8dc51be23f0d09c5281e40d9cf4273d188d9feeaf9b"}, 392 | {file = "frozenlist-1.3.3-cp38-cp38-win_amd64.whl", hash = "sha256:7f44e24fa70f6fbc74aeec3e971f60a14dde85da364aa87f15d1be94ae75aeef"}, 393 | {file = "frozenlist-1.3.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2b07ae0c1edaa0a36339ec6cce700f51b14a3fc6545fdd32930d2c83917332cf"}, 394 | {file = "frozenlist-1.3.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ebb86518203e12e96af765ee89034a1dbb0c3c65052d1b0c19bbbd6af8a145e1"}, 395 | {file = "frozenlist-1.3.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5cf820485f1b4c91e0417ea0afd41ce5cf5965011b3c22c400f6d144296ccbc0"}, 396 | {file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c11e43016b9024240212d2a65043b70ed8dfd3b52678a1271972702d990ac6d"}, 397 | {file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8fa3c6e3305aa1146b59a09b32b2e04074945ffcfb2f0931836d103a2c38f936"}, 398 | {file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:352bd4c8c72d508778cf05ab491f6ef36149f4d0cb3c56b1b4302852255d05d5"}, 399 | {file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65a5e4d3aa679610ac6e3569e865425b23b372277f89b5ef06cf2cdaf1ebf22b"}, 400 | {file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1e2c1185858d7e10ff045c496bbf90ae752c28b365fef2c09cf0fa309291669"}, 401 | {file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f163d2fd041c630fed01bc48d28c3ed4a3b003c00acd396900e11ee5316b56bb"}, 402 | {file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:05cdb16d09a0832eedf770cb7bd1fe57d8cf4eaf5aced29c4e41e3f20b30a784"}, 403 | {file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:8bae29d60768bfa8fb92244b74502b18fae55a80eac13c88eb0b496d4268fd2d"}, 404 | {file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:eedab4c310c0299961ac285591acd53dc6723a1ebd90a57207c71f6e0c2153ab"}, 405 | {file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3bbdf44855ed8f0fbcd102ef05ec3012d6a4fd7c7562403f76ce6a52aeffb2b1"}, 406 | {file = "frozenlist-1.3.3-cp39-cp39-win32.whl", hash = "sha256:efa568b885bca461f7c7b9e032655c0c143d305bf01c30caf6db2854a4532b38"}, 407 | {file = "frozenlist-1.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:cfe33efc9cb900a4c46f91a5ceba26d6df370ffddd9ca386eb1d4f0ad97b9ea9"}, 408 | {file = "frozenlist-1.3.3.tar.gz", hash = "sha256:58bcc55721e8a90b88332d6cd441261ebb22342e238296bb330968952fbb3a6a"}, 409 | ] 410 | 411 | [[package]] 412 | name = "idna" 413 | version = "3.4" 414 | description = "Internationalized Domain Names in Applications (IDNA)" 415 | category = "dev" 416 | optional = false 417 | python-versions = ">=3.5" 418 | files = [ 419 | {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, 420 | {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, 421 | ] 422 | 423 | [[package]] 424 | name = "multidict" 425 | version = "6.0.4" 426 | description = "multidict implementation" 427 | category = "dev" 428 | optional = false 429 | python-versions = ">=3.7" 430 | files = [ 431 | {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b1a97283e0c85772d613878028fec909f003993e1007eafa715b24b377cb9b8"}, 432 | {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eeb6dcc05e911516ae3d1f207d4b0520d07f54484c49dfc294d6e7d63b734171"}, 433 | {file = "multidict-6.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d6d635d5209b82a3492508cf5b365f3446afb65ae7ebd755e70e18f287b0adf7"}, 434 | {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c048099e4c9e9d615545e2001d3d8a4380bd403e1a0578734e0d31703d1b0c0b"}, 435 | {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ea20853c6dbbb53ed34cb4d080382169b6f4554d394015f1bef35e881bf83547"}, 436 | {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16d232d4e5396c2efbbf4f6d4df89bfa905eb0d4dc5b3549d872ab898451f569"}, 437 | {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36c63aaa167f6c6b04ef2c85704e93af16c11d20de1d133e39de6a0e84582a93"}, 438 | {file = "multidict-6.0.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:64bdf1086b6043bf519869678f5f2757f473dee970d7abf6da91ec00acb9cb98"}, 439 | {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:43644e38f42e3af682690876cff722d301ac585c5b9e1eacc013b7a3f7b696a0"}, 440 | {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7582a1d1030e15422262de9f58711774e02fa80df0d1578995c76214f6954988"}, 441 | {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ddff9c4e225a63a5afab9dd15590432c22e8057e1a9a13d28ed128ecf047bbdc"}, 442 | {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ee2a1ece51b9b9e7752e742cfb661d2a29e7bcdba2d27e66e28a99f1890e4fa0"}, 443 | {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a2e4369eb3d47d2034032a26c7a80fcb21a2cb22e1173d761a162f11e562caa5"}, 444 | {file = "multidict-6.0.4-cp310-cp310-win32.whl", hash = "sha256:574b7eae1ab267e5f8285f0fe881f17efe4b98c39a40858247720935b893bba8"}, 445 | {file = "multidict-6.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:4dcbb0906e38440fa3e325df2359ac6cb043df8e58c965bb45f4e406ecb162cc"}, 446 | {file = "multidict-6.0.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0dfad7a5a1e39c53ed00d2dd0c2e36aed4650936dc18fd9a1826a5ae1cad6f03"}, 447 | {file = "multidict-6.0.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:64da238a09d6039e3bd39bb3aee9c21a5e34f28bfa5aa22518581f910ff94af3"}, 448 | {file = "multidict-6.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ff959bee35038c4624250473988b24f846cbeb2c6639de3602c073f10410ceba"}, 449 | {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01a3a55bd90018c9c080fbb0b9f4891db37d148a0a18722b42f94694f8b6d4c9"}, 450 | {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c5cb09abb18c1ea940fb99360ea0396f34d46566f157122c92dfa069d3e0e982"}, 451 | {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:666daae833559deb2d609afa4490b85830ab0dfca811a98b70a205621a6109fe"}, 452 | {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11bdf3f5e1518b24530b8241529d2050014c884cf18b6fc69c0c2b30ca248710"}, 453 | {file = "multidict-6.0.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d18748f2d30f94f498e852c67d61261c643b349b9d2a581131725595c45ec6c"}, 454 | {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:458f37be2d9e4c95e2d8866a851663cbc76e865b78395090786f6cd9b3bbf4f4"}, 455 | {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b1a2eeedcead3a41694130495593a559a668f382eee0727352b9a41e1c45759a"}, 456 | {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7d6ae9d593ef8641544d6263c7fa6408cc90370c8cb2bbb65f8d43e5b0351d9c"}, 457 | {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:5979b5632c3e3534e42ca6ff856bb24b2e3071b37861c2c727ce220d80eee9ed"}, 458 | {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dcfe792765fab89c365123c81046ad4103fcabbc4f56d1c1997e6715e8015461"}, 459 | {file = "multidict-6.0.4-cp311-cp311-win32.whl", hash = "sha256:3601a3cece3819534b11d4efc1eb76047488fddd0c85a3948099d5da4d504636"}, 460 | {file = "multidict-6.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:81a4f0b34bd92df3da93315c6a59034df95866014ac08535fc819f043bfd51f0"}, 461 | {file = "multidict-6.0.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:67040058f37a2a51ed8ea8f6b0e6ee5bd78ca67f169ce6122f3e2ec80dfe9b78"}, 462 | {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:853888594621e6604c978ce2a0444a1e6e70c8d253ab65ba11657659dcc9100f"}, 463 | {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:39ff62e7d0f26c248b15e364517a72932a611a9b75f35b45be078d81bdb86603"}, 464 | {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af048912e045a2dc732847d33821a9d84ba553f5c5f028adbd364dd4765092ac"}, 465 | {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1e8b901e607795ec06c9e42530788c45ac21ef3aaa11dbd0c69de543bfb79a9"}, 466 | {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62501642008a8b9871ddfccbf83e4222cf8ac0d5aeedf73da36153ef2ec222d2"}, 467 | {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:99b76c052e9f1bc0721f7541e5e8c05db3941eb9ebe7b8553c625ef88d6eefde"}, 468 | {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:509eac6cf09c794aa27bcacfd4d62c885cce62bef7b2c3e8b2e49d365b5003fe"}, 469 | {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:21a12c4eb6ddc9952c415f24eef97e3e55ba3af61f67c7bc388dcdec1404a067"}, 470 | {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:5cad9430ab3e2e4fa4a2ef4450f548768400a2ac635841bc2a56a2052cdbeb87"}, 471 | {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ab55edc2e84460694295f401215f4a58597f8f7c9466faec545093045476327d"}, 472 | {file = "multidict-6.0.4-cp37-cp37m-win32.whl", hash = "sha256:5a4dcf02b908c3b8b17a45fb0f15b695bf117a67b76b7ad18b73cf8e92608775"}, 473 | {file = "multidict-6.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:6ed5f161328b7df384d71b07317f4d8656434e34591f20552c7bcef27b0ab88e"}, 474 | {file = "multidict-6.0.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5fc1b16f586f049820c5c5b17bb4ee7583092fa0d1c4e28b5239181ff9532e0c"}, 475 | {file = "multidict-6.0.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1502e24330eb681bdaa3eb70d6358e818e8e8f908a22a1851dfd4e15bc2f8161"}, 476 | {file = "multidict-6.0.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b692f419760c0e65d060959df05f2a531945af31fda0c8a3b3195d4efd06de11"}, 477 | {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45e1ecb0379bfaab5eef059f50115b54571acfbe422a14f668fc8c27ba410e7e"}, 478 | {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ddd3915998d93fbcd2566ddf9cf62cdb35c9e093075f862935573d265cf8f65d"}, 479 | {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:59d43b61c59d82f2effb39a93c48b845efe23a3852d201ed2d24ba830d0b4cf2"}, 480 | {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc8e1d0c705233c5dd0c5e6460fbad7827d5d36f310a0fadfd45cc3029762258"}, 481 | {file = "multidict-6.0.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6aa0418fcc838522256761b3415822626f866758ee0bc6632c9486b179d0b52"}, 482 | {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6748717bb10339c4760c1e63da040f5f29f5ed6e59d76daee30305894069a660"}, 483 | {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4d1a3d7ef5e96b1c9e92f973e43aa5e5b96c659c9bc3124acbbd81b0b9c8a951"}, 484 | {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4372381634485bec7e46718edc71528024fcdc6f835baefe517b34a33c731d60"}, 485 | {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:fc35cb4676846ef752816d5be2193a1e8367b4c1397b74a565a9d0389c433a1d"}, 486 | {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4b9d9e4e2b37daddb5c23ea33a3417901fa7c7b3dee2d855f63ee67a0b21e5b1"}, 487 | {file = "multidict-6.0.4-cp38-cp38-win32.whl", hash = "sha256:e41b7e2b59679edfa309e8db64fdf22399eec4b0b24694e1b2104fb789207779"}, 488 | {file = "multidict-6.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:d6c254ba6e45d8e72739281ebc46ea5eb5f101234f3ce171f0e9f5cc86991480"}, 489 | {file = "multidict-6.0.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:16ab77bbeb596e14212e7bab8429f24c1579234a3a462105cda4a66904998664"}, 490 | {file = "multidict-6.0.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc779e9e6f7fda81b3f9aa58e3a6091d49ad528b11ed19f6621408806204ad35"}, 491 | {file = "multidict-6.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ceef517eca3e03c1cceb22030a3e39cb399ac86bff4e426d4fc6ae49052cc60"}, 492 | {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:281af09f488903fde97923c7744bb001a9b23b039a909460d0f14edc7bf59706"}, 493 | {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52f2dffc8acaba9a2f27174c41c9e57f60b907bb9f096b36b1a1f3be71c6284d"}, 494 | {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b41156839806aecb3641f3208c0dafd3ac7775b9c4c422d82ee2a45c34ba81ca"}, 495 | {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5e3fc56f88cc98ef8139255cf8cd63eb2c586531e43310ff859d6bb3a6b51f1"}, 496 | {file = "multidict-6.0.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8316a77808c501004802f9beebde51c9f857054a0c871bd6da8280e718444449"}, 497 | {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f70b98cd94886b49d91170ef23ec5c0e8ebb6f242d734ed7ed677b24d50c82cf"}, 498 | {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bf6774e60d67a9efe02b3616fee22441d86fab4c6d335f9d2051d19d90a40063"}, 499 | {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:e69924bfcdda39b722ef4d9aa762b2dd38e4632b3641b1d9a57ca9cd18f2f83a"}, 500 | {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:6b181d8c23da913d4ff585afd1155a0e1194c0b50c54fcfe286f70cdaf2b7176"}, 501 | {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:52509b5be062d9eafc8170e53026fbc54cf3b32759a23d07fd935fb04fc22d95"}, 502 | {file = "multidict-6.0.4-cp39-cp39-win32.whl", hash = "sha256:27c523fbfbdfd19c6867af7346332b62b586eed663887392cff78d614f9ec313"}, 503 | {file = "multidict-6.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:33029f5734336aa0d4c0384525da0387ef89148dc7191aae00ca5fb23d7aafc2"}, 504 | {file = "multidict-6.0.4.tar.gz", hash = "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49"}, 505 | ] 506 | 507 | [[package]] 508 | name = "mypy-extensions" 509 | version = "1.0.0" 510 | description = "Type system extensions for programs checked with the mypy type checker." 511 | category = "dev" 512 | optional = false 513 | python-versions = ">=3.5" 514 | files = [ 515 | {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, 516 | {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, 517 | ] 518 | 519 | [[package]] 520 | name = "pathspec" 521 | version = "0.11.1" 522 | description = "Utility library for gitignore style pattern matching of file paths." 523 | category = "dev" 524 | optional = false 525 | python-versions = ">=3.7" 526 | files = [ 527 | {file = "pathspec-0.11.1-py3-none-any.whl", hash = "sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293"}, 528 | {file = "pathspec-0.11.1.tar.gz", hash = "sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687"}, 529 | ] 530 | 531 | [[package]] 532 | name = "platformdirs" 533 | version = "3.2.0" 534 | description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." 535 | category = "dev" 536 | optional = false 537 | python-versions = ">=3.7" 538 | files = [ 539 | {file = "platformdirs-3.2.0-py3-none-any.whl", hash = "sha256:ebe11c0d7a805086e99506aa331612429a72ca7cd52a1f0d277dc4adc20cb10e"}, 540 | {file = "platformdirs-3.2.0.tar.gz", hash = "sha256:d5b638ca397f25f979350ff789db335903d7ea010ab28903f57b27e1b16c2b08"}, 541 | ] 542 | 543 | [package.extras] 544 | docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"] 545 | test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.2.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] 546 | 547 | [[package]] 548 | name = "python-dotenv" 549 | version = "1.0.0" 550 | description = "Read key-value pairs from a .env file and set them as environment variables" 551 | category = "dev" 552 | optional = false 553 | python-versions = ">=3.8" 554 | files = [ 555 | {file = "python-dotenv-1.0.0.tar.gz", hash = "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba"}, 556 | {file = "python_dotenv-1.0.0-py3-none-any.whl", hash = "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a"}, 557 | ] 558 | 559 | [package.extras] 560 | cli = ["click (>=5.0)"] 561 | 562 | [[package]] 563 | name = "tomli" 564 | version = "2.0.1" 565 | description = "A lil' TOML parser" 566 | category = "dev" 567 | optional = false 568 | python-versions = ">=3.7" 569 | files = [ 570 | {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, 571 | {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, 572 | ] 573 | 574 | [[package]] 575 | name = "typing-extensions" 576 | version = "4.5.0" 577 | description = "Backported and Experimental Type Hints for Python 3.7+" 578 | category = "dev" 579 | optional = false 580 | python-versions = ">=3.7" 581 | files = [ 582 | {file = "typing_extensions-4.5.0-py3-none-any.whl", hash = "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"}, 583 | {file = "typing_extensions-4.5.0.tar.gz", hash = "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb"}, 584 | ] 585 | 586 | [[package]] 587 | name = "yarl" 588 | version = "1.9.1" 589 | description = "Yet another URL library" 590 | category = "dev" 591 | optional = false 592 | python-versions = ">=3.7" 593 | files = [ 594 | {file = "yarl-1.9.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e124b283a04cc06d22443cae536f93d86cd55108fa369f22b8fe1f2288b2fe1c"}, 595 | {file = "yarl-1.9.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:56956b13ec275de31fe4fb991510b735c4fb3e1b01600528c952b9ac90464430"}, 596 | {file = "yarl-1.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ecaa5755a39f6f26079bf13f336c67af589c222d76b53cd3824d3b684b84d1f1"}, 597 | {file = "yarl-1.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92a101f6d5a9464e86092adc36cd40ef23d18a25bfb1eb32eaeb62edc22776bb"}, 598 | {file = "yarl-1.9.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92e37999e36f9f3ded78e9d839face6baa2abdf9344ea8ed2735f495736159de"}, 599 | {file = "yarl-1.9.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef7e2f6c47c41e234600a02e1356b799761485834fe35d4706b0094cb3a587ee"}, 600 | {file = "yarl-1.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d7a0075a55380b19aa43b9e8056e128b058460d71d75018a4f9d60ace01e78c"}, 601 | {file = "yarl-1.9.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2f01351b7809182822b21061d2a4728b7b9e08f4585ba90ee4c5c4d3faa0812"}, 602 | {file = "yarl-1.9.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6cf47fe9df9b1ededc77e492581cdb6890a975ad96b4172e1834f1b8ba0fc3ba"}, 603 | {file = "yarl-1.9.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:098bdc06ffb4db39c73883325b8c738610199f5f12e85339afedf07e912a39af"}, 604 | {file = "yarl-1.9.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:6cdb47cbbacae8e1d7941b0d504d0235d686090eef5212ca2450525905e9cf02"}, 605 | {file = "yarl-1.9.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:73a4b46689f2d59c8ec6b71c9a0cdced4e7863dd6eb98a8c30ea610e191f9e1c"}, 606 | {file = "yarl-1.9.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:65d952e464df950eed32bb5dcbc1b4443c7c2de4d7abd7265b45b1b3b27f5fa2"}, 607 | {file = "yarl-1.9.1-cp310-cp310-win32.whl", hash = "sha256:39a7a9108e9fc633ae381562f8f0355bb4ba00355218b5fb19cf5263fcdbfa68"}, 608 | {file = "yarl-1.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:b63d41e0eecf3e3070d44f97456cf351fff7cb960e97ecb60a936b877ff0b4f6"}, 609 | {file = "yarl-1.9.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4295790981630c4dab9d6de7b0f555a4c8defe3ed7704a8e9e595a321e59a0f5"}, 610 | {file = "yarl-1.9.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b2b2382d59dec0f1fdca18ea429c4c4cee280d5e0dbc841180abb82e188cf6e9"}, 611 | {file = "yarl-1.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:575975d28795a61e82c85f114c02333ca54cbd325fd4e4b27598c9832aa732e7"}, 612 | {file = "yarl-1.9.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bb794882818fae20ff65348985fdf143ea6dfaf6413814db1848120db8be33e"}, 613 | {file = "yarl-1.9.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:89da1fd6068553e3a333011cc17ad91c414b2100c32579ddb51517edc768b49c"}, 614 | {file = "yarl-1.9.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4d817593d345fefda2fae877accc8a0d9f47ada57086da6125fa02a62f6d1a94"}, 615 | {file = "yarl-1.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85aa6fd779e194901386709e0eedd45710b68af2709f82a84839c44314b68c10"}, 616 | {file = "yarl-1.9.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eed9827033b7f67ad12cb70bd0cb59d36029144a7906694317c2dbf5c9eb5ddd"}, 617 | {file = "yarl-1.9.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:df747104ef27ab1aa9a1145064fa9ea26ad8cf24bfcbdba7db7abf0f8b3676b9"}, 618 | {file = "yarl-1.9.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:efec77851231410125cb5be04ec96fa4a075ca637f415a1f2d2c900b09032a8a"}, 619 | {file = "yarl-1.9.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:d5c407e530cf2979ea383885516ae79cc4f3c3530623acf5e42daf521f5c2564"}, 620 | {file = "yarl-1.9.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:f76edb386178a54ea7ceffa798cb830c3c22ab50ea10dfb25dc952b04848295f"}, 621 | {file = "yarl-1.9.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:75676110bce59944dd48fd18d0449bd37eaeb311b38a0c768f7670864b5f8b68"}, 622 | {file = "yarl-1.9.1-cp311-cp311-win32.whl", hash = "sha256:9ba5a18c4fbd408fe49dc5da85478a76bc75c1ce912d7fd7b43ed5297c4403e1"}, 623 | {file = "yarl-1.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:b20a5ddc4e243cbaa54886bfe9af6ffc4ba4ef58f17f1bb691e973eb65bba84d"}, 624 | {file = "yarl-1.9.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:791357d537a09a194f92b834f28c98d074e7297bac0a8f1d5b458a906cafa17c"}, 625 | {file = "yarl-1.9.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89099c887338608da935ba8bee027564a94f852ac40e472de15d8309517ad5fe"}, 626 | {file = "yarl-1.9.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:395ea180257a3742d09dcc5071739682a95f7874270ebe3982d6696caec75be0"}, 627 | {file = "yarl-1.9.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:90ebaf448b5f048352ec7c76cb8d452df30c27cb6b8627dfaa9cf742a14f141a"}, 628 | {file = "yarl-1.9.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f878a78ed2ccfbd973cab46dd0933ecd704787724db23979e5731674d76eb36f"}, 629 | {file = "yarl-1.9.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:74390c2318d066962500045aa145f5412169bce842e734b8c3e6e3750ad5b817"}, 630 | {file = "yarl-1.9.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f8e73f526140c1c32f5fca4cd0bc3b511a1abcd948f45b2a38a95e4edb76ca72"}, 631 | {file = "yarl-1.9.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ac8e593df1fbea820da7676929f821a0c7c2cecb8477d010254ce8ed54328ea8"}, 632 | {file = "yarl-1.9.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:01cf88cb80411978a14aa49980968c1aeb7c18a90ac978c778250dd234d8e0ba"}, 633 | {file = "yarl-1.9.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:97d76a3128f48fa1c721ef8a50e2c2f549296b2402dc8a8cde12ff60ed922f53"}, 634 | {file = "yarl-1.9.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:01a073c9175481dfed6b40704a1b67af5a9435fc4a58a27d35fd6b303469b0c7"}, 635 | {file = "yarl-1.9.1-cp37-cp37m-win32.whl", hash = "sha256:ecad20c3ef57c513dce22f58256361d10550a89e8eaa81d5082f36f8af305375"}, 636 | {file = "yarl-1.9.1-cp37-cp37m-win_amd64.whl", hash = "sha256:f5bcb80006efe9bf9f49ae89711253dd06df8053ff814622112a9219346566a7"}, 637 | {file = "yarl-1.9.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e7ddebeabf384099814353a2956ed3ab5dbaa6830cc7005f985fcb03b5338f05"}, 638 | {file = "yarl-1.9.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:13a1ad1f35839b3bb5226f59816b71e243d95d623f5b392efaf8820ddb2b3cd5"}, 639 | {file = "yarl-1.9.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f0cd87949d619157a0482c6c14e5011f8bf2bc0b91cb5087414d9331f4ef02dd"}, 640 | {file = "yarl-1.9.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d21887cbcf6a3cc5951662d8222bc9c04e1b1d98eebe3bb659c3a04ed49b0eec"}, 641 | {file = "yarl-1.9.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4764114e261fe49d5df9b316b3221493d177247825c735b2aae77bc2e340d800"}, 642 | {file = "yarl-1.9.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3abe37fd89a93ebe0010417ca671f422fa6fcffec54698f623b09f46b4d4a512"}, 643 | {file = "yarl-1.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9fe3a1c073ab80a28a06f41d2b623723046709ed29faf2c56bea41848597d86"}, 644 | {file = "yarl-1.9.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3b5f8da07a21f2e57551f88a6709c2d340866146cf7351e5207623cfe8aad16"}, 645 | {file = "yarl-1.9.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:88f6413ff5edfb9609e2769e32ce87a62353e66e75d264bf0eaad26fb9daa8f2"}, 646 | {file = "yarl-1.9.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b5d5fb6c94b620a7066a3adb7c246c87970f453813979818e4707ac32ce4d7bd"}, 647 | {file = "yarl-1.9.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:f206adb89424dca4a4d0b31981869700e44cd62742527e26d6b15a510dd410a2"}, 648 | {file = "yarl-1.9.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:44fa6158e6b4b8ccfa2872c3900a226b29e8ce543ce3e48aadc99816afa8874d"}, 649 | {file = "yarl-1.9.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:08c8599d6aa8a24425f8635f6c06fa8726afe3be01c8e53e236f519bcfa5db5b"}, 650 | {file = "yarl-1.9.1-cp38-cp38-win32.whl", hash = "sha256:6b09cce412386ea9b4dda965d8e78d04ac5b5792b2fa9cced3258ec69c7d1c16"}, 651 | {file = "yarl-1.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:09c56a32c26e24ef98d5757c5064e252836f621f9a8b42737773aa92936b8e08"}, 652 | {file = "yarl-1.9.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b86e98c3021b7e2740d8719bf074301361bf2f51221ca2765b7a58afbfbd9042"}, 653 | {file = "yarl-1.9.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5faf3ec98747318cb980aaf9addf769da68a66431fc203a373d95d7ee9c1fbb4"}, 654 | {file = "yarl-1.9.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a21789bdf28549d4eb1de6910cabc762c9f6ae3eef85efc1958197c1c6ef853b"}, 655 | {file = "yarl-1.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8b8d4b478a9862447daef4cafc89d87ea4ed958672f1d11db7732b77ead49cc"}, 656 | {file = "yarl-1.9.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:307a782736ebf994e7600dcaeea3b3113083584da567272f2075f1540919d6b3"}, 657 | {file = "yarl-1.9.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:46c4010de941e2e1365c07fb4418ddca10fcff56305a6067f5ae857f8c98f3a7"}, 658 | {file = "yarl-1.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bab67d041c78e305ff3eef5e549304d843bd9b603c8855b68484ee663374ce15"}, 659 | {file = "yarl-1.9.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1baf8cdaaab65d9ccedbf8748d626ad648b74b0a4d033e356a2f3024709fb82f"}, 660 | {file = "yarl-1.9.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:27efc2e324f72df02818cd72d7674b1f28b80ab49f33a94f37c6473c8166ce49"}, 661 | {file = "yarl-1.9.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ca14b84091700ae7c1fcd3a6000bd4ec1a3035009b8bcb94f246741ca840bb22"}, 662 | {file = "yarl-1.9.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c3ca8d71b23bdf164b36d06df2298ec8a5bd3de42b17bf3e0e8e6a7489195f2c"}, 663 | {file = "yarl-1.9.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:8c72a1dc7e2ea882cd3df0417c808ad3b69e559acdc43f3b096d67f2fb801ada"}, 664 | {file = "yarl-1.9.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d966cd59df9a4b218480562e8daab39e87e746b78a96add51a3ab01636fc4291"}, 665 | {file = "yarl-1.9.1-cp39-cp39-win32.whl", hash = "sha256:518a92a34c741836a315150460b5c1c71ae782d569eabd7acf53372e437709f7"}, 666 | {file = "yarl-1.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:78755ce43b6e827e65ec0c68be832f86d059fcf05d4b33562745ebcfa91b26b1"}, 667 | {file = "yarl-1.9.1.tar.gz", hash = "sha256:5ce0bcab7ec759062c818d73837644cde567ab8aa1e0d6c45db38dfb7c284441"}, 668 | ] 669 | 670 | [package.dependencies] 671 | idna = ">=2.0" 672 | multidict = ">=4.0" 673 | 674 | [metadata] 675 | lock-version = "2.0" 676 | python-versions = "^3.8" 677 | content-hash = "0fdc1cbb61f543b3548bb0d1a1dceabc7d09edcff5fa169aad57ec7767a166f7" 678 | --------------------------------------------------------------------------------