diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | bot/constants.py | 3 | ||||
-rw-r--r-- | bot/converters.py | 18 | ||||
-rw-r--r-- | bot/exts/filtering/_filters/unique/rich_embed.py | 2 | ||||
-rw-r--r-- | bot/exts/filtering/_utils.py | 2 | ||||
-rw-r--r-- | bot/exts/info/information.py | 14 | ||||
-rw-r--r-- | bot/exts/moderation/clean.py | 4 | ||||
-rw-r--r-- | bot/exts/moderation/defcon.py | 13 | ||||
-rw-r--r-- | bot/exts/moderation/infraction/_scheduler.py | 10 | ||||
-rw-r--r-- | bot/exts/moderation/infraction/management.py | 10 | ||||
-rw-r--r-- | bot/exts/moderation/modlog.py | 211 | ||||
-rw-r--r-- | bot/exts/moderation/voice_gate.py | 288 | ||||
-rw-r--r-- | bot/exts/moderation/watchchannels/_watchchannel.py | 13 | ||||
-rw-r--r-- | bot/resources/tags/codeblock.md | 2 | ||||
-rw-r--r-- | bot/resources/tags/equals-true.md | 24 | ||||
-rw-r--r-- | bot/resources/tags/range-len.md | 4 | ||||
-rw-r--r-- | bot/utils/modlog.py | 69 | ||||
-rw-r--r-- | poetry.lock | 506 | ||||
-rw-r--r-- | pyproject.toml | 20 | ||||
-rw-r--r-- | tests/bot/exts/moderation/test_modlog.py | 4 |
20 files changed, 624 insertions, 594 deletions
diff --git a/.gitignore b/.gitignore index 65a9af431..630f83870 100644 --- a/.gitignore +++ b/.gitignore @@ -117,6 +117,7 @@ log.* *config.yml docker-compose.override.yml metricity-config.toml +pyrightconfig.json # xmlrunner unittest XML reports TEST-**.xml diff --git a/bot/constants.py b/bot/constants.py index 1ddb1748e..0250d0e31 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -352,11 +352,10 @@ PythonNews = _PythonNews() class _VoiceGate(EnvConfig, env_prefix="voice_gate_"): - bot_message_delete_delay: int = 10 + delete_after_delay: int = 60 minimum_activity_blocks: int = 3 minimum_days_member: int = 3 minimum_messages: int = 50 - voice_ping_delete_delay: int = 60 VoiceGate = _VoiceGate() diff --git a/bot/converters.py b/bot/converters.py index 3c8ea44d7..038f815a5 100644 --- a/bot/converters.py +++ b/bot/converters.py @@ -423,23 +423,19 @@ class HushDurationConverter(Converter): def _is_an_unambiguous_user_argument(argument: str) -> bool: - """Check if the provided argument is a user mention, user id, or username (name#discrim).""" - has_id_or_mention = bool(IDConverter()._get_id_match(argument) or RE_USER_MENTION.match(argument)) + """Check if the provided argument is a user mention or user id.""" + user_id = IDConverter._get_id_match(argument) + user_mention = RE_USER_MENTION.match(argument) - # Check to see if the author passed a username (a discriminator exists) - argument = argument.removeprefix("@") - has_username = len(argument) > 5 and argument[-5] == "#" + return bool(user_id or user_mention) - return has_id_or_mention or has_username - -AMBIGUOUS_ARGUMENT_MSG = ("`{argument}` is not a User mention, a User ID or a Username in the format" - " `name#discriminator`.") +AMBIGUOUS_ARGUMENT_MSG = "`{argument}` is not a User mention or a User ID." class UnambiguousUser(UserConverter): """ - Converts to a `discord.User`, but only if a mention, userID or a username (name#discrim) is provided. + Converts to a `discord.User`, but only if a mention or userID is provided. Unlike the default `UserConverter`, it doesn't allow conversion from a name. This is useful in cases where that lookup strategy would lead to too much ambiguity. @@ -454,7 +450,7 @@ class UnambiguousUser(UserConverter): class UnambiguousMember(MemberConverter): """ - Converts to a `discord.Member`, but only if a mention, userID or a username (name#discrim) is provided. + Converts to a `discord.Member`, but only if a mention or userID is provided. Unlike the default `MemberConverter`, it doesn't allow conversion from a name or nickname. This is useful in cases where that lookup strategy would lead to too much ambiguity. diff --git a/bot/exts/filtering/_filters/unique/rich_embed.py b/bot/exts/filtering/_filters/unique/rich_embed.py index cfed18e64..cbcc90272 100644 --- a/bot/exts/filtering/_filters/unique/rich_embed.py +++ b/bot/exts/filtering/_filters/unique/rich_embed.py @@ -8,7 +8,7 @@ from bot.utils.helpers import remove_subdomain_from_url log = get_logger(__name__) -URL_RE = re.compile(r"(https?://\S+)", flags=re.IGNORECASE) +URL_RE = re.compile(r"(https?://[^\)\s]+)", flags=re.IGNORECASE) class RichEmbedFilter(UniqueFilter): diff --git a/bot/exts/filtering/_utils.py b/bot/exts/filtering/_utils.py index 5fe3bd3c9..a12d09875 100644 --- a/bot/exts/filtering/_utils.py +++ b/bot/exts/filtering/_utils.py @@ -266,7 +266,7 @@ class CustomIOField: _handler: Callable[[Any], core_schema.CoreSchema], ) -> core_schema.CoreSchema: """Boilerplate for Pydantic.""" - return core_schema.general_plain_validator_function(cls.validate) + return core_schema.with_info_plain_validator_function(cls.validate) @classmethod def validate(cls, v: Any, _info: core_schema.ValidationInfo) -> Self: diff --git a/bot/exts/info/information.py b/bot/exts/info/information.py index c7ee9065c..8ef68bd9e 100644 --- a/bot/exts/info/information.py +++ b/bot/exts/info/information.py @@ -420,7 +420,7 @@ class Information(Cog): return "Nominations", "\n".join(output) - async def user_messages(self, user: MemberOrUser) -> tuple[bool | str, tuple[str, str]]: + async def user_messages(self, user: MemberOrUser) -> tuple[str, str]: """ Gets the amount of messages for `member`. @@ -435,15 +435,21 @@ class Information(Cog): if e.status == 404: activity_output = "No activity" else: - activity_output.append(f"{user_activity['total_messages']:,}" or "No messages") - activity_output.append(f"{user_activity['activity_blocks']:,}" or "No activity") + total_message_text = ( + f"{user_activity['total_messages']:,}" if user_activity["total_messages"] else "No messages" + ) + activity_blocks_text = ( + f"{user_activity['activity_blocks']:,}" if user_activity["activity_blocks"] else "No activity" + ) + activity_output.append(total_message_text) + activity_output.append(activity_blocks_text) activity_output = "\n".join( f"{name}: {metric}" for name, metric in zip(["Messages", "Activity blocks"], activity_output, strict=True) ) - return ("Activity", activity_output) + return "Activity", activity_output def format_fields(self, mapping: Mapping[str, Any], field_width: int | None = None) -> str: """Format a mapping to be readable to a human.""" diff --git a/bot/exts/moderation/clean.py b/bot/exts/moderation/clean.py index 1c73736d7..d38de15e0 100644 --- a/bot/exts/moderation/clean.py +++ b/bot/exts/moderation/clean.py @@ -21,6 +21,7 @@ from bot.exts.moderation.modlog import ModLog from bot.log import get_logger from bot.utils.channel import is_mod_channel from bot.utils.messages import upload_log +from bot.utils.modlog import send_log_message log = get_logger(__name__) @@ -367,7 +368,8 @@ class Clean(Cog): f"A log of the deleted messages can be found [here]({log_url})." ) - await self.mod_log.send_log_message( + await send_log_message( + self.bot, icon_url=Icons.message_bulk_delete, colour=Colour(Colours.soft_red), title="Bulk message delete", diff --git a/bot/exts/moderation/defcon.py b/bot/exts/moderation/defcon.py index 3c16f8e0e..3196c4a1a 100644 --- a/bot/exts/moderation/defcon.py +++ b/bot/exts/moderation/defcon.py @@ -21,6 +21,7 @@ from bot.exts.moderation.modlog import ModLog from bot.log import get_logger from bot.utils import time from bot.utils.messages import format_user +from bot.utils.modlog import send_log_message log = get_logger(__name__) @@ -136,9 +137,13 @@ class Defcon(Cog): if not message_sent: message = f"{message}\n\nUnable to send rejection message via DM; they probably have DMs disabled." - await (await self.get_mod_log()).send_log_message( - Icons.defcon_denied, Colours.soft_red, "Entry denied", - message, member.display_avatar.url + await send_log_message( + self.bot, + Icons.defcon_denied, + Colours.soft_red, + "Entry denied", + message, + thumbnail=member.display_avatar.url ) @group(name="defcon", aliases=("dc",), invoke_without_command=True) @@ -304,7 +309,7 @@ class Defcon(Cog): ) status_msg = f"DEFCON {action.name.lower()}" - await (await self.get_mod_log()).send_log_message(info.icon, info.color, status_msg, log_msg) + await send_log_message(self.bot, info.icon, info.color, status_msg, log_msg) def _update_notifier(self) -> None: """Start or stop the notifier according to the DEFCON status.""" diff --git a/bot/exts/moderation/infraction/_scheduler.py b/bot/exts/moderation/infraction/_scheduler.py index a079f775e..aed6210a2 100644 --- a/bot/exts/moderation/infraction/_scheduler.py +++ b/bot/exts/moderation/infraction/_scheduler.py @@ -20,6 +20,7 @@ from bot.exts.moderation.modlog import ModLog from bot.log import get_logger from bot.utils import messages, time from bot.utils.channel import is_mod_channel +from bot.utils.modlog import send_log_message log = get_logger(__name__) @@ -270,7 +271,8 @@ class InfractionScheduler: # Send a log message to the mod log. # Don't use ctx.message.author for the actor; antispam only patches ctx.author. log.trace(f"Sending apply mod log for infraction #{id_}.") - await self.mod_log.send_log_message( + await send_log_message( + self.bot, icon_url=icon, colour=Colours.soft_red, title=f"Infraction {log_title}: {' '.join(infr_type.split('_'))}", @@ -369,7 +371,8 @@ class InfractionScheduler: log_text["Reason"] = log_text.pop("Reason") # Send a log message to the mod log. - await self.mod_log.send_log_message( + await send_log_message( + self.bot, icon_url=_utils.INFRACTION_ICONS[infr_type][1], colour=Colours.soft_green, title=f"Infraction {log_title}: {' '.join(infr_type.split('_'))}", @@ -507,7 +510,8 @@ class InfractionScheduler: log_text["Reason"] = log_text.pop("Reason") log.trace(f"Sending deactivation mod log for infraction #{id_}.") - await self.mod_log.send_log_message( + await send_log_message( + self.bot, icon_url=_utils.INFRACTION_ICONS[type_][1], colour=Colours.soft_green, title=f"Infraction {log_title}: {type_}", diff --git a/bot/exts/moderation/infraction/management.py b/bot/exts/moderation/infraction/management.py index 9bf3a4dbb..93959042b 100644 --- a/bot/exts/moderation/infraction/management.py +++ b/bot/exts/moderation/infraction/management.py @@ -16,11 +16,11 @@ from bot.decorators import ensure_future_timestamp from bot.errors import InvalidInfractionError from bot.exts.moderation.infraction import _utils from bot.exts.moderation.infraction.infractions import Infractions -from bot.exts.moderation.modlog import ModLog from bot.log import get_logger from bot.pagination import LinePaginator from bot.utils import messages, time from bot.utils.channel import is_in_category, is_mod_channel +from bot.utils.modlog import send_log_message from bot.utils.time import unpack_duration log = get_logger(__name__) @@ -58,11 +58,6 @@ class ModManagement(commands.Cog): command.help += f"\n{SYMBOLS_GUIDE}" @property - def mod_log(self) -> ModLog: - """Get currently loaded ModLog cog instance.""" - return self.bot.get_cog("ModLog") - - @property def infractions_cog(self) -> Infractions: """Get currently loaded Infractions cog instance.""" return self.bot.get_cog("Infractions") @@ -260,7 +255,8 @@ class ModManagement(commands.Cog): else: jump_url = f"[Click here.]({ctx.message.jump_url})" - await self.mod_log.send_log_message( + await send_log_message( + self.bot, icon_url=constants.Icons.pencil, colour=discord.Colour.og_blurple(), title="Infraction edited", diff --git a/bot/exts/moderation/modlog.py b/bot/exts/moderation/modlog.py index b349f4d5d..3c256396a 100644 --- a/bot/exts/moderation/modlog.py +++ b/bot/exts/moderation/modlog.py @@ -8,7 +8,7 @@ from dateutil.relativedelta import relativedelta from deepdiff import DeepDiff from discord import Colour, Message, Thread from discord.abc import GuildChannel -from discord.ext.commands import Cog, Context +from discord.ext.commands import Cog from discord.utils import escape_markdown, format_dt, snowflake_time from bot.bot import Bot @@ -16,6 +16,7 @@ from bot.constants import Channels, Colours, Emojis, Event, Guild as GuildConsta from bot.log import get_logger from bot.utils import time from bot.utils.messages import format_user, upload_log +from bot.utils.modlog import send_log_message log = get_logger(__name__) @@ -47,63 +48,6 @@ class ModLog(Cog, name="ModLog"): if item not in self._ignored[event]: self._ignored[event].append(item) - async def send_log_message( - self, - icon_url: str | None, - colour: discord.Colour | int, - title: str | None, - text: str, - thumbnail: str | discord.Asset | None = None, - channel_id: int = Channels.mod_log, - ping_everyone: bool = False, - files: list[discord.File] | None = None, - content: str | None = None, - additional_embeds: list[discord.Embed] | None = None, - timestamp_override: datetime | None = None, - footer: str | None = None, - ) -> Context: - """Generate log embed and send to logging channel.""" - await self.bot.wait_until_guild_available() - # Truncate string directly here to avoid removing newlines - embed = discord.Embed( - description=text[:4093] + "..." if len(text) > 4096 else text - ) - - if title and icon_url: - embed.set_author(name=title, icon_url=icon_url) - - embed.colour = colour - embed.timestamp = timestamp_override or datetime.now(tz=UTC) - - if footer: - embed.set_footer(text=footer) - - if thumbnail: - embed.set_thumbnail(url=thumbnail) - - if ping_everyone: - if content: - content = f"<@&{Roles.moderators}> {content}" - else: - content = f"<@&{Roles.moderators}>" - - # Truncate content to 2000 characters and append an ellipsis. - if content and len(content) > 2000: - content = content[:2000 - 3] + "..." - - channel = self.bot.get_channel(channel_id) - log_message = await channel.send( - content=content, - embed=embed, - files=files - ) - - if additional_embeds: - for additional_embed in additional_embeds: - await channel.send(embed=additional_embed) - - return await self.bot.get_context(log_message) # Optionally return for use with antispam - @Cog.listener() async def on_guild_channel_create(self, channel: GUILD_CHANNEL) -> None: """Log channel create event to mod log.""" @@ -128,7 +72,7 @@ class ModLog(Cog, name="ModLog"): else: message = f"{channel.name} (`{channel.id}`)" - await self.send_log_message(Icons.hash_green, Colours.soft_green, title, message) + await send_log_message(self.bot, Icons.hash_green, Colours.soft_green, title, message) @Cog.listener() async def on_guild_channel_delete(self, channel: GUILD_CHANNEL) -> None: @@ -148,9 +92,12 @@ class ModLog(Cog, name="ModLog"): else: message = f"{channel.name} (`{channel.id}`)" - await self.send_log_message( - Icons.hash_red, Colours.soft_red, - title, message + await send_log_message( + self.bot, + Icons.hash_red, + Colours.soft_red, + title, + message ) @Cog.listener() @@ -211,9 +158,12 @@ class ModLog(Cog, name="ModLog"): else: message = f"**#{after.name}** (`{after.id}`)\n{message}" - await self.send_log_message( - Icons.hash_blurple, Colour.og_blurple(), - "Channel updated", message + await send_log_message( + self.bot, + Icons.hash_blurple, + Colour.og_blurple(), + "Channel updated", + message ) @Cog.listener() @@ -222,9 +172,12 @@ class ModLog(Cog, name="ModLog"): if role.guild.id != GuildConstant.id: return - await self.send_log_message( - Icons.crown_green, Colours.soft_green, - "Role created", f"`{role.id}`" + await send_log_message( + self.bot, + Icons.crown_green, + Colours.soft_green, + "Role created", + f"`{role.id}`" ) @Cog.listener() @@ -233,9 +186,12 @@ class ModLog(Cog, name="ModLog"): if role.guild.id != GuildConstant.id: return - await self.send_log_message( - Icons.crown_red, Colours.soft_red, - "Role removed", f"{role.name} (`{role.id}`)" + await send_log_message( + self.bot, + Icons.crown_red, + Colours.soft_red, + "Role removed", + f"{role.name} (`{role.id}`)" ) @Cog.listener() @@ -286,9 +242,12 @@ class ModLog(Cog, name="ModLog"): message = f"**{after.name}** (`{after.id}`)\n{message}" - await self.send_log_message( - Icons.crown_blurple, Colour.og_blurple(), - "Role updated", message + await send_log_message( + self.bot, + Icons.crown_blurple, + Colour.og_blurple(), + "Role updated", + message ) @Cog.listener() @@ -336,9 +295,12 @@ class ModLog(Cog, name="ModLog"): message = f"**{after.name}** (`{after.id}`)\n{message}" - await self.send_log_message( - Icons.guild_update, Colour.og_blurple(), - "Guild updated", message, + await send_log_message( + self.bot, + Icons.guild_update, + Colour.og_blurple(), + "Guild updated", + message, thumbnail=after.icon.with_static_format("png") ) @@ -352,9 +314,12 @@ class ModLog(Cog, name="ModLog"): self._ignored[Event.member_ban].remove(member.id) return - await self.send_log_message( - Icons.user_ban, Colours.soft_red, - "User banned", format_user(member), + await send_log_message( + self.bot, + Icons.user_ban, + Colours.soft_red, + "User banned", + format_user(member), thumbnail=member.display_avatar.url, channel_id=Channels.user_log ) @@ -373,9 +338,12 @@ class ModLog(Cog, name="ModLog"): if difference.days < 1 and difference.months < 1 and difference.years < 1: # New user account! message = f"{Emojis.new} {message}" - await self.send_log_message( - Icons.sign_in, Colours.soft_green, - "User joined", message, + await send_log_message( + self.bot, + Icons.sign_in, + Colours.soft_green, + "User joined", + message, thumbnail=member.display_avatar.url, channel_id=Channels.user_log ) @@ -390,9 +358,12 @@ class ModLog(Cog, name="ModLog"): self._ignored[Event.member_remove].remove(member.id) return - await self.send_log_message( - Icons.sign_out, Colours.soft_red, - "User left", format_user(member), + await send_log_message( + self.bot, + Icons.sign_out, + Colours.soft_red, + "User left", + format_user(member), thumbnail=member.display_avatar.url, channel_id=Channels.user_log ) @@ -407,9 +378,12 @@ class ModLog(Cog, name="ModLog"): self._ignored[Event.member_unban].remove(member.id) return - await self.send_log_message( - Icons.user_unban, Colour.og_blurple(), - "User unbanned", format_user(member), + await send_log_message( + self.bot, + Icons.user_unban, + Colour.og_blurple(), + "User unbanned", + format_user(member), thumbnail=member.display_avatar.url, channel_id=Channels.mod_log ) @@ -471,7 +445,8 @@ class ModLog(Cog, name="ModLog"): message = f"{format_user(after)}\n{message}" - await self.send_log_message( + await send_log_message( + self.bot, icon_url=Icons.user_update, colour=Colour.og_blurple(), title="Member updated", @@ -565,8 +540,10 @@ class ModLog(Cog, name="ModLog"): response += f"{content}" - await self.send_log_message( - Icons.message_delete, Colours.soft_red, + await send_log_message( + self.bot, + Icons.message_delete, + Colours.soft_red, "Message deleted", response, channel_id=Channels.message_log @@ -606,8 +583,10 @@ class ModLog(Cog, name="ModLog"): "This message was not cached, so the message content cannot be displayed." ) - await self.send_log_message( - Icons.message_delete, Colours.soft_red, + await send_log_message( + self.bot, + Icons.message_delete, + Colours.soft_red, "Message deleted", response, channel_id=Channels.message_log @@ -687,9 +666,15 @@ class ModLog(Cog, name="ModLog"): timestamp = msg_before.created_at footer = None - await self.send_log_message( - Icons.message_edit, Colour.og_blurple(), "Message edited", response, - channel_id=Channels.message_log, timestamp_override=timestamp, footer=footer + await send_log_message( + self.bot, + Icons.message_edit, + Colour.og_blurple(), + "Message edited", + response, + channel_id=Channels.message_log, + timestamp_override=timestamp, + footer=footer ) @Cog.listener() @@ -734,14 +719,22 @@ class ModLog(Cog, name="ModLog"): f"{message.clean_content}" ) - await self.send_log_message( - Icons.message_edit, Colour.og_blurple(), "Message edited (Before)", - before_response, channel_id=Channels.message_log + await send_log_message( + self.bot, + Icons.message_edit, + Colour.og_blurple(), + "Message edited (Before)", + before_response, + channel_id=Channels.message_log ) - await self.send_log_message( - Icons.message_edit, Colour.og_blurple(), "Message edited (After)", - after_response, channel_id=Channels.message_log + await send_log_message( + self.bot, + Icons.message_edit, + Colour.og_blurple(), + "Message edited (After)", + after_response, + channel_id=Channels.message_log ) @Cog.listener() @@ -752,7 +745,8 @@ class ModLog(Cog, name="ModLog"): return if before.name != after.name: - await self.send_log_message( + await send_log_message( + self.bot, Icons.hash_blurple, Colour.og_blurple(), "Thread name edited", @@ -774,7 +768,8 @@ class ModLog(Cog, name="ModLog"): else: return - await self.send_log_message( + await send_log_message( + self.bot, icon, colour, f"Thread {action}", @@ -792,7 +787,8 @@ class ModLog(Cog, name="ModLog"): log.trace("Ignoring deletion of thread %s (%d)", thread.mention, thread.id) return - await self.send_log_message( + await send_log_message( + self.bot, Icons.hash_red, Colours.soft_red, "Thread deleted", @@ -868,7 +864,8 @@ class ModLog(Cog, name="ModLog"): message = "\n".join(f"{Emojis.bullet} {item}" for item in sorted(changes)) message = f"{format_user(member)}\n{message}" - await self.send_log_message( + await send_log_message( + self.bot, icon_url=icon, colour=colour, title="Voice state updated", diff --git a/bot/exts/moderation/voice_gate.py b/bot/exts/moderation/voice_gate.py index 4e0334078..4244cce03 100644 --- a/bot/exts/moderation/voice_gate.py +++ b/bot/exts/moderation/voice_gate.py @@ -1,18 +1,15 @@ -import asyncio -from contextlib import suppress from datetime import timedelta import arrow import discord from async_rediscache import RedisCache -from discord import Colour, Member, VoiceState -from discord.ext.commands import Cog, Context, command +from discord import Colour, Member, TextChannel, VoiceState +from discord.ext.commands import Cog, Context, command, has_any_role from pydis_core.site_api import ResponseCodeError +from pydis_core.utils.channel import get_or_fetch_channel from bot.bot import Bot -from bot.constants import Bot as BotConfig, Channels, MODERATION_ROLES, Roles, VoiceGate as GateConf -from bot.decorators import has_no_roles, in_whitelist -from bot.exts.moderation.modlog import ModLog +from bot.constants import Channels, MODERATION_ROLES, Roles, VoiceGate as GateConf from bot.log import get_logger from bot.utils.checks import InWhitelistCheckFailure @@ -37,137 +34,63 @@ MESSAGE_FIELD_MAP = { VOICE_PING = ( "Wondering why you can't talk in the voice channels? " - f"Use the `{BotConfig.prefix}voiceverify` command in here to verify. " + "Click the Voice Verify button above to verify. " "If you don't yet qualify, you'll be told why!" ) -VOICE_PING_DM = ( - "Wondering why you can't talk in the voice channels? " - f"Use the `{BotConfig.prefix}voiceverify` command in " - "{channel_mention} to verify. If you don't yet qualify, you'll be told why!" -) - -class VoiceGate(Cog): - """Voice channels verification management.""" - - # RedisCache[discord.User.id | discord.Member.id, discord.Message.id | int] - # The cache's keys are the IDs of members who are verified or have joined a voice channel - # The cache's values are either the message ID of the ping message or 0 (NO_MSG) if no message is present - redis_cache = RedisCache() +class VoiceVerificationView(discord.ui.View): + """Persistent view to add a Voice Verify button.""" def __init__(self, bot: Bot) -> None: + super().__init__(timeout=None) self.bot = bot - @property - def mod_log(self) -> ModLog: - """Get the currently loaded ModLog cog instance.""" - return self.bot.get_cog("ModLog") - - @redis_cache.atomic_transaction # Fully process each call until starting the next - async def _delete_ping(self, member_id: int) -> None: - """ - If `redis_cache` holds a message ID for `member_id`, delete the message. - - If the message was deleted, the value under the `member_id` key is then set to `NO_MSG`. - When `member_id` is not in the cache, or has a value of `NO_MSG` already, this function - does nothing. - """ - if message_id := await self.redis_cache.get(member_id): - log.trace(f"Removing voice gate reminder message for user: {member_id}") - with suppress(discord.NotFound): - await self.bot.http.delete_message(Channels.voice_gate, message_id) - await self.redis_cache.set(member_id, NO_MSG) - else: - log.trace(f"Voice gate reminder message for user {member_id} was already removed") - - @redis_cache.atomic_transaction - async def _ping_newcomer(self, member: discord.Member) -> tuple: - """ - See if `member` should be sent a voice verification notification, and send it if so. - - Returns (False, None) if the notification was not sent. This happens when: - * The `member` has already received the notification - * The `member` is already voice-verified - - Otherwise, the notification message ID is stored in `redis_cache` and return (True, channel). - channel is either [discord.TextChannel, discord.DMChannel]. - """ - if await self.redis_cache.contains(member.id): - log.trace("User already in cache. Ignore.") - return False, None - - log.trace("User not in cache and is in a voice channel.") - verified = any(Roles.voice_verified == role.id for role in member.roles) - if verified: - log.trace("User is verified, add to the cache and ignore.") - await self.redis_cache.set(member.id, NO_MSG) - return False, None - - log.trace("User is unverified. Send ping.") - - await self.bot.wait_until_guild_available() - voice_verification_channel = self.bot.get_channel(Channels.voice_gate) - - try: - message = await member.send(VOICE_PING_DM.format(channel_mention=voice_verification_channel.mention)) - except discord.Forbidden: - log.trace("DM failed for Voice ping message. Sending in channel.") - message = await voice_verification_channel.send(f"Hello, {member.mention}! {VOICE_PING}") - - await self.redis_cache.set(member.id, message.id) - return True, message.channel - - @command(aliases=("voiceverify", "voice-verify",)) - @has_no_roles(Roles.voice_verified) - @in_whitelist(channels=(Channels.voice_gate,), redirect=None) - async def voice_verify(self, ctx: Context, *_) -> None: - """ - Apply to be able to use voice within the Discord server. - - In order to use voice you must meet all three of the following criteria: - - You must have over a certain number of messages within the Discord server - - You must have accepted our rules over a certain number of days ago - - You must not be actively banned from using our voice channels - - You must have been active for over a certain number of 10-minute blocks - """ - await self._delete_ping(ctx.author.id) # If user has received a ping in voice_verification, delete the message + @discord.ui.button(label="Voice Verify", style=discord.ButtonStyle.primary, custom_id="voice_verify_button",) + async def voice_button(self, interaction: discord.Interaction, button: discord.ui.Button) -> None: + """A button that checks to see if the user qualifies for voice verification and verifies them if they do.""" + if interaction.user.get_role(Roles.voice_verified): + await interaction.response.send_message(( + "You have already verified! " + "If you have received this message in error, " + "please send a message to the ModMail bot."), + ephemeral=True, + delete_after=GateConf.delete_after_delay, + ) + return try: - data = await self.bot.api_client.get(f"bot/users/{ctx.author.id}/metricity_data") - except ResponseCodeError as e: - if e.status == 404: - embed = discord.Embed( - title="Not found", - description=( - "We were unable to find user data for you. " - "Please try again shortly, " - "if this problem persists please contact the server staff through Modmail." - ), - color=Colour.red() + data = await self.bot.api_client.get( + f"bot/users/{interaction.user.id}/metricity_data", + raise_for_status=True + ) + except ResponseCodeError as err: + if err.response.status == 404: + await interaction.response.send_message(( + "We were unable to find user data for you. " + "Please try again shortly. " + "If this problem persists, please contact the server staff through ModMail."), + ephemeral=True, + delete_after=GateConf.delete_after_delay, ) - log.info(f"Unable to find Metricity data about {ctx.author} ({ctx.author.id})") + log.info("Unable to find Metricity data about %s (%s)", interaction.user, interaction.user.id) else: - embed = discord.Embed( - title="Unexpected response", - description=( - "We encountered an error while attempting to find data for your user. " - "Please try again and let us know if the problem persists." - ), - color=Colour.red() + await interaction.response.send_message(( + "We encountered an error while attempting to find data for your user. " + "Please try again and let us know if the problem persists."), + ephemeral=True, + delete_after=GateConf.delete_after_delay, + ) + log.warning( + "Got response code %s while trying to get %s Metricity data.", + err.status, + interaction.user.id ) - log.warning(f"Got response code {e.status} while trying to get {ctx.author.id} Metricity data.") - try: - await ctx.author.send(embed=embed) - except discord.Forbidden: - log.info("Could not send user DM. Sending in voice-verify channel and scheduling delete.") - await ctx.send(embed=embed) - return checks = { "joined_at": ( - ctx.author.joined_at > arrow.utcnow() - timedelta(days=GateConf.minimum_days_member) + interaction.user.joined_at > arrow.utcnow() - timedelta(days=GateConf.minimum_days_member) ), "total_messages": data["total_messages"] < GateConf.minimum_messages, "voice_gate_blocked": data["voice_gate_blocked"], @@ -175,102 +98,121 @@ class VoiceGate(Cog): } failed = any(checks.values()) - failed_reasons = [MESSAGE_FIELD_MAP[key] for key, value in checks.items() if value is True] - [self.bot.stats.incr(f"voice_gate.failed.{key}") for key, value in checks.items() if value is True] if failed: + failed_reasons = [] + for key, value in checks.items(): + if value is True: + failed_reasons.append(MESSAGE_FIELD_MAP[key]) + self.bot.stats.incr(f"voice_gate.failed.{key}") + embed = discord.Embed( title="Voice Gate failed", description=FAILED_MESSAGE.format(reasons="\n".join(f"- You {reason}." for reason in failed_reasons)), color=Colour.red() ) - try: - await ctx.author.send(embed=embed) - await ctx.send(f"{ctx.author}, please check your DMs.") - except discord.Forbidden: - await ctx.channel.send(ctx.author.mention, embed=embed) + + await interaction.response.send_message( + embed=embed, + ephemeral=True, + delete_after=GateConf.delete_after_delay, + ) return embed = discord.Embed( title="Voice gate passed", description="You have been granted permission to use voice channels in Python Discord.", - color=Colour.green() + color=Colour.green(), ) - if ctx.author.voice: + # interaction.user.voice will return None if the user is not in a voice channel + if interaction.user.voice: embed.description += "\n\nPlease reconnect to your voice channel to be granted your new permissions." - try: - await ctx.author.send(embed=embed) - await ctx.send(f"{ctx.author}, please check your DMs.") - except discord.Forbidden: - await ctx.channel.send(ctx.author.mention, embed=embed) + await interaction.response.send_message( + embed=embed, + ephemeral=True, + delete_after=GateConf.delete_after_delay, + ) + await interaction.user.add_roles(discord.Object(Roles.voice_verified), reason="Voice Gate passed") + self.bot.stats.incr("voice_gate.passed") - # wait a little bit so those who don't get DMs see the response in-channel before losing perms to see it. - await asyncio.sleep(3) - await ctx.author.add_roles(discord.Object(Roles.voice_verified), reason="Voice Gate passed") - self.bot.stats.incr("voice_gate.passed") +class VoiceGate(Cog): + """Voice channels verification management.""" - @Cog.listener() - async def on_message(self, message: discord.Message) -> None: - """Delete all non-staff messages from voice gate channel that don't invoke voice verify command.""" - # Check is channel voice gate - if message.channel.id != Channels.voice_gate: - return + # RedisCache[discord.User.id | discord.Member.id, discord.Message.id | int] + # The cache's keys are the IDs of members who are verified or have joined a voice channel + # The cache's values are set to 0, as we only need to track which users have connected before + redis_cache = RedisCache() - ctx = await self.bot.get_context(message) - is_verify_command = ctx.command is not None and ctx.command.name == "voice_verify" - - # When it's a bot sent message, delete it after some time - if message.author.bot: - # Comparing the message with the voice ping constant - if message.content.endswith(VOICE_PING): - log.trace("Message is the voice verification ping. Ignore.") - return - with suppress(discord.NotFound): - await message.delete(delay=GateConf.bot_message_delete_delay) - return - - # Then check is member moderator+, because we don't want to delete their messages. - if any(role.id in MODERATION_ROLES for role in message.author.roles) and is_verify_command is False: - log.trace(f"Excluding moderator message {message.id} from deletion in #{message.channel}.") + def __init__(self, bot: Bot) -> None: + self.bot = bot + + async def cog_load(self) -> None: + """Adds verify button to be monitored by the bot.""" + self.bot.add_view(VoiceVerificationView(self.bot)) + + @redis_cache.atomic_transaction + async def _ping_newcomer(self, member: discord.Member) -> None: + """See if `member` should be sent a voice verification notification, and send it if so.""" + log.trace("User is not verified. Checking cache.") + if await self.redis_cache.contains(member.id): + log.trace("User %s already in cache. Ignore.", member.id) return - with suppress(discord.NotFound): - await message.delete() + log.trace("User %s is unverified and has not been pinged before. Sending ping.", member.id) + await self.bot.wait_until_guild_available() + voice_verification_channel = await get_or_fetch_channel(self.bot, Channels.voice_gate) + + await voice_verification_channel.send( + f"Hello, {member.mention}! {VOICE_PING}", + delete_after=GateConf.delete_after_delay, + ) + + await self.redis_cache.set(member.id, NO_MSG) + log.trace("User %s added to cache to not be pinged again.", member.id) @Cog.listener() async def on_voice_state_update(self, member: Member, before: VoiceState, after: VoiceState) -> None: """Pings a user if they've never joined the voice chat before and aren't voice verified.""" if member.bot: - log.trace("User is a bot. Ignore.") + log.trace("User %s is a bot. Ignore.", member.id) + return + + if member.get_role(Roles.voice_verified): + log.trace("User %s already verified. Ignore", member.id) return # member.voice will return None if the user is not in a voice channel if member.voice is None: - log.trace("User not in a voice channel. Ignore.") + log.trace("User %s not in a voice channel. Ignore.", member.id) return if isinstance(after.channel, discord.StageChannel): - log.trace("User joined a stage channel. Ignore.") + log.trace("User %s joined a stage channel. Ignore.", member.id) return # To avoid race conditions, checking if the user should receive a notification # and sending it if appropriate is delegated to an atomic helper - notification_sent, message_channel = await self._ping_newcomer(member) - - # Schedule the channel ping notification to be deleted after the configured delay, which is - # again delegated to an atomic helper - if notification_sent and isinstance(message_channel, discord.TextChannel): - await asyncio.sleep(GateConf.voice_ping_delete_delay) - await self._delete_ping(member.id) + await self._ping_newcomer(member) async def cog_command_error(self, ctx: Context, error: Exception) -> None: """Check for & ignore any InWhitelistCheckFailure.""" if isinstance(error, InWhitelistCheckFailure): error.handled = True + @command(name="prepare_voice") + @has_any_role(*MODERATION_ROLES) + async def prepare_voice_button(self, ctx: Context, channel: TextChannel | None, *, text: str) -> None: + """Sends a message that includes the Voice Verify button. Should only need to be run once.""" + if channel is None: + await ctx.send(text, view=VoiceVerificationView(self.bot)) + elif not channel.permissions_for(ctx.author).send_messages: + await ctx.send("You don't have permission to send messages to that channel.") + else: + await channel.send(text, view=VoiceVerificationView(self.bot)) + async def setup(bot: Bot) -> None: """Loads the VoiceGate cog.""" diff --git a/bot/exts/moderation/watchchannels/_watchchannel.py b/bot/exts/moderation/watchchannels/_watchchannel.py index d0fc0de44..71600e9df 100644 --- a/bot/exts/moderation/watchchannels/_watchchannel.py +++ b/bot/exts/moderation/watchchannels/_watchchannel.py @@ -19,10 +19,10 @@ from bot.bot import Bot from bot.constants import BigBrother as BigBrotherConfig, Guild as GuildConfig, Icons from bot.exts.filtering._filters.unique.discord_token import DiscordTokenFilter from bot.exts.filtering._filters.unique.webhook import WEBHOOK_URL_RE -from bot.exts.moderation.modlog import ModLog from bot.log import get_logger from bot.pagination import LinePaginator from bot.utils import CogABCMeta, messages, time +from bot.utils.modlog import send_log_message log = get_logger(__name__) @@ -73,11 +73,6 @@ class WatchChannel(metaclass=CogABCMeta): self.disable_header = disable_header @property - def modlog(self) -> ModLog: - """Provides access to the ModLog cog for alert purposes.""" - return self.bot.get_cog("ModLog") - - @property def consuming_messages(self) -> bool: """Checks if a consumption task is currently running.""" if self._consume_task is None: @@ -122,7 +117,8 @@ class WatchChannel(metaclass=CogABCMeta): """ ) - await self.modlog.send_log_message( + await send_log_message( + self.bot, title=f"Error: Failed to initialize the {self.__class__.__name__} watch channel", text=message, ping_everyone=True, @@ -134,7 +130,8 @@ class WatchChannel(metaclass=CogABCMeta): return if not await self.fetch_user_cache(): - await self.modlog.send_log_message( + await send_log_message( + self.bot, title=f"Warning: Failed to retrieve user cache for the {self.__class__.__name__} watch channel", text=( "Could not retrieve the list of watched users from the API. " diff --git a/bot/resources/tags/codeblock.md b/bot/resources/tags/codeblock.md index c2b77637e..c7f2990fd 100644 --- a/bot/resources/tags/codeblock.md +++ b/bot/resources/tags/codeblock.md @@ -1,6 +1,6 @@ --- embed: - title: "Formatting code on discord" + title: "Formatting code on Discord" --- Here's how to format Python code on Discord: diff --git a/bot/resources/tags/equals-true.md b/bot/resources/tags/equals-true.md new file mode 100644 index 000000000..d8e1a707e --- /dev/null +++ b/bot/resources/tags/equals-true.md @@ -0,0 +1,24 @@ +--- +embed: + title: "Comparisons to `True` and `False`" +--- +It's tempting to think that if statements always need a comparison operator like `==` or `!=`, but this isn't true. +If you're just checking if a value is truthy or falsey, you don't need `== True` or `== False`. +```py +# instead of this... +if user_input.startswith('y') == True: + my_func(user_input) + +# ...write this +if user_input.startswith('y'): + my_func(user_input) + +# for false conditions, instead of this... +if user_input.startswith('y') == False: + my_func(user_input) + +# ...just use `not` +if not user_input.startswith('y'): + my_func(user_input) +``` +This also applies to expressions that use `is True` or `is False`. diff --git a/bot/resources/tags/range-len.md b/bot/resources/tags/range-len.md index 4bd377d59..76fe9051e 100644 --- a/bot/resources/tags/range-len.md +++ b/bot/resources/tags/range-len.md @@ -2,12 +2,12 @@ embed: title: "Pythonic way of iterating over ordered collections" --- -Iterating over `range(len(...))` is a common approach to accessing each item in an ordered collection. +Beginners often iterate over `range(len(...))` because they look like Java or C-style loops, but this is almost always a bad practice in Python. ```py for i in range(len(my_list)): do_something(my_list[i]) ``` -The pythonic syntax is much simpler, and is guaranteed to produce elements in the same order: +It's much simpler to iterate over the list (or other sequence) directly: ```py for item in my_list: do_something(item) diff --git a/bot/utils/modlog.py b/bot/utils/modlog.py new file mode 100644 index 000000000..6a432e65e --- /dev/null +++ b/bot/utils/modlog.py @@ -0,0 +1,69 @@ +from datetime import UTC, datetime + +import discord + +from bot.bot import Bot +from bot.constants import Channels, Roles + + +async def send_log_message( + bot: Bot, + icon_url: str | None, + colour: discord.Colour | int, + title: str | None, + text: str, + *, + thumbnail: str | discord.Asset | None = None, + channel_id: int = Channels.mod_log, + ping_everyone: bool = False, + files: list[discord.File] | None = None, + content: str | None = None, + additional_embeds: list[discord.Embed] | None = None, + timestamp_override: datetime | None = None, + footer: str | None = None, +) -> discord.Message: + """Generate log embed and send to logging channel.""" + await bot.wait_until_guild_available() + # Truncate string directly here to avoid removing newlines + embed = discord.Embed( + description=text[:4093] + "..." if len(text) > 4096 else text + ) + + if title and icon_url: + embed.set_author(name=title, icon_url=icon_url) + elif title: + raise ValueError("title cannot be set without icon_url") + elif icon_url: + raise ValueError("icon_url cannot be set without title") + + embed.colour = colour + embed.timestamp = timestamp_override or datetime.now(tz=UTC) + + if footer: + embed.set_footer(text=footer) + + if thumbnail: + embed.set_thumbnail(url=thumbnail) + + if ping_everyone: + if content: + content = f"<@&{Roles.moderators}> {content}" + else: + content = f"<@&{Roles.moderators}>" + + # Truncate content to 2000 characters and append an ellipsis. + if content and len(content) > 2000: + content = content[:2000 - 3] + "..." + + channel = bot.get_channel(channel_id) + log_message = await channel.send( + content=content, + embed=embed, + files=files + ) + + if additional_embeds: + for additional_embed in additional_embeds: + await channel.send(embed=additional_embed) + + return log_message diff --git a/poetry.lock b/poetry.lock index 202809489..a20fc303f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -136,13 +136,13 @@ files = [ [[package]] name = "anyio" -version = "4.1.0" +version = "4.2.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.8" files = [ - {file = "anyio-4.1.0-py3-none-any.whl", hash = "sha256:56a415fbc462291813a94528a779597226619c8e78af7de0507333f700011e5f"}, - {file = "anyio-4.1.0.tar.gz", hash = "sha256:5a0bec7085176715be77df87fc66d6c9d70626bd752fcc85f57cdbee5b3760da"}, + {file = "anyio-4.2.0-py3-none-any.whl", hash = "sha256:745843b39e829e108e518c489b31dc757de7d2131d53fac32bd8df268227bfee"}, + {file = "anyio-4.2.0.tar.gz", hash = "sha256:e1875bb4b4e2de1669f4bc7869b6d3f54231cdced71605e6e64c9be77e3be50f"}, ] [package.dependencies] @@ -204,37 +204,41 @@ files = [ [[package]] name = "attrs" -version = "23.1.0" +version = "23.2.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.7" files = [ - {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, - {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, + {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, + {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, ] [package.extras] cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] -dev = ["attrs[docs,tests]", "pre-commit"] +dev = ["attrs[tests]", "pre-commit"] docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] tests = ["attrs[tests-no-zope]", "zope-interface"] -tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] +tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] [[package]] name = "beautifulsoup4" -version = "4.12.2" +version = "4.12.3" description = "Screen-scraping library" optional = false python-versions = ">=3.6.0" files = [ - {file = "beautifulsoup4-4.12.2-py3-none-any.whl", hash = "sha256:bd2520ca0d9d7d12694a53d44ac482d181b4ec1888909b035a3dbf40d0f57d4a"}, - {file = "beautifulsoup4-4.12.2.tar.gz", hash = "sha256:492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da"}, + {file = "beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed"}, + {file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"}, ] [package.dependencies] soupsieve = ">1.2" [package.extras] +cchardet = ["cchardet"] +chardet = ["chardet"] +charset-normalizer = ["charset-normalizer"] html5lib = ["html5lib"] lxml = ["lxml"] @@ -569,13 +573,13 @@ files = [ [[package]] name = "emoji" -version = "2.9.0" +version = "2.10.0" description = "Emoji for Python" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ - {file = "emoji-2.9.0-py2.py3-none-any.whl", hash = "sha256:17b0d53e1d9f787307a4c65aa19badb0a1ffdbc89b3a3cd851fc77821cdaced2"}, - {file = "emoji-2.9.0.tar.gz", hash = "sha256:5f4a15b7caa9c67fc11be9d90a822e3fa26aeb4e5b7bd2ded754b394d9c47869"}, + {file = "emoji-2.10.0-py2.py3-none-any.whl", hash = "sha256:aed4332caa23553a7218f032c08b0a325ae53b010f7fb98ad272c0f7841bc1d3"}, + {file = "emoji-2.10.0.tar.gz", hash = "sha256:7e68435eecd2c428c3b4aaa5f72d61a5b1a36c81a5138681cba13d19d94aa3a0"}, ] [package.extras] @@ -930,111 +934,96 @@ files = [ [[package]] name = "lxml" -version = "4.9.4" +version = "5.1.0" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" -files = [ - {file = "lxml-4.9.4-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e214025e23db238805a600f1f37bf9f9a15413c7bf5f9d6ae194f84980c78722"}, - {file = "lxml-4.9.4-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ec53a09aee61d45e7dbe7e91252ff0491b6b5fee3d85b2d45b173d8ab453efc1"}, - {file = "lxml-4.9.4-cp27-cp27m-win32.whl", hash = "sha256:7d1d6c9e74c70ddf524e3c09d9dc0522aba9370708c2cb58680ea40174800013"}, - {file = "lxml-4.9.4-cp27-cp27m-win_amd64.whl", hash = "sha256:cb53669442895763e61df5c995f0e8361b61662f26c1b04ee82899c2789c8f69"}, - {file = "lxml-4.9.4-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:647bfe88b1997d7ae8d45dabc7c868d8cb0c8412a6e730a7651050b8c7289cf2"}, - {file = "lxml-4.9.4-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:4d973729ce04784906a19108054e1fd476bc85279a403ea1a72fdb051c76fa48"}, - {file = "lxml-4.9.4-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:056a17eaaf3da87a05523472ae84246f87ac2f29a53306466c22e60282e54ff8"}, - {file = "lxml-4.9.4-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:aaa5c173a26960fe67daa69aa93d6d6a1cd714a6eb13802d4e4bd1d24a530644"}, - {file = "lxml-4.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:647459b23594f370c1c01768edaa0ba0959afc39caeeb793b43158bb9bb6a663"}, - {file = "lxml-4.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:bdd9abccd0927673cffe601d2c6cdad1c9321bf3437a2f507d6b037ef91ea307"}, - {file = "lxml-4.9.4-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:00e91573183ad273e242db5585b52670eddf92bacad095ce25c1e682da14ed91"}, - {file = "lxml-4.9.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a602ed9bd2c7d85bd58592c28e101bd9ff9c718fbde06545a70945ffd5d11868"}, - {file = "lxml-4.9.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:de362ac8bc962408ad8fae28f3967ce1a262b5d63ab8cefb42662566737f1dc7"}, - {file = "lxml-4.9.4-cp310-cp310-win32.whl", hash = "sha256:33714fcf5af4ff7e70a49731a7cc8fd9ce910b9ac194f66eaa18c3cc0a4c02be"}, - {file = "lxml-4.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:d3caa09e613ece43ac292fbed513a4bce170681a447d25ffcbc1b647d45a39c5"}, - {file = "lxml-4.9.4-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:359a8b09d712df27849e0bcb62c6a3404e780b274b0b7e4c39a88826d1926c28"}, - {file = "lxml-4.9.4-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:43498ea734ccdfb92e1886dfedaebeb81178a241d39a79d5351ba2b671bff2b2"}, - {file = "lxml-4.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:4855161013dfb2b762e02b3f4d4a21cc7c6aec13c69e3bffbf5022b3e708dd97"}, - {file = "lxml-4.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:c71b5b860c5215fdbaa56f715bc218e45a98477f816b46cfde4a84d25b13274e"}, - {file = "lxml-4.9.4-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:9a2b5915c333e4364367140443b59f09feae42184459b913f0f41b9fed55794a"}, - {file = "lxml-4.9.4-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d82411dbf4d3127b6cde7da0f9373e37ad3a43e89ef374965465928f01c2b979"}, - {file = "lxml-4.9.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:273473d34462ae6e97c0f4e517bd1bf9588aa67a1d47d93f760a1282640e24ac"}, - {file = "lxml-4.9.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:389d2b2e543b27962990ab529ac6720c3dded588cc6d0f6557eec153305a3622"}, - {file = "lxml-4.9.4-cp311-cp311-win32.whl", hash = "sha256:8aecb5a7f6f7f8fe9cac0bcadd39efaca8bbf8d1bf242e9f175cbe4c925116c3"}, - {file = "lxml-4.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:c7721a3ef41591341388bb2265395ce522aba52f969d33dacd822da8f018aff8"}, - {file = "lxml-4.9.4-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:dbcb2dc07308453db428a95a4d03259bd8caea97d7f0776842299f2d00c72fc8"}, - {file = "lxml-4.9.4-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:01bf1df1db327e748dcb152d17389cf6d0a8c5d533ef9bab781e9d5037619229"}, - {file = "lxml-4.9.4-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:e8f9f93a23634cfafbad6e46ad7d09e0f4a25a2400e4a64b1b7b7c0fbaa06d9d"}, - {file = "lxml-4.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3f3f00a9061605725df1816f5713d10cd94636347ed651abdbc75828df302b20"}, - {file = "lxml-4.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:953dd5481bd6252bd480d6ec431f61d7d87fdcbbb71b0d2bdcfc6ae00bb6fb10"}, - {file = "lxml-4.9.4-cp312-cp312-win32.whl", hash = "sha256:266f655d1baff9c47b52f529b5f6bec33f66042f65f7c56adde3fcf2ed62ae8b"}, - {file = "lxml-4.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:f1faee2a831fe249e1bae9cbc68d3cd8a30f7e37851deee4d7962b17c410dd56"}, - {file = "lxml-4.9.4-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:23d891e5bdc12e2e506e7d225d6aa929e0a0368c9916c1fddefab88166e98b20"}, - {file = "lxml-4.9.4-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e96a1788f24d03e8d61679f9881a883ecdf9c445a38f9ae3f3f193ab6c591c66"}, - {file = "lxml-4.9.4-cp36-cp36m-macosx_11_0_x86_64.whl", hash = "sha256:5557461f83bb7cc718bc9ee1f7156d50e31747e5b38d79cf40f79ab1447afd2d"}, - {file = "lxml-4.9.4-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:fdb325b7fba1e2c40b9b1db407f85642e32404131c08480dd652110fc908561b"}, - {file = "lxml-4.9.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d74d4a3c4b8f7a1f676cedf8e84bcc57705a6d7925e6daef7a1e54ae543a197"}, - {file = "lxml-4.9.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:ac7674d1638df129d9cb4503d20ffc3922bd463c865ef3cb412f2c926108e9a4"}, - {file = "lxml-4.9.4-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:ddd92e18b783aeb86ad2132d84a4b795fc5ec612e3545c1b687e7747e66e2b53"}, - {file = "lxml-4.9.4-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2bd9ac6e44f2db368ef8986f3989a4cad3de4cd55dbdda536e253000c801bcc7"}, - {file = "lxml-4.9.4-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:bc354b1393dce46026ab13075f77b30e40b61b1a53e852e99d3cc5dd1af4bc85"}, - {file = "lxml-4.9.4-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:f836f39678cb47c9541f04d8ed4545719dc31ad850bf1832d6b4171e30d65d23"}, - {file = "lxml-4.9.4-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:9c131447768ed7bc05a02553d939e7f0e807e533441901dd504e217b76307745"}, - {file = "lxml-4.9.4-cp36-cp36m-win32.whl", hash = "sha256:bafa65e3acae612a7799ada439bd202403414ebe23f52e5b17f6ffc2eb98c2be"}, - {file = "lxml-4.9.4-cp36-cp36m-win_amd64.whl", hash = "sha256:6197c3f3c0b960ad033b9b7d611db11285bb461fc6b802c1dd50d04ad715c225"}, - {file = "lxml-4.9.4-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:7b378847a09d6bd46047f5f3599cdc64fcb4cc5a5a2dd0a2af610361fbe77b16"}, - {file = "lxml-4.9.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:1343df4e2e6e51182aad12162b23b0a4b3fd77f17527a78c53f0f23573663545"}, - {file = "lxml-4.9.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:6dbdacf5752fbd78ccdb434698230c4f0f95df7dd956d5f205b5ed6911a1367c"}, - {file = "lxml-4.9.4-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:506becdf2ecaebaf7f7995f776394fcc8bd8a78022772de66677c84fb02dd33d"}, - {file = "lxml-4.9.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ca8e44b5ba3edb682ea4e6185b49661fc22b230cf811b9c13963c9f982d1d964"}, - {file = "lxml-4.9.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9d9d5726474cbbef279fd709008f91a49c4f758bec9c062dfbba88eab00e3ff9"}, - {file = "lxml-4.9.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:bbdd69e20fe2943b51e2841fc1e6a3c1de460d630f65bde12452d8c97209464d"}, - {file = "lxml-4.9.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8671622256a0859f5089cbe0ce4693c2af407bc053dcc99aadff7f5310b4aa02"}, - {file = "lxml-4.9.4-cp37-cp37m-win32.whl", hash = "sha256:dd4fda67f5faaef4f9ee5383435048ee3e11ad996901225ad7615bc92245bc8e"}, - {file = "lxml-4.9.4-cp37-cp37m-win_amd64.whl", hash = "sha256:6bee9c2e501d835f91460b2c904bc359f8433e96799f5c2ff20feebd9bb1e590"}, - {file = "lxml-4.9.4-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:1f10f250430a4caf84115b1e0f23f3615566ca2369d1962f82bef40dd99cd81a"}, - {file = "lxml-4.9.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:3b505f2bbff50d261176e67be24e8909e54b5d9d08b12d4946344066d66b3e43"}, - {file = "lxml-4.9.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:1449f9451cd53e0fd0a7ec2ff5ede4686add13ac7a7bfa6988ff6d75cff3ebe2"}, - {file = "lxml-4.9.4-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:4ece9cca4cd1c8ba889bfa67eae7f21d0d1a2e715b4d5045395113361e8c533d"}, - {file = "lxml-4.9.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:59bb5979f9941c61e907ee571732219fa4774d5a18f3fa5ff2df963f5dfaa6bc"}, - {file = "lxml-4.9.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b1980dbcaad634fe78e710c8587383e6e3f61dbe146bcbfd13a9c8ab2d7b1192"}, - {file = "lxml-4.9.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9ae6c3363261021144121427b1552b29e7b59de9d6a75bf51e03bc072efb3c37"}, - {file = "lxml-4.9.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bcee502c649fa6351b44bb014b98c09cb00982a475a1912a9881ca28ab4f9cd9"}, - {file = "lxml-4.9.4-cp38-cp38-win32.whl", hash = "sha256:a8edae5253efa75c2fc79a90068fe540b197d1c7ab5803b800fccfe240eed33c"}, - {file = "lxml-4.9.4-cp38-cp38-win_amd64.whl", hash = "sha256:701847a7aaefef121c5c0d855b2affa5f9bd45196ef00266724a80e439220e46"}, - {file = "lxml-4.9.4-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:f610d980e3fccf4394ab3806de6065682982f3d27c12d4ce3ee46a8183d64a6a"}, - {file = "lxml-4.9.4-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:aa9b5abd07f71b081a33115d9758ef6077924082055005808f68feccb27616bd"}, - {file = "lxml-4.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:365005e8b0718ea6d64b374423e870648ab47c3a905356ab6e5a5ff03962b9a9"}, - {file = "lxml-4.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:16b9ec51cc2feab009e800f2c6327338d6ee4e752c76e95a35c4465e80390ccd"}, - {file = "lxml-4.9.4-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:a905affe76f1802edcac554e3ccf68188bea16546071d7583fb1b693f9cf756b"}, - {file = "lxml-4.9.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fd814847901df6e8de13ce69b84c31fc9b3fb591224d6762d0b256d510cbf382"}, - {file = "lxml-4.9.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:91bbf398ac8bb7d65a5a52127407c05f75a18d7015a270fdd94bbcb04e65d573"}, - {file = "lxml-4.9.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f99768232f036b4776ce419d3244a04fe83784bce871b16d2c2e984c7fcea847"}, - {file = "lxml-4.9.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bb5bd6212eb0edfd1e8f254585290ea1dadc3687dd8fd5e2fd9a87c31915cdab"}, - {file = "lxml-4.9.4-cp39-cp39-win32.whl", hash = "sha256:88f7c383071981c74ec1998ba9b437659e4fd02a3c4a4d3efc16774eb108d0ec"}, - {file = "lxml-4.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:936e8880cc00f839aa4173f94466a8406a96ddce814651075f95837316369899"}, - {file = "lxml-4.9.4-pp310-pypy310_pp73-macosx_11_0_x86_64.whl", hash = "sha256:f6c35b2f87c004270fa2e703b872fcc984d714d430b305145c39d53074e1ffe0"}, - {file = "lxml-4.9.4-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:606d445feeb0856c2b424405236a01c71af7c97e5fe42fbc778634faef2b47e4"}, - {file = "lxml-4.9.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a1bdcbebd4e13446a14de4dd1825f1e778e099f17f79718b4aeaf2403624b0f7"}, - {file = "lxml-4.9.4-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:0a08c89b23117049ba171bf51d2f9c5f3abf507d65d016d6e0fa2f37e18c0fc5"}, - {file = "lxml-4.9.4-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:232fd30903d3123be4c435fb5159938c6225ee8607b635a4d3fca847003134ba"}, - {file = "lxml-4.9.4-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:231142459d32779b209aa4b4d460b175cadd604fed856f25c1571a9d78114771"}, - {file = "lxml-4.9.4-pp38-pypy38_pp73-macosx_11_0_x86_64.whl", hash = "sha256:520486f27f1d4ce9654154b4494cf9307b495527f3a2908ad4cb48e4f7ed7ef7"}, - {file = "lxml-4.9.4-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:562778586949be7e0d7435fcb24aca4810913771f845d99145a6cee64d5b67ca"}, - {file = "lxml-4.9.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:a9e7c6d89c77bb2770c9491d988f26a4b161d05c8ca58f63fb1f1b6b9a74be45"}, - {file = "lxml-4.9.4-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:786d6b57026e7e04d184313c1359ac3d68002c33e4b1042ca58c362f1d09ff58"}, - {file = "lxml-4.9.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:95ae6c5a196e2f239150aa4a479967351df7f44800c93e5a975ec726fef005e2"}, - {file = "lxml-4.9.4-pp39-pypy39_pp73-macosx_11_0_x86_64.whl", hash = "sha256:9b556596c49fa1232b0fff4b0e69b9d4083a502e60e404b44341e2f8fb7187f5"}, - {file = "lxml-4.9.4-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:cc02c06e9e320869d7d1bd323df6dd4281e78ac2e7f8526835d3d48c69060683"}, - {file = "lxml-4.9.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:857d6565f9aa3464764c2cb6a2e3c2e75e1970e877c188f4aeae45954a314e0c"}, - {file = "lxml-4.9.4-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c42ae7e010d7d6bc51875d768110c10e8a59494855c3d4c348b068f5fb81fdcd"}, - {file = "lxml-4.9.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f10250bb190fb0742e3e1958dd5c100524c2cc5096c67c8da51233f7448dc137"}, - {file = "lxml-4.9.4.tar.gz", hash = "sha256:b1541e50b78e15fa06a2670157a1962ef06591d4c998b998047fff5e3236880e"}, +python-versions = ">=3.6" +files = [ + {file = "lxml-5.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:704f5572ff473a5f897745abebc6df40f22d4133c1e0a1f124e4f2bd3330ff7e"}, + {file = "lxml-5.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9d3c0f8567ffe7502d969c2c1b809892dc793b5d0665f602aad19895f8d508da"}, + {file = "lxml-5.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5fcfbebdb0c5d8d18b84118842f31965d59ee3e66996ac842e21f957eb76138c"}, + {file = "lxml-5.1.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2f37c6d7106a9d6f0708d4e164b707037b7380fcd0b04c5bd9cae1fb46a856fb"}, + {file = "lxml-5.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2befa20a13f1a75c751f47e00929fb3433d67eb9923c2c0b364de449121f447c"}, + {file = "lxml-5.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22b7ee4c35f374e2c20337a95502057964d7e35b996b1c667b5c65c567d2252a"}, + {file = "lxml-5.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bf8443781533b8d37b295016a4b53c1494fa9a03573c09ca5104550c138d5c05"}, + {file = "lxml-5.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:82bddf0e72cb2af3cbba7cec1d2fd11fda0de6be8f4492223d4a268713ef2147"}, + {file = "lxml-5.1.0-cp310-cp310-win32.whl", hash = "sha256:b66aa6357b265670bb574f050ffceefb98549c721cf28351b748be1ef9577d93"}, + {file = "lxml-5.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:4946e7f59b7b6a9e27bef34422f645e9a368cb2be11bf1ef3cafc39a1f6ba68d"}, + {file = "lxml-5.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:14deca1460b4b0f6b01f1ddc9557704e8b365f55c63070463f6c18619ebf964f"}, + {file = "lxml-5.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ed8c3d2cd329bf779b7ed38db176738f3f8be637bb395ce9629fc76f78afe3d4"}, + {file = "lxml-5.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:436a943c2900bb98123b06437cdd30580a61340fbdb7b28aaf345a459c19046a"}, + {file = "lxml-5.1.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:acb6b2f96f60f70e7f34efe0c3ea34ca63f19ca63ce90019c6cbca6b676e81fa"}, + {file = "lxml-5.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af8920ce4a55ff41167ddbc20077f5698c2e710ad3353d32a07d3264f3a2021e"}, + {file = "lxml-5.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cfced4a069003d8913408e10ca8ed092c49a7f6cefee9bb74b6b3e860683b45"}, + {file = "lxml-5.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9e5ac3437746189a9b4121db2a7b86056ac8786b12e88838696899328fc44bb2"}, + {file = "lxml-5.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f4c9bda132ad108b387c33fabfea47866af87f4ea6ffb79418004f0521e63204"}, + {file = "lxml-5.1.0-cp311-cp311-win32.whl", hash = "sha256:bc64d1b1dab08f679fb89c368f4c05693f58a9faf744c4d390d7ed1d8223869b"}, + {file = "lxml-5.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:a5ab722ae5a873d8dcee1f5f45ddd93c34210aed44ff2dc643b5025981908cda"}, + {file = "lxml-5.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9aa543980ab1fbf1720969af1d99095a548ea42e00361e727c58a40832439114"}, + {file = "lxml-5.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6f11b77ec0979f7e4dc5ae081325a2946f1fe424148d3945f943ceaede98adb8"}, + {file = "lxml-5.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a36c506e5f8aeb40680491d39ed94670487ce6614b9d27cabe45d94cd5d63e1e"}, + {file = "lxml-5.1.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f643ffd2669ffd4b5a3e9b41c909b72b2a1d5e4915da90a77e119b8d48ce867a"}, + {file = "lxml-5.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16dd953fb719f0ffc5bc067428fc9e88f599e15723a85618c45847c96f11f431"}, + {file = "lxml-5.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16018f7099245157564d7148165132c70adb272fb5a17c048ba70d9cc542a1a1"}, + {file = "lxml-5.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:82cd34f1081ae4ea2ede3d52f71b7be313756e99b4b5f829f89b12da552d3aa3"}, + {file = "lxml-5.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:19a1bc898ae9f06bccb7c3e1dfd73897ecbbd2c96afe9095a6026016e5ca97b8"}, + {file = "lxml-5.1.0-cp312-cp312-win32.whl", hash = "sha256:13521a321a25c641b9ea127ef478b580b5ec82aa2e9fc076c86169d161798b01"}, + {file = "lxml-5.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:1ad17c20e3666c035db502c78b86e58ff6b5991906e55bdbef94977700c72623"}, + {file = "lxml-5.1.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:24ef5a4631c0b6cceaf2dbca21687e29725b7c4e171f33a8f8ce23c12558ded1"}, + {file = "lxml-5.1.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8d2900b7f5318bc7ad8631d3d40190b95ef2aa8cc59473b73b294e4a55e9f30f"}, + {file = "lxml-5.1.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:601f4a75797d7a770daed8b42b97cd1bb1ba18bd51a9382077a6a247a12aa38d"}, + {file = "lxml-5.1.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4b68c961b5cc402cbd99cca5eb2547e46ce77260eb705f4d117fd9c3f932b95"}, + {file = "lxml-5.1.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:afd825e30f8d1f521713a5669b63657bcfe5980a916c95855060048b88e1adb7"}, + {file = "lxml-5.1.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:262bc5f512a66b527d026518507e78c2f9c2bd9eb5c8aeeb9f0eb43fcb69dc67"}, + {file = "lxml-5.1.0-cp36-cp36m-win32.whl", hash = "sha256:e856c1c7255c739434489ec9c8aa9cdf5179785d10ff20add308b5d673bed5cd"}, + {file = "lxml-5.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:c7257171bb8d4432fe9d6fdde4d55fdbe663a63636a17f7f9aaba9bcb3153ad7"}, + {file = "lxml-5.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b9e240ae0ba96477682aa87899d94ddec1cc7926f9df29b1dd57b39e797d5ab5"}, + {file = "lxml-5.1.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a96f02ba1bcd330807fc060ed91d1f7a20853da6dd449e5da4b09bfcc08fdcf5"}, + {file = "lxml-5.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e3898ae2b58eeafedfe99e542a17859017d72d7f6a63de0f04f99c2cb125936"}, + {file = "lxml-5.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61c5a7edbd7c695e54fca029ceb351fc45cd8860119a0f83e48be44e1c464862"}, + {file = "lxml-5.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:3aeca824b38ca78d9ee2ab82bd9883083d0492d9d17df065ba3b94e88e4d7ee6"}, + {file = "lxml-5.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8f52fe6859b9db71ee609b0c0a70fea5f1e71c3462ecf144ca800d3f434f0764"}, + {file = "lxml-5.1.0-cp37-cp37m-win32.whl", hash = "sha256:d42e3a3fc18acc88b838efded0e6ec3edf3e328a58c68fbd36a7263a874906c8"}, + {file = "lxml-5.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:eac68f96539b32fce2c9b47eb7c25bb2582bdaf1bbb360d25f564ee9e04c542b"}, + {file = "lxml-5.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ae15347a88cf8af0949a9872b57a320d2605ae069bcdf047677318bc0bba45b1"}, + {file = "lxml-5.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c26aab6ea9c54d3bed716b8851c8bfc40cb249b8e9880e250d1eddde9f709bf5"}, + {file = "lxml-5.1.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:342e95bddec3a698ac24378d61996b3ee5ba9acfeb253986002ac53c9a5f6f84"}, + {file = "lxml-5.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:725e171e0b99a66ec8605ac77fa12239dbe061482ac854d25720e2294652eeaa"}, + {file = "lxml-5.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d184e0d5c918cff04cdde9dbdf9600e960161d773666958c9d7b565ccc60c45"}, + {file = "lxml-5.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:98f3f020a2b736566c707c8e034945c02aa94e124c24f77ca097c446f81b01f1"}, + {file = "lxml-5.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6d48fc57e7c1e3df57be5ae8614bab6d4e7b60f65c5457915c26892c41afc59e"}, + {file = "lxml-5.1.0-cp38-cp38-win32.whl", hash = "sha256:7ec465e6549ed97e9f1e5ed51c657c9ede767bc1c11552f7f4d022c4df4a977a"}, + {file = "lxml-5.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:b21b4031b53d25b0858d4e124f2f9131ffc1530431c6d1321805c90da78388d1"}, + {file = "lxml-5.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:52427a7eadc98f9e62cb1368a5079ae826f94f05755d2d567d93ee1bc3ceb354"}, + {file = "lxml-5.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6a2a2c724d97c1eb8cf966b16ca2915566a4904b9aad2ed9a09c748ffe14f969"}, + {file = "lxml-5.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:843b9c835580d52828d8f69ea4302537337a21e6b4f1ec711a52241ba4a824f3"}, + {file = "lxml-5.1.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9b99f564659cfa704a2dd82d0684207b1aadf7d02d33e54845f9fc78e06b7581"}, + {file = "lxml-5.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f8b0c78e7aac24979ef09b7f50da871c2de2def043d468c4b41f512d831e912"}, + {file = "lxml-5.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9bcf86dfc8ff3e992fed847c077bd875d9e0ba2fa25d859c3a0f0f76f07f0c8d"}, + {file = "lxml-5.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:49a9b4af45e8b925e1cd6f3b15bbba2c81e7dba6dce170c677c9cda547411e14"}, + {file = "lxml-5.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:280f3edf15c2a967d923bcfb1f8f15337ad36f93525828b40a0f9d6c2ad24890"}, + {file = "lxml-5.1.0-cp39-cp39-win32.whl", hash = "sha256:ed7326563024b6e91fef6b6c7a1a2ff0a71b97793ac33dbbcf38f6005e51ff6e"}, + {file = "lxml-5.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:8d7b4beebb178e9183138f552238f7e6613162a42164233e2bda00cb3afac58f"}, + {file = "lxml-5.1.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9bd0ae7cc2b85320abd5e0abad5ccee5564ed5f0cc90245d2f9a8ef330a8deae"}, + {file = "lxml-5.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8c1d679df4361408b628f42b26a5d62bd3e9ba7f0c0e7969f925021554755aa"}, + {file = "lxml-5.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2ad3a8ce9e8a767131061a22cd28fdffa3cd2dc193f399ff7b81777f3520e372"}, + {file = "lxml-5.1.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:304128394c9c22b6569eba2a6d98392b56fbdfbad58f83ea702530be80d0f9df"}, + {file = "lxml-5.1.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d74fcaf87132ffc0447b3c685a9f862ffb5b43e70ea6beec2fb8057d5d2a1fea"}, + {file = "lxml-5.1.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:8cf5877f7ed384dabfdcc37922c3191bf27e55b498fecece9fd5c2c7aaa34c33"}, + {file = "lxml-5.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:877efb968c3d7eb2dad540b6cabf2f1d3c0fbf4b2d309a3c141f79c7e0061324"}, + {file = "lxml-5.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f14a4fb1c1c402a22e6a341a24c1341b4a3def81b41cd354386dcb795f83897"}, + {file = "lxml-5.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:25663d6e99659544ee8fe1b89b1a8c0aaa5e34b103fab124b17fa958c4a324a6"}, + {file = "lxml-5.1.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8b9f19df998761babaa7f09e6bc169294eefafd6149aaa272081cbddc7ba4ca3"}, + {file = "lxml-5.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e53d7e6a98b64fe54775d23a7c669763451340c3d44ad5e3a3b48a1efbdc96f"}, + {file = "lxml-5.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c3cd1fc1dc7c376c54440aeaaa0dcc803d2126732ff5c6b68ccd619f2e64be4f"}, + {file = "lxml-5.1.0.tar.gz", hash = "sha256:3eea6ed6e6c918e468e693c41ef07f3c3acc310b70ddd9cc72d9ef84bc9564ca"}, ] [package.extras] cssselect = ["cssselect (>=0.7)"] html5 = ["html5lib"] htmlsoup = ["BeautifulSoup4"] -source = ["Cython (==0.29.37)"] +source = ["Cython (>=3.0.7)"] [[package]] name = "markdownify" @@ -1053,13 +1042,13 @@ six = ">=1.15,<2" [[package]] name = "more-itertools" -version = "10.1.0" +version = "10.2.0" description = "More routines for operating on iterables, beyond itertools" optional = false python-versions = ">=3.8" files = [ - {file = "more-itertools-10.1.0.tar.gz", hash = "sha256:626c369fa0eb37bac0291bce8259b332fd59ac792fa5497b59837309cd5b114a"}, - {file = "more_itertools-10.1.0-py3-none-any.whl", hash = "sha256:64e0735fcfdc6f3464ea133afe8ea4483b1c5fe3a3d69852e6503b43a0b222e6"}, + {file = "more-itertools-10.2.0.tar.gz", hash = "sha256:8fccb480c43d3e99a00087634c06dd02b0d50fbf088b380de5a41a015ec239e1"}, + {file = "more_itertools-10.2.0-py3-none-any.whl", hash = "sha256:686b06abe565edfab151cb8fd385a05651e1fdf8f0a14191e4439283421f8684"}, ] [[package]] @@ -1197,13 +1186,13 @@ files = [ [[package]] name = "pip-licenses" -version = "4.3.3" +version = "4.3.4" description = "Dump the software license list of Python packages installed with pip." optional = false python-versions = "~=3.8" files = [ - {file = "pip-licenses-4.3.3.tar.gz", hash = "sha256:d14447094135eb5e43e4d9e1e3bcdb17a05751a9199df2d07f043a542c241c7a"}, - {file = "pip_licenses-4.3.3-py3-none-any.whl", hash = "sha256:1b697cace3149d7d380307bb1f1e0505f0db98f25fada64d32b7e6240f37f72c"}, + {file = "pip-licenses-4.3.4.tar.gz", hash = "sha256:9c6c9c3252b976d08735bdffb0eb4c5eaa50dfd46f5e075532c0248ffe94fed1"}, + {file = "pip_licenses-4.3.4-py3-none-any.whl", hash = "sha256:85706ec30781076eb611fed3934f27a1f18437d3211f747567cd3c4e943fce1b"}, ] [package.dependencies] @@ -1279,27 +1268,27 @@ tests = ["pytest", "pytest-cov", "pytest-lazy-fixture"] [[package]] name = "psutil" -version = "5.9.6" +version = "5.9.7" description = "Cross-platform lib for process and system monitoring in Python." optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ - {file = "psutil-5.9.6-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:fb8a697f11b0f5994550555fcfe3e69799e5b060c8ecf9e2f75c69302cc35c0d"}, - {file = "psutil-5.9.6-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:91ecd2d9c00db9817a4b4192107cf6954addb5d9d67a969a4f436dbc9200f88c"}, - {file = "psutil-5.9.6-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:10e8c17b4f898d64b121149afb136c53ea8b68c7531155147867b7b1ac9e7e28"}, - {file = "psutil-5.9.6-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:18cd22c5db486f33998f37e2bb054cc62fd06646995285e02a51b1e08da97017"}, - {file = "psutil-5.9.6-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:ca2780f5e038379e520281e4c032dddd086906ddff9ef0d1b9dcf00710e5071c"}, - {file = "psutil-5.9.6-cp27-none-win32.whl", hash = "sha256:70cb3beb98bc3fd5ac9ac617a327af7e7f826373ee64c80efd4eb2856e5051e9"}, - {file = "psutil-5.9.6-cp27-none-win_amd64.whl", hash = "sha256:51dc3d54607c73148f63732c727856f5febec1c7c336f8f41fcbd6315cce76ac"}, - {file = "psutil-5.9.6-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c69596f9fc2f8acd574a12d5f8b7b1ba3765a641ea5d60fb4736bf3c08a8214a"}, - {file = "psutil-5.9.6-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:92e0cc43c524834af53e9d3369245e6cc3b130e78e26100d1f63cdb0abeb3d3c"}, - {file = "psutil-5.9.6-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:748c9dd2583ed86347ed65d0035f45fa8c851e8d90354c122ab72319b5f366f4"}, - {file = "psutil-5.9.6-cp36-cp36m-win32.whl", hash = "sha256:3ebf2158c16cc69db777e3c7decb3c0f43a7af94a60d72e87b2823aebac3d602"}, - {file = "psutil-5.9.6-cp36-cp36m-win_amd64.whl", hash = "sha256:ff18b8d1a784b810df0b0fff3bcb50ab941c3b8e2c8de5726f9c71c601c611aa"}, - {file = "psutil-5.9.6-cp37-abi3-win32.whl", hash = "sha256:a6f01f03bf1843280f4ad16f4bde26b817847b4c1a0db59bf6419807bc5ce05c"}, - {file = "psutil-5.9.6-cp37-abi3-win_amd64.whl", hash = "sha256:6e5fb8dc711a514da83098bc5234264e551ad980cec5f85dabf4d38ed6f15e9a"}, - {file = "psutil-5.9.6-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:daecbcbd29b289aac14ece28eca6a3e60aa361754cf6da3dfb20d4d32b6c7f57"}, - {file = "psutil-5.9.6.tar.gz", hash = "sha256:e4b92ddcd7dd4cdd3f900180ea1e104932c7bce234fb88976e2a3b296441225a"}, + {file = "psutil-5.9.7-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:0bd41bf2d1463dfa535942b2a8f0e958acf6607ac0be52265ab31f7923bcd5e6"}, + {file = "psutil-5.9.7-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:5794944462509e49d4d458f4dbfb92c47539e7d8d15c796f141f474010084056"}, + {file = "psutil-5.9.7-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:fe361f743cb3389b8efda21980d93eb55c1f1e3898269bc9a2a1d0bb7b1f6508"}, + {file = "psutil-5.9.7-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:e469990e28f1ad738f65a42dcfc17adaed9d0f325d55047593cb9033a0ab63df"}, + {file = "psutil-5.9.7-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:3c4747a3e2ead1589e647e64aad601981f01b68f9398ddf94d01e3dc0d1e57c7"}, + {file = "psutil-5.9.7-cp27-none-win32.whl", hash = "sha256:1d4bc4a0148fdd7fd8f38e0498639ae128e64538faa507df25a20f8f7fb2341c"}, + {file = "psutil-5.9.7-cp27-none-win_amd64.whl", hash = "sha256:4c03362e280d06bbbfcd52f29acd79c733e0af33d707c54255d21029b8b32ba6"}, + {file = "psutil-5.9.7-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ea36cc62e69a13ec52b2f625c27527f6e4479bca2b340b7a452af55b34fcbe2e"}, + {file = "psutil-5.9.7-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1132704b876e58d277168cd729d64750633d5ff0183acf5b3c986b8466cd0284"}, + {file = "psutil-5.9.7-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe8b7f07948f1304497ce4f4684881250cd859b16d06a1dc4d7941eeb6233bfe"}, + {file = "psutil-5.9.7-cp36-cp36m-win32.whl", hash = "sha256:b27f8fdb190c8c03914f908a4555159327d7481dac2f01008d483137ef3311a9"}, + {file = "psutil-5.9.7-cp36-cp36m-win_amd64.whl", hash = "sha256:44969859757f4d8f2a9bd5b76eba8c3099a2c8cf3992ff62144061e39ba8568e"}, + {file = "psutil-5.9.7-cp37-abi3-win32.whl", hash = "sha256:c727ca5a9b2dd5193b8644b9f0c883d54f1248310023b5ad3e92036c5e2ada68"}, + {file = "psutil-5.9.7-cp37-abi3-win_amd64.whl", hash = "sha256:f37f87e4d73b79e6c5e749440c3113b81d1ee7d26f21c19c47371ddea834f414"}, + {file = "psutil-5.9.7-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:032f4f2c909818c86cea4fe2cc407f1c0f0cde8e6c6d702b28b8ce0c0d143340"}, + {file = "psutil-5.9.7.tar.gz", hash = "sha256:3f02134e82cfb5d089fddf20bb2e03fd5cd52395321d1c8458a9e58500ff417c"}, ] [package.extras] @@ -1567,13 +1556,13 @@ files = [ [[package]] name = "pytest" -version = "7.4.3" +version = "7.4.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, - {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, + {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, + {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, ] [package.dependencies] @@ -1668,13 +1657,13 @@ cli = ["click (>=5.0)"] [[package]] name = "python-frontmatter" -version = "1.0.1" +version = "1.1.0" description = "Parse and manage posts with YAML (or other) frontmatter" optional = false python-versions = "*" files = [ - {file = "python-frontmatter-1.0.1.tar.gz", hash = "sha256:a6a082844fc601f34e4dd576bed8fcb5ef19112166e087629e4d6ba9bf4f7c35"}, - {file = "python_frontmatter-1.0.1-py3-none-any.whl", hash = "sha256:0599198cc01b445e5d0be74ff35be0a6c7442dddbdb0803e018be4e055397f6a"}, + {file = "python-frontmatter-1.1.0.tar.gz", hash = "sha256:7118d2bd56af9149625745c58c9b51fb67e8d1294a0c76796dafdc72c36e5f6d"}, + {file = "python_frontmatter-1.1.0-py3-none-any.whl", hash = "sha256:335465556358d9d0e6c98bbeb69b1c969f2a4a21360587b9873bfc3b213407c1"}, ] [package.dependencies] @@ -1682,7 +1671,7 @@ PyYAML = "*" [package.extras] docs = ["sphinx"] -test = ["pyaml", "pytest", "toml"] +test = ["mypy", "pyaml", "pytest", "toml", "types-PyYAML", "types-toml"] [[package]] name = "pyyaml" @@ -1709,6 +1698,7 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -1745,101 +1735,101 @@ files = [ [[package]] name = "rapidfuzz" -version = "3.6.0" +version = "3.6.1" description = "rapid fuzzy string matching" optional = false python-versions = ">=3.8" files = [ - {file = "rapidfuzz-3.6.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b21e65818a7e4846bacfa1bd77bc337b02107cc88a7b262dbaeb7944e0c8958d"}, - {file = "rapidfuzz-3.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3bf1f610954ec936d87d58eb0247af61e35c41a92c30f3cfe0478baf764558bf"}, - {file = "rapidfuzz-3.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d7a4b458096be3b39bf5778e26ac96ac10399b8e4fd40a03fd55a155c093acf5"}, - {file = "rapidfuzz-3.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a09cdfd9c1a11a91e207df138aa2e20a9267cf5f7cde6e9a53a4551454b06333"}, - {file = "rapidfuzz-3.6.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:514b15338b7f59b80bbe014d1ffc0093d17abf96f82eb20d8bb573ce24d84a12"}, - {file = "rapidfuzz-3.6.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4ba08ba184e530a770b0fc8897f4ce77ae0863039e139ef3180502b37586fec"}, - {file = "rapidfuzz-3.6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:195cc2a216223ff6118a1eb6cddb077cd264bc828ba7064ebb6e3bc61dd9d864"}, - {file = "rapidfuzz-3.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a743db763cba0aad39e8c8c6a6d1210247cb468f514891632211adad3935a29"}, - {file = "rapidfuzz-3.6.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2a317f1a7c318957bd5ca54bf8258263936320c49857fac69c5ed0b10c81ef0d"}, - {file = "rapidfuzz-3.6.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:96d46e9664c53b07f446ceb0f09973a46766e0fd4a26904e75f067ed78f07db2"}, - {file = "rapidfuzz-3.6.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:12eaf1aed5b0ded8c4b638a892b4fda53bf6f9f2d8597d8507ba6d697a34170a"}, - {file = "rapidfuzz-3.6.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:b9b7baab3245df24447c5dbd6d6ca4ce400e3bb088ffe6c994407c16852157b6"}, - {file = "rapidfuzz-3.6.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7927fff9dd2a34522704c665f9846e0f13e1824f014af8f14294858921bed731"}, - {file = "rapidfuzz-3.6.0-cp310-cp310-win32.whl", hash = "sha256:9557792003addc7e141e63fd60edc8d77bbd983c212f0f1683bf542cb0d396d9"}, - {file = "rapidfuzz-3.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:4c1de6260975d5589374abca04a76c3e968907ccdc6daf5f9dd2b4cca1a7a64d"}, - {file = "rapidfuzz-3.6.0-cp310-cp310-win_arm64.whl", hash = "sha256:ac328c83d49811b36e2699d5132193c5a82139e1a3d0b340babc1bce7428754e"}, - {file = "rapidfuzz-3.6.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8b6205e8d730e0ad3e0472b4fde8f93c740c2165a198ab0ad457e35371b28e08"}, - {file = "rapidfuzz-3.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7c1eccce1125676537322d7bc14ecb917b6464700ea222703e131ccb9d165658"}, - {file = "rapidfuzz-3.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:68dd5912a1b0cc145a674aa45513d595fd6691b263f860d00ac71388ebde09bc"}, - {file = "rapidfuzz-3.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc6604d6f1be13d9fb6b01442805ae2ec3bcccc54247ecabba8d3712aff9685a"}, - {file = "rapidfuzz-3.6.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1ed25d6d7b184725bd26ecfe64dfe6a17d261705435e7c38415499b1316120a9"}, - {file = "rapidfuzz-3.6.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:187751b2b5c4e5b53ea4c30bcbdf6f545dbd985808c0750f990152e95357638f"}, - {file = "rapidfuzz-3.6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2e96db4dfd4bf853898438dbf821c5017229aa8064b4b9a12a4bc7ff3112aa1e"}, - {file = "rapidfuzz-3.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25d98d242e7626c577ab702902040afb87e257ee93c9575884f82e6e7b4aaec0"}, - {file = "rapidfuzz-3.6.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b54cd11ee89b606252c90c5eb711eb6735e2b63305cc8c2e70479166017733a3"}, - {file = "rapidfuzz-3.6.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5d7e82a29af3c8052f78c9b2d98a0586ebd6bf41f27298b92b80293c6506e1d7"}, - {file = "rapidfuzz-3.6.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:a0271e194a5c811db02c7350a119cabde6757587312c70247f6e50984ce36144"}, - {file = "rapidfuzz-3.6.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:2a31a6f6442219bb494a4d5293abb106f95adfdbad3fef597377f7344883afa9"}, - {file = "rapidfuzz-3.6.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:48314743e61394e6418cec38a5389dd3ad6c1b33fc15d525898a303450f958e7"}, - {file = "rapidfuzz-3.6.0-cp311-cp311-win32.whl", hash = "sha256:fcf2ab337b7d331c6cbe7a5296b9f703666e7c1b00771a1dbac6e2d62e46b9a4"}, - {file = "rapidfuzz-3.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:a3aec96905badee77915f6cd791019aa06376b252ca4da3676339c4f8dd64e8f"}, - {file = "rapidfuzz-3.6.0-cp311-cp311-win_arm64.whl", hash = "sha256:4d67f9f180faf341bc04be4f633707b773844a9c07f21dd2eabc27ea54591c8e"}, - {file = "rapidfuzz-3.6.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:583f9cca4e53b5ff93f86a9cf5ca15a6fed3094a2b49acaa3851b4eb00ea04f9"}, - {file = "rapidfuzz-3.6.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:90fb0e1f931031a0fa967d77d8be21220d5b8e626546d3e774dc28c5a0aea10d"}, - {file = "rapidfuzz-3.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:62be08cdd370cc491b594b80493850cf83aafec938b3ca2c98fc4d45667baac8"}, - {file = "rapidfuzz-3.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ea93d044eaf0d0204a088dbaab18ce2cda1bb0738062c8d2834a8b3832f496c"}, - {file = "rapidfuzz-3.6.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a99dc8dc8c2d6da1f5b15c9364bcad262f23da098e7bbd54056bee087423d74d"}, - {file = "rapidfuzz-3.6.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:88813871a373dc600a8ac831b6900ff57c9ed72e61128e065190e30c502b2e7a"}, - {file = "rapidfuzz-3.6.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4c9c495ebe81a2996cb737060181703822215360abdd60a619839397667f8e4e"}, - {file = "rapidfuzz-3.6.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:708457ab87c6eb2aec6f278697b03e088744623c63f450bae2571ce8f29e37d2"}, - {file = "rapidfuzz-3.6.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:2dfba991ea3e9963a1d24946f7932893384a64369bf3c28c6d07eb8ee4c4fc86"}, - {file = "rapidfuzz-3.6.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:346422d616bdc9d90c2d800f963cde370c4bdc3b99ea1d9bd7b16d43f88d4313"}, - {file = "rapidfuzz-3.6.0-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:17b23ef8fae6aa08fe0a02b9e171ef6443ad876bebfdab8d491e07942e36bca6"}, - {file = "rapidfuzz-3.6.0-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:6be8fd7b7a39cb2655a0d216da8fc424bc334cfe43f1dcf00fbc3e0426252a35"}, - {file = "rapidfuzz-3.6.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ac480cdef530a5a9c8e560e5f77783f3dccd65373e0a09dabe32446e212ea3c4"}, - {file = "rapidfuzz-3.6.0-cp312-cp312-win32.whl", hash = "sha256:a6ae64784f0e8a7f989e0d24a401fce68fbe37b9e0d61c24ec983828b1dee768"}, - {file = "rapidfuzz-3.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0938400bb41f738809aae6cd9b4d9985ec2c8cfb34c4931c5a16dba76edf58c"}, - {file = "rapidfuzz-3.6.0-cp312-cp312-win_arm64.whl", hash = "sha256:9a09731ed953126ac3f89f5a8d4998f93eca8a81e41e57b173edc3e44f0afd20"}, - {file = "rapidfuzz-3.6.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:606eb61b04f1f023048dae46e9a002354bde304a192d3b7f6fcc6e75d3910879"}, - {file = "rapidfuzz-3.6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:40e381099e36df52e073abe18aa24e9ace17b7800c2b38d7818b9c77ba22a622"}, - {file = "rapidfuzz-3.6.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8ee4151e1ca81cdc8247847d8e041f2ed9e087d550bc21088506b1599c4c842a"}, - {file = "rapidfuzz-3.6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a829e8486988889d6a316f528d92364a88c11a10fb53a8b981ae9cd52ab5846b"}, - {file = "rapidfuzz-3.6.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4d58f3fd98495d3597137056eb88372ac9360b74a46ab298115230f259e1efa2"}, - {file = "rapidfuzz-3.6.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:76e3d6507ce10696765709093cdedfc814e64960535dcd4f684564c02b6e6d07"}, - {file = "rapidfuzz-3.6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f70743f5626743dfab402697953ce0e9458d52000a2d5f52ae0e110facfd62bd"}, - {file = "rapidfuzz-3.6.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a40e52fcd1b61421de465113624bc802546b106fa02aa28b001b0db493651fd1"}, - {file = "rapidfuzz-3.6.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cb2ddc1afe32fc8d70dc37d825a04ab1df98a91f40ad6b17d976c5b6fbd99130"}, - {file = "rapidfuzz-3.6.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:67a97425abac462e0cb6be02a9adf581577d72e18aa922ef121400e203273657"}, - {file = "rapidfuzz-3.6.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:0c8d8e72030c7ad2b486a6cdcb0af7b51c0041db1e9e0e6c41fa3e3d244df284"}, - {file = "rapidfuzz-3.6.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:5475ea451df17a802c3f78c58f63701c2e99762ce71b9953c2a8da574f450807"}, - {file = "rapidfuzz-3.6.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:19159a69f9d1132cffeb5fcea344f09ec02212654b92a913c9d3deaf3d387f46"}, - {file = "rapidfuzz-3.6.0-cp38-cp38-win32.whl", hash = "sha256:da1f2cff6f0128f1ff7c2745051a87f3cd8946036d4036a9dc464868ad5d3a53"}, - {file = "rapidfuzz-3.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:d920bead489ff2f02893261dd180f2c24afa4f0d00ec24b6b31311966e02f66f"}, - {file = "rapidfuzz-3.6.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:82db5d39f9d87b639a23d700200fea379916114d5352e9574d1a11f82b9d8bca"}, - {file = "rapidfuzz-3.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1f2ecf1e23ee64a7cdce01be1350b977169ac866d27f7301a3add21993163b68"}, - {file = "rapidfuzz-3.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f916630b388d465ab54bb205398abbb38b3f8eeed8f224accee534271ca52fba"}, - {file = "rapidfuzz-3.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52ecaa0619248cc0faa098cc8fa96a65296a9b734f2e8cd509a2cf1358041ae5"}, - {file = "rapidfuzz-3.6.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a5801f45fb585c21b6dbe08658a0d38e08ddca7b1ffb3825f39a59bb78998529"}, - {file = "rapidfuzz-3.6.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a14ebea5e14b3b8c91c02be8adf9397247397f1f2be7e9cb6962ded9cc4d2cba"}, - {file = "rapidfuzz-3.6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b89591f5eb1c3a7509a5294bfd65b3eaca7ee7e0583bdd84122e2fc2e37e6973"}, - {file = "rapidfuzz-3.6.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:029ae17bbe55671884702adc16225ca25ca447f86c1dba95b564fcd51eb82d44"}, - {file = "rapidfuzz-3.6.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:23b278a7d8f2cdc1a54cf9b72a48f76dc9f1b68373f2a3299f8b6cc5e796c160"}, - {file = "rapidfuzz-3.6.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8a5087f5c0b4e8584cd6044c279b4a6df15420a0074bf914e50bdebc9ac4db77"}, - {file = "rapidfuzz-3.6.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:a1d8640e1cad1757378a810c363695822462f331c40b23f30c1bbbc477d77c68"}, - {file = "rapidfuzz-3.6.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:2a3c44bafd6d919ccf3f36d454c3e70cafc4c1aa8557970befbb9ae4930e32d7"}, - {file = "rapidfuzz-3.6.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:863c6ee97d156026bc1685fb7878c440833c221e935474e5b0ffb255b0888356"}, - {file = "rapidfuzz-3.6.0-cp39-cp39-win32.whl", hash = "sha256:834d9bd0fca92fb5cd92a7027df5d0492c3d3c2111f365dc8168f5a2f2582a36"}, - {file = "rapidfuzz-3.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:26c671bd3f2954df7e3d9635d5870177ba7d7433ec610bc3d4ba75648d89b9e9"}, - {file = "rapidfuzz-3.6.0-cp39-cp39-win_arm64.whl", hash = "sha256:f4378ad75d176c067dc9f79898a8b767305cfac97712f769859b118164852893"}, - {file = "rapidfuzz-3.6.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a5a76e488060fde32bfd2dc789821da95ca172a718752d0e65a2b168c7742612"}, - {file = "rapidfuzz-3.6.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:454ecaf9bd547b8a7ff8f461f5b25bd60ec15800ff2fab562e663732f53f0829"}, - {file = "rapidfuzz-3.6.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:392effa32f235b2b30c9f00ece8002e21255fbbffa0ce0d4a1cbcbb88e02d019"}, - {file = "rapidfuzz-3.6.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fad2c70768f83a1f202c191f0e4a3ef3d376659728a4602b22dc62bd7f118973"}, - {file = "rapidfuzz-3.6.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:3fce2489072ae2362abeabdc7745a5b9eb0ff4291c7a69be2318025e1184f016"}, - {file = "rapidfuzz-3.6.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c715df0f21116e830c666d35ea413d528501c50079079ecaa5904ec244661992"}, - {file = "rapidfuzz-3.6.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be2e2b96ea1fcefe0a2ed2560fd33a510dc8afe8e93062e111b40d1cb0e34b6a"}, - {file = "rapidfuzz-3.6.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:adbc4686e7252b97ef344fb9fb05080c8524ac2e77a20e835d166b8330024ac3"}, - {file = "rapidfuzz-3.6.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:306ca0358fc7d2e4660de3fce782bfea9c6bf443d60f9134ea8d4b8e8f1869e3"}, - {file = "rapidfuzz-3.6.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:db23d692ba27f58e5b97c724005e6a478168cb41af5d793bbc5478cb52842306"}, - {file = "rapidfuzz-3.6.0.tar.gz", hash = "sha256:4cdf564c3eeb2d95148bd7199e7869fa927f47cc3aea42f299aa836cfb2b6cfd"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ac434fc71edda30d45db4a92ba5e7a42c7405e1a54cb4ec01d03cc668c6dcd40"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2a791168e119cfddf4b5a40470620c872812042f0621e6a293983a2d52372db0"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5a2f3e9df346145c2be94e4d9eeffb82fab0cbfee85bd4a06810e834fe7c03fa"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23de71e7f05518b0bbeef55d67b5dbce3bcd3e2c81e7e533051a2e9401354eb0"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d056e342989248d2bdd67f1955bb7c3b0ecfa239d8f67a8dfe6477b30872c607"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01835d02acd5d95c1071e1da1bb27fe213c84a013b899aba96380ca9962364bc"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ed0f712e0bb5fea327e92aec8a937afd07ba8de4c529735d82e4c4124c10d5a0"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96cd19934f76a1264e8ecfed9d9f5291fde04ecb667faef5f33bdbfd95fe2d1f"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e06c4242a1354cf9d48ee01f6f4e6e19c511d50bb1e8d7d20bcadbb83a2aea90"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:d73dcfe789d37c6c8b108bf1e203e027714a239e50ad55572ced3c004424ed3b"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:06e98ff000e2619e7cfe552d086815671ed09b6899408c2c1b5103658261f6f3"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:08b6fb47dd889c69fbc0b915d782aaed43e025df6979b6b7f92084ba55edd526"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a1788ebb5f5b655a15777e654ea433d198f593230277e74d51a2a1e29a986283"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-win32.whl", hash = "sha256:c65f92881753aa1098c77818e2b04a95048f30edbe9c3094dc3707d67df4598b"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:4243a9c35667a349788461aae6471efde8d8800175b7db5148a6ab929628047f"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-win_arm64.whl", hash = "sha256:f59d19078cc332dbdf3b7b210852ba1f5db8c0a2cd8cc4c0ed84cc00c76e6802"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fbc07e2e4ac696497c5f66ec35c21ddab3fc7a406640bffed64c26ab2f7ce6d6"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:40cced1a8852652813f30fb5d4b8f9b237112a0bbaeebb0f4cc3611502556764"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:82300e5f8945d601c2daaaac139d5524d7c1fdf719aa799a9439927739917460"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edf97c321fd641fea2793abce0e48fa4f91f3c202092672f8b5b4e781960b891"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7420e801b00dee4a344ae2ee10e837d603461eb180e41d063699fb7efe08faf0"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:060bd7277dc794279fa95522af355034a29c90b42adcb7aa1da358fc839cdb11"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7e3375e4f2bfec77f907680328e4cd16cc64e137c84b1886d547ab340ba6928"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a490cd645ef9d8524090551016f05f052e416c8adb2d8b85d35c9baa9d0428ab"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:2e03038bfa66d2d7cffa05d81c2f18fd6acbb25e7e3c068d52bb7469e07ff382"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:2b19795b26b979c845dba407fe79d66975d520947b74a8ab6cee1d22686f7967"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:064c1d66c40b3a0f488db1f319a6e75616b2e5fe5430a59f93a9a5e40a656d15"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:3c772d04fb0ebeece3109d91f6122b1503023086a9591a0b63d6ee7326bd73d9"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:841eafba6913c4dfd53045835545ba01a41e9644e60920c65b89c8f7e60c00a9"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-win32.whl", hash = "sha256:266dd630f12696ea7119f31d8b8e4959ef45ee2cbedae54417d71ae6f47b9848"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:d79aec8aeee02ab55d0ddb33cea3ecd7b69813a48e423c966a26d7aab025cdfe"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-win_arm64.whl", hash = "sha256:484759b5dbc5559e76fefaa9170147d1254468f555fd9649aea3bad46162a88b"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b2ef4c0fd3256e357b70591ffb9e8ed1d439fb1f481ba03016e751a55261d7c1"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:588c4b20fa2fae79d60a4e438cf7133d6773915df3cc0a7f1351da19eb90f720"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7142ee354e9c06e29a2636b9bbcb592bb00600a88f02aa5e70e4f230347b373e"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1dfc557c0454ad22382373ec1b7df530b4bbd974335efe97a04caec936f2956a"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:03f73b381bdeccb331a12c3c60f1e41943931461cdb52987f2ecf46bfc22f50d"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b0ccc2ec1781c7e5370d96aef0573dd1f97335343e4982bdb3a44c133e27786"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da3e8c9f7e64bb17faefda085ff6862ecb3ad8b79b0f618a6cf4452028aa2222"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fde9b14302a31af7bdafbf5cfbb100201ba21519be2b9dedcf4f1048e4fbe65d"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c1a23eee225dfb21c07f25c9fcf23eb055d0056b48e740fe241cbb4b22284379"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e49b9575d16c56c696bc7b06a06bf0c3d4ef01e89137b3ddd4e2ce709af9fe06"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:0a9fc714b8c290261669f22808913aad49553b686115ad0ee999d1cb3df0cd66"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:a3ee4f8f076aa92184e80308fc1a079ac356b99c39408fa422bbd00145be9854"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f056ba42fd2f32e06b2c2ba2443594873cfccc0c90c8b6327904fc2ddf6d5799"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-win32.whl", hash = "sha256:5d82b9651e3d34b23e4e8e201ecd3477c2baa17b638979deeabbb585bcb8ba74"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:dad55a514868dae4543ca48c4e1fc0fac704ead038dafedf8f1fc0cc263746c1"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-win_arm64.whl", hash = "sha256:3c84294f4470fcabd7830795d754d808133329e0a81d62fcc2e65886164be83b"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e19d519386e9db4a5335a4b29f25b8183a1c3f78cecb4c9c3112e7f86470e37f"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:01eb03cd880a294d1bf1a583fdd00b87169b9cc9c9f52587411506658c864d73"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:be368573255f8fbb0125a78330a1a40c65e9ba3c5ad129a426ff4289099bfb41"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b3e5af946f419c30f5cb98b69d40997fe8580efe78fc83c2f0f25b60d0e56efb"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f382f7ffe384ce34345e1c0b2065451267d3453cadde78946fbd99a59f0cc23c"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be156f51f3a4f369e758505ed4ae64ea88900dcb2f89d5aabb5752676d3f3d7e"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1936d134b6c513fbe934aeb668b0fee1ffd4729a3c9d8d373f3e404fbb0ce8a0"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12ff8eaf4a9399eb2bebd838f16e2d1ded0955230283b07376d68947bbc2d33d"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ae598a172e3a95df3383634589660d6b170cc1336fe7578115c584a99e0ba64d"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cd4ba4c18b149da11e7f1b3584813159f189dc20833709de5f3df8b1342a9759"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:0402f1629e91a4b2e4aee68043a30191e5e1b7cd2aa8dacf50b1a1bcf6b7d3ab"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:1e12319c6b304cd4c32d5db00b7a1e36bdc66179c44c5707f6faa5a889a317c0"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0bbfae35ce4de4c574b386c43c78a0be176eeddfdae148cb2136f4605bebab89"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-win32.whl", hash = "sha256:7fec74c234d3097612ea80f2a80c60720eec34947066d33d34dc07a3092e8105"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:a553cc1a80d97459d587529cc43a4c7c5ecf835f572b671107692fe9eddf3e24"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:757dfd7392ec6346bd004f8826afb3bf01d18a723c97cbe9958c733ab1a51791"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2963f4a3f763870a16ee076796be31a4a0958fbae133dbc43fc55c3968564cf5"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d2f0274595cc5b2b929c80d4e71b35041104b577e118cf789b3fe0a77b37a4c5"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f211e366e026de110a4246801d43a907cd1a10948082f47e8a4e6da76fef52"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a59472b43879012b90989603aa5a6937a869a72723b1bf2ff1a0d1edee2cc8e6"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a03863714fa6936f90caa7b4b50ea59ea32bb498cc91f74dc25485b3f8fccfe9"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5dd95b6b7bfb1584f806db89e1e0c8dbb9d25a30a4683880c195cc7f197eaf0c"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7183157edf0c982c0b8592686535c8b3e107f13904b36d85219c77be5cefd0d8"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ad9d74ef7c619b5b0577e909582a1928d93e07d271af18ba43e428dc3512c2a1"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:b53137d81e770c82189e07a8f32722d9e4260f13a0aec9914029206ead38cac3"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:49b9ed2472394d306d5dc967a7de48b0aab599016aa4477127b20c2ed982dbf9"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:dec307b57ec2d5054d77d03ee4f654afcd2c18aee00c48014cb70bfed79597d6"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4381023fa1ff32fd5076f5d8321249a9aa62128eb3f21d7ee6a55373e672b261"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-win32.whl", hash = "sha256:8d7a072f10ee57c8413c8ab9593086d42aaff6ee65df4aa6663eecdb7c398dca"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:ebcfb5bfd0a733514352cfc94224faad8791e576a80ffe2fd40b2177bf0e7198"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-win_arm64.whl", hash = "sha256:1c47d592e447738744905c18dda47ed155620204714e6df20eb1941bb1ba315e"}, + {file = "rapidfuzz-3.6.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:eef8b346ab331bec12bbc83ac75641249e6167fab3d84d8f5ca37fd8e6c7a08c"}, + {file = "rapidfuzz-3.6.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53251e256017e2b87f7000aee0353ba42392c442ae0bafd0f6b948593d3f68c6"}, + {file = "rapidfuzz-3.6.1-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6dede83a6b903e3ebcd7e8137e7ff46907ce9316e9d7e7f917d7e7cdc570ee05"}, + {file = "rapidfuzz-3.6.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e4da90e4c2b444d0a171d7444ea10152e07e95972bb40b834a13bdd6de1110c"}, + {file = "rapidfuzz-3.6.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:ca3dfcf74f2b6962f411c33dd95b0adf3901266e770da6281bc96bb5a8b20de9"}, + {file = "rapidfuzz-3.6.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bcc957c0a8bde8007f1a8a413a632a1a409890f31f73fe764ef4eac55f59ca87"}, + {file = "rapidfuzz-3.6.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:692c9a50bea7a8537442834f9bc6b7d29d8729a5b6379df17c31b6ab4df948c2"}, + {file = "rapidfuzz-3.6.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c23ceaea27e790ddd35ef88b84cf9d721806ca366199a76fd47cfc0457a81b"}, + {file = "rapidfuzz-3.6.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b155e67fff215c09f130555002e42f7517d0ea72cbd58050abb83cb7c880cec"}, + {file = "rapidfuzz-3.6.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3028ee8ecc48250607fa8a0adce37b56275ec3b1acaccd84aee1f68487c8557b"}, + {file = "rapidfuzz-3.6.1.tar.gz", hash = "sha256:35660bee3ce1204872574fa041c7ad7ec5175b3053a4cb6e181463fc07013de7"}, ] [package.extras] @@ -2003,39 +1993,39 @@ six = "*" [[package]] name = "ruff" -version = "0.1.7" +version = "0.1.11" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.1.7-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7f80496854fdc65b6659c271d2c26e90d4d401e6a4a31908e7e334fab4645aac"}, - {file = "ruff-0.1.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:1ea109bdb23c2a4413f397ebd8ac32cb498bee234d4191ae1a310af760e5d287"}, - {file = "ruff-0.1.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b0c2de9dd9daf5e07624c24add25c3a490dbf74b0e9bca4145c632457b3b42a"}, - {file = "ruff-0.1.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:69a4bed13bc1d5dabf3902522b5a2aadfebe28226c6269694283c3b0cecb45fd"}, - {file = "ruff-0.1.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de02ca331f2143195a712983a57137c5ec0f10acc4aa81f7c1f86519e52b92a1"}, - {file = "ruff-0.1.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:45b38c3f8788a65e6a2cab02e0f7adfa88872696839d9882c13b7e2f35d64c5f"}, - {file = "ruff-0.1.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6c64cb67b2025b1ac6d58e5ffca8f7b3f7fd921f35e78198411237e4f0db8e73"}, - {file = "ruff-0.1.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9dcc6bb2f4df59cb5b4b40ff14be7d57012179d69c6565c1da0d1f013d29951b"}, - {file = "ruff-0.1.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df2bb4bb6bbe921f6b4f5b6fdd8d8468c940731cb9406f274ae8c5ed7a78c478"}, - {file = "ruff-0.1.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:276a89bcb149b3d8c1b11d91aa81898fe698900ed553a08129b38d9d6570e717"}, - {file = "ruff-0.1.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:90c958fe950735041f1c80d21b42184f1072cc3975d05e736e8d66fc377119ea"}, - {file = "ruff-0.1.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6b05e3b123f93bb4146a761b7a7d57af8cb7384ccb2502d29d736eaade0db519"}, - {file = "ruff-0.1.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:290ecab680dce94affebefe0bbca2322a6277e83d4f29234627e0f8f6b4fa9ce"}, - {file = "ruff-0.1.7-py3-none-win32.whl", hash = "sha256:416dfd0bd45d1a2baa3b1b07b1b9758e7d993c256d3e51dc6e03a5e7901c7d80"}, - {file = "ruff-0.1.7-py3-none-win_amd64.whl", hash = "sha256:4af95fd1d3b001fc41325064336db36e3d27d2004cdb6d21fd617d45a172dd96"}, - {file = "ruff-0.1.7-py3-none-win_arm64.whl", hash = "sha256:0683b7bfbb95e6df3c7c04fe9d78f631f8e8ba4868dfc932d43d690698057e2e"}, - {file = "ruff-0.1.7.tar.gz", hash = "sha256:dffd699d07abf54833e5f6cc50b85a6ff043715da8788c4a79bcd4ab4734d306"}, + {file = "ruff-0.1.11-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:a7f772696b4cdc0a3b2e527fc3c7ccc41cdcb98f5c80fdd4f2b8c50eb1458196"}, + {file = "ruff-0.1.11-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:934832f6ed9b34a7d5feea58972635c2039c7a3b434fe5ba2ce015064cb6e955"}, + {file = "ruff-0.1.11-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea0d3e950e394c4b332bcdd112aa566010a9f9c95814844a7468325290aabfd9"}, + {file = "ruff-0.1.11-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9bd4025b9c5b429a48280785a2b71d479798a69f5c2919e7d274c5f4b32c3607"}, + {file = "ruff-0.1.11-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1ad00662305dcb1e987f5ec214d31f7d6a062cae3e74c1cbccef15afd96611d"}, + {file = "ruff-0.1.11-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:4b077ce83f47dd6bea1991af08b140e8b8339f0ba8cb9b7a484c30ebab18a23f"}, + {file = "ruff-0.1.11-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4a88efecec23c37b11076fe676e15c6cdb1271a38f2b415e381e87fe4517f18"}, + {file = "ruff-0.1.11-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5b25093dad3b055667730a9b491129c42d45e11cdb7043b702e97125bcec48a1"}, + {file = "ruff-0.1.11-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:231d8fb11b2cc7c0366a326a66dafc6ad449d7fcdbc268497ee47e1334f66f77"}, + {file = "ruff-0.1.11-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:09c415716884950080921dd6237767e52e227e397e2008e2bed410117679975b"}, + {file = "ruff-0.1.11-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0f58948c6d212a6b8d41cd59e349751018797ce1727f961c2fa755ad6208ba45"}, + {file = "ruff-0.1.11-py3-none-musllinux_1_2_i686.whl", hash = "sha256:190a566c8f766c37074d99640cd9ca3da11d8deae2deae7c9505e68a4a30f740"}, + {file = "ruff-0.1.11-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:6464289bd67b2344d2a5d9158d5eb81025258f169e69a46b741b396ffb0cda95"}, + {file = "ruff-0.1.11-py3-none-win32.whl", hash = "sha256:9b8f397902f92bc2e70fb6bebfa2139008dc72ae5177e66c383fa5426cb0bf2c"}, + {file = "ruff-0.1.11-py3-none-win_amd64.whl", hash = "sha256:eb85ee287b11f901037a6683b2374bb0ec82928c5cbc984f575d0437979c521a"}, + {file = "ruff-0.1.11-py3-none-win_arm64.whl", hash = "sha256:97ce4d752f964ba559c7023a86e5f8e97f026d511e48013987623915431c7ea9"}, + {file = "ruff-0.1.11.tar.gz", hash = "sha256:f9d4d88cb6eeb4dfe20f9f0519bd2eaba8119bde87c3d5065c541dbae2b5a2cb"}, ] [[package]] name = "sentry-sdk" -version = "1.39.1" +version = "1.39.2" description = "Python client for Sentry (https://sentry.io)" optional = false python-versions = "*" files = [ - {file = "sentry-sdk-1.39.1.tar.gz", hash = "sha256:320a55cdf9da9097a0bead239c35b7e61f53660ef9878861824fd6d9b2eaf3b5"}, - {file = "sentry_sdk-1.39.1-py2.py3-none-any.whl", hash = "sha256:81b5b9ffdd1a374e9eb0c053b5d2012155db9cbe76393a8585677b753bd5fdc1"}, + {file = "sentry-sdk-1.39.2.tar.gz", hash = "sha256:24c83b0b41c887d33328a9166f5950dc37ad58f01c9f2fbff6b87a6f1094170c"}, + {file = "sentry_sdk-1.39.2-py2.py3-none-any.whl", hash = "sha256:acaf597b30258fc7663063b291aa99e58f3096e91fe1e6634f4b79f9c1943e8e"}, ] [package.dependencies] @@ -2061,7 +2051,7 @@ huey = ["huey (>=2)"] loguru = ["loguru (>=0.5)"] opentelemetry = ["opentelemetry-distro (>=0.35b0)"] opentelemetry-experimental = ["opentelemetry-distro (>=0.40b0,<1.0)", "opentelemetry-instrumentation-aiohttp-client (>=0.40b0,<1.0)", "opentelemetry-instrumentation-django (>=0.40b0,<1.0)", "opentelemetry-instrumentation-fastapi (>=0.40b0,<1.0)", "opentelemetry-instrumentation-flask (>=0.40b0,<1.0)", "opentelemetry-instrumentation-requests (>=0.40b0,<1.0)", "opentelemetry-instrumentation-sqlite3 (>=0.40b0,<1.0)", "opentelemetry-instrumentation-urllib (>=0.40b0,<1.0)"] -pure-eval = ["asttokens", "executing", "pure-eval"] +pure-eval = ["asttokens", "executing", "pure_eval"] pymongo = ["pymongo (>=3.1)"] pyspark = ["pyspark (>=2.4.4)"] quart = ["blinker (>=1.1)", "quart (>=0.16.1)"] @@ -2074,13 +2064,13 @@ tornado = ["tornado (>=5)"] [[package]] name = "setuptools" -version = "69.0.2" +version = "69.0.3" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-69.0.2-py3-none-any.whl", hash = "sha256:1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2"}, - {file = "setuptools-69.0.2.tar.gz", hash = "sha256:735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6"}, + {file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05"}, + {file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78"}, ] [package.extras] @@ -2376,4 +2366,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "3.11.*" -content-hash = "cdab9b3369450a83d07322f36b93d3626e2ad9fc2ab55f30f1defc4809fc7279" +content-hash = "3bfbd01b5217abd3711777158d2f3b8bf439ab7deda354f900a773b5fcab4069" diff --git a/pyproject.toml b/pyproject.toml index 641128f04..286fa556b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,20 +13,20 @@ pydis_core = { version = "10.5.1", extras = ["async-rediscache"] } aiohttp = "3.9.1" arrow = "1.3.0" -beautifulsoup4 = "4.12.2" +beautifulsoup4 = "4.12.3" colorama = { version = "0.4.6", markers = "sys_platform == 'win32'" } coloredlogs = "15.0.1" deepdiff = "6.7.1" -emoji = "2.9.0" +emoji = "2.10.0" feedparser = "6.0.11" -lxml = "4.9.4" +lxml = "5.1.0" markdownify = "0.11.6" -more-itertools = "10.1.0" +more-itertools = "10.2.0" python-dateutil = "2.8.2" -python-frontmatter = "1.0.1" -rapidfuzz = "3.6.0" +python-frontmatter = "1.1.0" +rapidfuzz = "3.6.1" regex = "2023.12.25" -sentry-sdk = "1.39.1" +sentry-sdk = "1.39.2" tldextract = "5.1.1" pydantic = "2.5.2" pydantic-settings = "2.1.0" @@ -35,12 +35,12 @@ pydantic-settings = "2.1.0" coverage = "7.4.0" httpx = "0.26.0" pre-commit = "3.6.0" -pip-licenses = "4.3.3" -pytest = "7.4.3" +pip-licenses = "4.3.4" +pytest = "7.4.4" pytest-cov = "4.1.0" pytest-subtests = "0.11.0" pytest-xdist = "3.5.0" -ruff = "0.1.7" +ruff = "0.1.11" taskipy = "1.12.2" diff --git a/tests/bot/exts/moderation/test_modlog.py b/tests/bot/exts/moderation/test_modlog.py index 79e04837d..f2b02bd1b 100644 --- a/tests/bot/exts/moderation/test_modlog.py +++ b/tests/bot/exts/moderation/test_modlog.py @@ -3,6 +3,7 @@ import unittest import discord from bot.exts.moderation.modlog import ModLog +from bot.utils.modlog import send_log_message from tests.helpers import MockBot, MockTextChannel @@ -17,7 +18,8 @@ class ModLogTests(unittest.IsolatedAsyncioTestCase): async def test_log_entry_description_truncation(self): """Test that embed description for ModLog entry is truncated.""" self.bot.get_channel.return_value = self.channel - await self.cog.send_log_message( + await send_log_message( + self.bot, icon_url="foo", colour=discord.Colour.blue(), title="bar", |